Merged of mcp750 and mvme2307 BSP by Eric Valette <valette@crf.canon.fr>.

As part of this effort, the mpc750 libcpu code is now shared with the
ppc6xx.
This commit is contained in:
Joel Sherrill
1999-12-02 14:31:19 +00:00
parent 4cf56006c7
commit acc25eec35
163 changed files with 42536 additions and 648 deletions

View File

@@ -20,10 +20,10 @@ INSTALL_CHANGE = @INSTALL_CHANGE@
SHARED_LIB = shared SHARED_LIB = shared
ifeq ($(RTEMS_CPU_MODEL),mpc750) ifeq ($(RTEMS_PPC_EXCEPTION_PROCESSING_MODEL),new)
CPUDIR = mpc750 CPUDIR = new_exception_processing
else else
CPUDIR = other_cpu CPUDIR = old_exception_processing
endif endif
SUBDIRS = $(CPUDIR) $(SHARED_LIB) SUBDIRS = $(CPUDIR) $(SHARED_LIB)

View File

@@ -0,0 +1,90 @@
#
# $Id$
#
@SET_MAKE@
srcdir = @srcdir@
top_srcdir = @top_srcdir@
top_builddir = ../..
subdir = powerpc/new_exception_processing
RTEMS_ROOT = @RTEMS_ROOT@
PROJECT_ROOT = @PROJECT_ROOT@
VPATH = @srcdir@
RELS = ../$(ARCH)/rtems-cpu.rel
# C source names, if any, go here -- minus the .c
C_PIECES = cpu
C_FILES = $(C_PIECES:%=%.c)
C_O_FILES = $(C_PIECES:%=${ARCH}/%.o)
ROOT_H_PIECES =
ROOT_H_FILES = $(ROOT_H_PIECES:%=$(srcdir)/%)
RTEMS_SCORE_H_PIECES = cpu.h
RTEMS_SCORE_H_FILES = $(RTEMS_SCORE_H_PIECES:%=$(srcdir)/%)
H_PIECES = $(ROOT_H_PIECES) $(RTEMS_SCORE_H_PIECES)
H_FILES = $(H_PIECES%=$(srcdir)/%)
I_PIECES = c_isr
I_FILES = $(I_PIECES:%=$(srcdir)/%.inl)
# Assembly source names, if any, go here -- minus the .S
S_PIECES = cpu_asm
S_FILES = $(S_PIECES:%=%.S)
S_O_FILES = $(S_FILES:%.S=${ARCH}/%.o)
SRCS = $(C_FILES) $(CC_FILES) $(H_FILES) $(S_FILES) $(EXTERNAL_H_FILES) \
$(I_FILES)
OBJS = $(C_O_FILES) $(CC_O_FILES) $(S_O_FILES)
include $(RTEMS_ROOT)/make/custom/@RTEMS_BSP@.cfg
include $(RTEMS_ROOT)/make/leaf.cfg
INSTALL_CHANGE = @INSTALL_CHANGE@
mkinstalldirs = $(SHELL) $(top_srcdir)/@RTEMS_TOPdir@/mkinstalldirs
INSTALLDIRS = $(PROJECT_INCLUDE)/rtems/score $(PROJECT_INCLUDE)
$(INSTALLDIRS):
@$(mkinstalldirs) $(INSTALLDIRS)
#
# (OPTIONAL) Add local stuff here using +=
#
DEFINES +=
CPPFLAGS +=
CFLAGS += $(CFLAGS_OS_V)
LD_PATHS +=
LD_LIBS +=
LDFLAGS +=
#
# Add your list of files to delete here. The config files
# already know how to delete some stuff, so you may want
# to just run 'make clean' first to see what gets missed.
# 'make clobber' already includes 'make clean'
#
CLEAN_ADDITIONS +=
CLOBBER_ADDITIONS +=
../$(ARCH)/rtems-cpu.rel: $(OBJS)
test -d ../$(ARCH) || mkdir ../$(ARCH)
$(make-rel)
all: ${ARCH} $(SRCS) preinstall $(OBJS) $(RELS)
# Install the program(s), appending _g or _p as appropriate.
# for include files, just use $(INSTALL_CHANGE)
install: all
preinstall: ${ARCH}
@$(INSTALL_CHANGE) -m 644 $(RTEMS_SCORE_H_FILES) $(I_FILES) $(PROJECT_INCLUDE)/rtems/score
@$(INSTALL_CHANGE) -m 644 $(ROOT_H_FILES) $(PROJECT_INCLUDE)
Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
cd $(top_builddir) \
&& CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status

View File

@@ -0,0 +1,9 @@
RTEMS_INLINE_ROUTINE boolean _ISR_Is_in_progress( void )
{
register unsigned int isr_nesting_level;
/*
* Move from special purpose register 0 (mfspr SPRG0, r3)
*/
asm volatile ("mfspr %0, 272" : "=r" (isr_nesting_level));
return isr_nesting_level;
}

View File

@@ -0,0 +1,116 @@
/*
* PowerPC CPU Dependent Source
*
* Author: Andrew Bray <andy@i-cubed.co.uk>
*
* COPYRIGHT (c) 1995 by i-cubed ltd.
*
* To anyone who acknowledges that this file is provided "AS IS"
* without any express or implied warranty:
* permission to use, copy, modify, and distribute this file
* for any purpose is hereby granted without fee, provided that
* the above copyright notice and this notice appears in all
* copies, and that the name of i-cubed limited not be used in
* advertising or publicity pertaining to distribution of the
* software without specific, written prior permission.
* i-cubed limited makes no representations about the suitability
* of this software for any purpose.
*
* Derived from c/src/exec/cpu/no_cpu/cpu.c:
*
* COPYRIGHT (c) 1989-1997.
* On-Line Applications Research Corporation (OAR).
* Copyright assigned to U.S. Government, 1994.
*
* The license and distribution terms for this file may be found in
* the file LICENSE in this distribution or at
* http://www.OARcorp.com/rtems/license.html.
*
* $Id$
*/
#include <rtems/system.h>
#include <rtems/score/isr.h>
#include <rtems/score/context.h>
#include <rtems/score/thread.h>
#include <rtems/score/interr.h>
/* _CPU_Initialize
*
* This routine performs processor dependent initialization.
*
* INPUT PARAMETERS:
* cpu_table - CPU table to initialize
* thread_dispatch - address of disptaching routine
*/
void _CPU_Initialize(
rtems_cpu_table *cpu_table,
void (*thread_dispatch) /* ignored on this CPU */
)
{
_CPU_Table = *cpu_table;
}
/*PAGE
*
* _CPU_Context_Initialize
*/
void _CPU_Context_Initialize(
Context_Control *the_context,
unsigned32 *stack_base,
unsigned32 size,
unsigned32 new_level,
void *entry_point,
boolean is_fp
)
{
unsigned32 msr_value;
unsigned32 sp;
sp = (unsigned32)stack_base + size - CPU_MINIMUM_STACK_FRAME_SIZE;
*((unsigned32 *)sp) = 0;
the_context->gpr1 = sp;
_CPU_MSR_GET( msr_value );
if (!(new_level & CPU_MODES_INTERRUPT_MASK)) {
msr_value |= MSR_EE;
}
else {
msr_value &= ~MSR_EE;
}
the_context->msr = msr_value;
/*
* The FP bit of the MSR should only be enabled if this is a floating
* point task. Unfortunately, the vfprintf_r routine in newlib
* ends up pushing a floating point register regardless of whether or
* not a floating point number is being printed. Serious restructuring
* of vfprintf.c will be required to avoid this behavior. At this
* time (7 July 1997), this restructuring is not being done.
*/
/*if ( is_fp ) */
the_context->msr |= PPC_MSR_FP;
the_context->pc = (unsigned32)entry_point;
}
/*PAGE
*
* _CPU_Install_interrupt_stack
*/
void _CPU_Install_interrupt_stack( void )
{
}

View File

@@ -0,0 +1,979 @@
/* cpu.h
*
* This include file contains information pertaining to the PowerPC
* processor.
*
* Author: Andrew Bray <andy@i-cubed.co.uk>
*
* COPYRIGHT (c) 1995 by i-cubed ltd.
*
* To anyone who acknowledges that this file is provided "AS IS"
* without any express or implied warranty:
* permission to use, copy, modify, and distribute this file
* for any purpose is hereby granted without fee, provided that
* the above copyright notice and this notice appears in all
* copies, and that the name of i-cubed limited not be used in
* advertising or publicity pertaining to distribution of the
* software without specific, written prior permission.
* i-cubed limited makes no representations about the suitability
* of this software for any purpose.
*
* Derived from c/src/exec/cpu/no_cpu/cpu.h:
*
* COPYRIGHT (c) 1989-1997.
* On-Line Applications Research Corporation (OAR).
* Copyright assigned to U.S. Government, 1994.
*
* The license and distribution terms for this file may be found in
* the file LICENSE in this distribution or at
* http://www.OARcorp.com/rtems/license.html.
*
* $Id$
*/
#ifndef __CPU_h
#define __CPU_h
#ifdef __cplusplus
extern "C" {
#endif
#include <rtems/score/ppc.h> /* pick up machine definitions */
#include <libcpu/cpu.h>
#ifndef ASM
#include <rtems/score/ppctypes.h>
#endif
/* conditional compilation parameters */
/*
* Should the calls to _Thread_Enable_dispatch be inlined?
*
* If TRUE, then they are inlined.
* If FALSE, then a subroutine call is made.
*
* Basically this is an example of the classic trade-off of size
* versus speed. Inlining the call (TRUE) typically increases the
* size of RTEMS while speeding up the enabling of dispatching.
* [NOTE: In general, the _Thread_Dispatch_disable_level will
* only be 0 or 1 unless you are in an interrupt handler and that
* interrupt handler invokes the executive.] When not inlined
* something calls _Thread_Enable_dispatch which in turns calls
* _Thread_Dispatch. If the enable dispatch is inlined, then
* one subroutine call is avoided entirely.]
*/
#define CPU_INLINE_ENABLE_DISPATCH FALSE
/*
* Should the body of the search loops in _Thread_queue_Enqueue_priority
* be unrolled one time? In unrolled each iteration of the loop examines
* two "nodes" on the chain being searched. Otherwise, only one node
* is examined per iteration.
*
* If TRUE, then the loops are unrolled.
* If FALSE, then the loops are not unrolled.
*
* The primary factor in making this decision is the cost of disabling
* and enabling interrupts (_ISR_Flash) versus the cost of rest of the
* body of the loop. On some CPUs, the flash is more expensive than
* one iteration of the loop body. In this case, it might be desirable
* to unroll the loop. It is important to note that on some CPUs, this
* code is the longest interrupt disable period in RTEMS. So it is
* necessary to strike a balance when setting this parameter.
*/
#define CPU_UNROLL_ENQUEUE_PRIORITY FALSE
/*
* Does RTEMS manage a dedicated interrupt stack in software?
*
* If TRUE, then a stack is allocated in _Interrupt_Manager_initialization.
* If FALSE, nothing is done.
*
* If the CPU supports a dedicated interrupt stack in hardware,
* then it is generally the responsibility of the BSP to allocate it
* and set it up.
*
* If the CPU does not support a dedicated interrupt stack, then
* the porter has two options: (1) execute interrupts on the
* stack of the interrupted task, and (2) have RTEMS manage a dedicated
* interrupt stack.
*
* If this is TRUE, CPU_ALLOCATE_INTERRUPT_STACK should also be TRUE.
*
* Only one of CPU_HAS_SOFTWARE_INTERRUPT_STACK and
* CPU_HAS_HARDWARE_INTERRUPT_STACK should be set to TRUE. It is
* possible that both are FALSE for a particular CPU. Although it
* is unclear what that would imply about the interrupt processing
* procedure on that CPU.
*/
#define CPU_HAS_SOFTWARE_INTERRUPT_STACK TRUE
/*
* Does this CPU have hardware support for a dedicated interrupt stack?
*
* If TRUE, then it must be installed during initialization.
* If FALSE, then no installation is performed.
*
* If this is TRUE, CPU_ALLOCATE_INTERRUPT_STACK should also be TRUE.
*
* Only one of CPU_HAS_SOFTWARE_INTERRUPT_STACK and
* CPU_HAS_HARDWARE_INTERRUPT_STACK should be set to TRUE. It is
* possible that both are FALSE for a particular CPU. Although it
* is unclear what that would imply about the interrupt processing
* procedure on that CPU.
*/
#define CPU_HAS_HARDWARE_INTERRUPT_STACK FALSE
/*
* Does RTEMS allocate a dedicated interrupt stack in the Interrupt Manager?
*
* If TRUE, then the memory is allocated during initialization.
* If FALSE, then the memory is allocated during initialization.
*
* This should be TRUE is CPU_HAS_SOFTWARE_INTERRUPT_STACK is TRUE
* or CPU_INSTALL_HARDWARE_INTERRUPT_STACK is TRUE.
*/
#define CPU_ALLOCATE_INTERRUPT_STACK FALSE
/*
* Does the RTEMS invoke the user's ISR with the vector number and
* a pointer to the saved interrupt frame (1) or just the vector
* number (0)?
*/
#define CPU_ISR_PASSES_FRAME_POINTER 0
/*
* Does the CPU have hardware floating point?
*
* If TRUE, then the RTEMS_FLOATING_POINT task attribute is supported.
* If FALSE, then the RTEMS_FLOATING_POINT task attribute is ignored.
*
* If there is a FP coprocessor such as the i387 or mc68881, then
* the answer is TRUE.
*
* The macro name "PPC_HAS_FPU" should be made CPU specific.
* It indicates whether or not this CPU model has FP support. For
* example, it would be possible to have an i386_nofp CPU model
* which set this to false to indicate that you have an i386 without
* an i387 and wish to leave floating point support out of RTEMS.
*/
#if ( PPC_HAS_FPU == 1 )
#define CPU_HARDWARE_FP TRUE
#else
#define CPU_HARDWARE_FP FALSE
#endif
/*
* Are all tasks RTEMS_FLOATING_POINT tasks implicitly?
*
* If TRUE, then the RTEMS_FLOATING_POINT task attribute is assumed.
* If FALSE, then the RTEMS_FLOATING_POINT task attribute is followed.
*
* So far, the only CPU in which this option has been used is the
* HP PA-RISC. The HP C compiler and gcc both implicitly use the
* floating point registers to perform integer multiplies. If
* a function which you would not think utilize the FP unit DOES,
* then one can not easily predict which tasks will use the FP hardware.
* In this case, this option should be TRUE.
*
* If CPU_HARDWARE_FP is FALSE, then this should be FALSE as well.
*/
#define CPU_ALL_TASKS_ARE_FP FALSE
/*
* Should the IDLE task have a floating point context?
*
* If TRUE, then the IDLE task is created as a RTEMS_FLOATING_POINT task
* and it has a floating point context which is switched in and out.
* If FALSE, then the IDLE task does not have a floating point context.
*
* Setting this to TRUE negatively impacts the time required to preempt
* the IDLE task from an interrupt because the floating point context
* must be saved as part of the preemption.
*/
#define CPU_IDLE_TASK_IS_FP FALSE
/*
* Should the saving of the floating point registers be deferred
* until a context switch is made to another different floating point
* task?
*
* If TRUE, then the floating point context will not be stored until
* necessary. It will remain in the floating point registers and not
* disturned until another floating point task is switched to.
*
* If FALSE, then the floating point context is saved when a floating
* point task is switched out and restored when the next floating point
* task is restored. The state of the floating point registers between
* those two operations is not specified.
*
* If the floating point context does NOT have to be saved as part of
* interrupt dispatching, then it should be safe to set this to TRUE.
*
* Setting this flag to TRUE results in using a different algorithm
* for deciding when to save and restore the floating point context.
* The deferred FP switch algorithm minimizes the number of times
* the FP context is saved and restored. The FP context is not saved
* until a context switch is made to another, different FP task.
* Thus in a system with only one FP task, the FP context will never
* be saved or restored.
*/
/*
* ACB Note: This could make debugging tricky..
*/
#define CPU_USE_DEFERRED_FP_SWITCH TRUE
/*
* Does this port provide a CPU dependent IDLE task implementation?
*
* If TRUE, then the routine _CPU_Thread_Idle_body
* must be provided and is the default IDLE thread body instead of
* _CPU_Thread_Idle_body.
*
* If FALSE, then use the generic IDLE thread body if the BSP does
* not provide one.
*
* This is intended to allow for supporting processors which have
* a low power or idle mode. When the IDLE thread is executed, then
* the CPU can be powered down.
*
* The order of precedence for selecting the IDLE thread body is:
*
* 1. BSP provided
* 2. CPU dependent (if provided)
* 3. generic (if no BSP and no CPU dependent)
*/
#define CPU_PROVIDES_IDLE_THREAD_BODY FALSE
/*
* Does the stack grow up (toward higher addresses) or down
* (toward lower addresses)?
*
* If TRUE, then the grows upward.
* If FALSE, then the grows toward smaller addresses.
*/
#define CPU_STACK_GROWS_UP FALSE
/*
* The following is the variable attribute used to force alignment
* of critical RTEMS structures. On some processors it may make
* sense to have these aligned on tighter boundaries than
* the minimum requirements of the compiler in order to have as
* much of the critical data area as possible in a cache line.
*
* The placement of this macro in the declaration of the variables
* is based on the syntactically requirements of the GNU C
* "__attribute__" extension. For example with GNU C, use
* the following to force a structures to a 32 byte boundary.
*
* __attribute__ ((aligned (32)))
*
* NOTE: Currently only the Priority Bit Map table uses this feature.
* To benefit from using this, the data must be heavily
* used so it will stay in the cache and used frequently enough
* in the executive to justify turning this on.
*/
#define CPU_STRUCTURE_ALIGNMENT \
__attribute__ ((aligned (PPC_CACHE_ALIGNMENT)))
/*
* Define what is required to specify how the network to host conversion
* routines are handled.
*/
#define CPU_HAS_OWN_HOST_TO_NETWORK_ROUTINES FALSE
#define CPU_BIG_ENDIAN TRUE
#define CPU_LITTLE_ENDIAN FALSE
/*
* Processor defined structures
*
* Examples structures include the descriptor tables from the i386
* and the processor control structure on the i960ca.
*/
/* may need to put some structures here. */
/*
* Contexts
*
* Generally there are 2 types of context to save.
* 1. Interrupt registers to save
* 2. Task level registers to save
*
* This means we have the following 3 context items:
* 1. task level context stuff:: Context_Control
* 2. floating point task stuff:: Context_Control_fp
* 3. special interrupt level context :: Context_Control_interrupt
*
* On some processors, it is cost-effective to save only the callee
* preserved registers during a task context switch. This means
* that the ISR code needs to save those registers which do not
* persist across function calls. It is not mandatory to make this
* distinctions between the caller/callee saves registers for the
* purpose of minimizing context saved during task switch and on interrupts.
* If the cost of saving extra registers is minimal, simplicity is the
* choice. Save the same context on interrupt entry as for tasks in
* this case.
*
* Additionally, if gdb is to be made aware of RTEMS tasks for this CPU, then
* care should be used in designing the context area.
*
* On some CPUs with hardware floating point support, the Context_Control_fp
* structure will not be used or it simply consist of an array of a
* fixed number of bytes. This is done when the floating point context
* is dumped by a "FP save context" type instruction and the format
* is not really defined by the CPU. In this case, there is no need
* to figure out the exact format -- only the size. Of course, although
* this is enough information for RTEMS, it is probably not enough for
* a debugger such as gdb. But that is another problem.
*/
#ifndef ASM
typedef struct {
unsigned32 gpr1; /* Stack pointer for all */
unsigned32 gpr2; /* TOC in PowerOpen, reserved SVR4, section ptr EABI + */
unsigned32 gpr13; /* First non volatile PowerOpen, section ptr SVR4/EABI */
unsigned32 gpr14; /* Non volatile for all */
unsigned32 gpr15; /* Non volatile for all */
unsigned32 gpr16; /* Non volatile for all */
unsigned32 gpr17; /* Non volatile for all */
unsigned32 gpr18; /* Non volatile for all */
unsigned32 gpr19; /* Non volatile for all */
unsigned32 gpr20; /* Non volatile for all */
unsigned32 gpr21; /* Non volatile for all */
unsigned32 gpr22; /* Non volatile for all */
unsigned32 gpr23; /* Non volatile for all */
unsigned32 gpr24; /* Non volatile for all */
unsigned32 gpr25; /* Non volatile for all */
unsigned32 gpr26; /* Non volatile for all */
unsigned32 gpr27; /* Non volatile for all */
unsigned32 gpr28; /* Non volatile for all */
unsigned32 gpr29; /* Non volatile for all */
unsigned32 gpr30; /* Non volatile for all */
unsigned32 gpr31; /* Non volatile for all */
unsigned32 cr; /* PART of the CR is non volatile for all */
unsigned32 pc; /* Program counter/Link register */
unsigned32 msr; /* Initial interrupt level */
} Context_Control;
typedef struct {
/* The ABIs (PowerOpen/SVR4/EABI) only require saving f14-f31 over
* procedure calls. However, this would mean that the interrupt
* frame had to hold f0-f13, and the fpscr. And as the majority
* of tasks will not have an FP context, we will save the whole
* context here.
*/
#if (PPC_HAS_DOUBLE == 1)
double f[32];
double fpscr;
#else
float f[32];
float fpscr;
#endif
} Context_Control_fp;
typedef struct CPU_Interrupt_frame {
unsigned32 stacklink; /* Ensure this is a real frame (also reg1 save) */
unsigned32 calleeLr; /* link register used by callees: SVR4/EABI */
/* This is what is left out of the primary contexts */
unsigned32 gpr0;
unsigned32 gpr2; /* play safe */
unsigned32 gpr3;
unsigned32 gpr4;
unsigned32 gpr5;
unsigned32 gpr6;
unsigned32 gpr7;
unsigned32 gpr8;
unsigned32 gpr9;
unsigned32 gpr10;
unsigned32 gpr11;
unsigned32 gpr12;
unsigned32 gpr13; /* Play safe */
unsigned32 gpr28; /* For internal use by the IRQ handler */
unsigned32 gpr29; /* For internal use by the IRQ handler */
unsigned32 gpr30; /* For internal use by the IRQ handler */
unsigned32 gpr31; /* For internal use by the IRQ handler */
unsigned32 cr; /* Bits of this are volatile, so no-one may save */
unsigned32 ctr;
unsigned32 xer;
unsigned32 lr;
unsigned32 pc;
unsigned32 msr;
unsigned32 pad[3];
} CPU_Interrupt_frame;
/*
* The following table contains the information required to configure
* the PowerPC processor specific parameters.
*/
typedef struct {
void (*pretasking_hook)( void );
void (*predriver_hook)( void );
void (*postdriver_hook)( void );
void (*idle_task)( void );
boolean do_zero_of_workspace;
unsigned32 idle_task_stack_size;
unsigned32 interrupt_stack_size;
unsigned32 extra_mpci_receive_server_stack;
void * (*stack_allocate_hook)( unsigned32 );
void (*stack_free_hook)( void* );
/* end of fields required on all CPUs */
unsigned32 clicks_per_usec; /* Timer clicks per microsecond */
boolean exceptions_in_RAM; /* TRUE if in RAM */
} rtems_cpu_table;
/*
* Macros to access required entires in the CPU Table are in
* the file rtems/system.h.
*/
/*
* Macros to access PowerPC MPC750 specific additions to the CPU Table
*/
#define rtems_cpu_configuration_get_clicks_per_usec() \
(_CPU_Table.clicks_per_usec)
#define rtems_cpu_configuration_get_exceptions_in_ram() \
(_CPU_Table.exceptions_in_RAM)
/*
* This variable is optional. It is used on CPUs on which it is difficult
* to generate an "uninitialized" FP context. It is filled in by
* _CPU_Initialize and copied into the task's FP context area during
* _CPU_Context_Initialize.
*/
/* EXTERN Context_Control_fp _CPU_Null_fp_context; */
/*
* On some CPUs, RTEMS supports a software managed interrupt stack.
* This stack is allocated by the Interrupt Manager and the switch
* is performed in _ISR_Handler. These variables contain pointers
* to the lowest and highest addresses in the chunk of memory allocated
* for the interrupt stack. Since it is unknown whether the stack
* grows up or down (in general), this give the CPU dependent
* code the option of picking the version it wants to use.
*
* NOTE: These two variables are required if the macro
* CPU_HAS_SOFTWARE_INTERRUPT_STACK is defined as TRUE.
*/
SCORE_EXTERN void *_CPU_Interrupt_stack_low;
SCORE_EXTERN void *_CPU_Interrupt_stack_high;
#endif /* ndef ASM */
/*
* This defines the number of levels and the mask used to pick those
* bits out of a thread mode.
*/
#define CPU_MODES_INTERRUPT_LEVEL 0x00000001 /* interrupt level in mode */
#define CPU_MODES_INTERRUPT_MASK 0x00000001 /* interrupt level in mode */
/*
* With some compilation systems, it is difficult if not impossible to
* call a high-level language routine from assembly language. This
* is especially true of commercial Ada compilers and name mangling
* C++ ones. This variable can be optionally defined by the CPU porter
* and contains the address of the routine _Thread_Dispatch. This
* can make it easier to invoke that routine at the end of the interrupt
* sequence (if a dispatch is necessary).
*/
/* EXTERN void (*_CPU_Thread_dispatch_pointer)(); */
/*
* Nothing prevents the porter from declaring more CPU specific variables.
*/
#ifndef ASM
SCORE_EXTERN struct {
unsigned32 *Disable_level;
void *Stack;
volatile boolean *Switch_necessary;
boolean *Signal;
} _CPU_IRQ_info CPU_STRUCTURE_ALIGNMENT;
#endif /* ndef ASM */
/*
* The size of the floating point context area. On some CPUs this
* will not be a "sizeof" because the format of the floating point
* area is not defined -- only the size is. This is usually on
* CPUs with a "floating point save context" instruction.
*/
#define CPU_CONTEXT_FP_SIZE sizeof( Context_Control_fp )
/*
* (Optional) # of bytes for libmisc/stackchk to check
* If not specifed, then it defaults to something reasonable
* for most architectures.
*/
#define CPU_STACK_CHECK_SIZE (128)
/*
* Amount of extra stack (above minimum stack size) required by
* MPCI receive server thread. Remember that in a multiprocessor
* system this thread must exist and be able to process all directives.
*/
#define CPU_MPCI_RECEIVE_SERVER_EXTRA_STACK 0
/*
* This defines the number of entries in the ISR_Vector_table managed
* by RTEMS.
*/
#define CPU_INTERRUPT_NUMBER_OF_VECTORS (PPC_INTERRUPT_MAX)
#define CPU_INTERRUPT_MAXIMUM_VECTOR_NUMBER (PPC_INTERRUPT_MAX - 1)
/*
* Should be large enough to run all RTEMS tests. This insures
* that a "reasonable" small application should not have any problems.
*/
#define CPU_STACK_MINIMUM_SIZE (1024*8)
/*
* CPU's worst alignment requirement for data types on a byte boundary. This
* alignment does not take into account the requirements for the stack.
*/
#define CPU_ALIGNMENT (PPC_ALIGNMENT)
/*
* This number corresponds to the byte alignment requirement for the
* heap handler. This alignment requirement may be stricter than that
* for the data types alignment specified by CPU_ALIGNMENT. It is
* common for the heap to follow the same alignment requirement as
* CPU_ALIGNMENT. If the CPU_ALIGNMENT is strict enough for the heap,
* then this should be set to CPU_ALIGNMENT.
*
* NOTE: This does not have to be a power of 2. It does have to
* be greater or equal to than CPU_ALIGNMENT.
*/
#define CPU_HEAP_ALIGNMENT (PPC_ALIGNMENT)
/*
* This number corresponds to the byte alignment requirement for memory
* buffers allocated by the partition manager. This alignment requirement
* may be stricter than that for the data types alignment specified by
* CPU_ALIGNMENT. It is common for the partition to follow the same
* alignment requirement as CPU_ALIGNMENT. If the CPU_ALIGNMENT is strict
* enough for the partition, then this should be set to CPU_ALIGNMENT.
*
* NOTE: This does not have to be a power of 2. It does have to
* be greater or equal to than CPU_ALIGNMENT.
*/
#define CPU_PARTITION_ALIGNMENT (PPC_ALIGNMENT)
/*
* This number corresponds to the byte alignment requirement for the
* stack. This alignment requirement may be stricter than that for the
* data types alignment specified by CPU_ALIGNMENT. If the CPU_ALIGNMENT
* is strict enough for the stack, then this should be set to 0.
*
* NOTE: This must be a power of 2 either 0 or greater than CPU_ALIGNMENT.
*/
#define CPU_STACK_ALIGNMENT (PPC_STACK_ALIGNMENT)
/*
* Needed for Interrupt stack
*/
#define CPU_MINIMUM_STACK_FRAME_SIZE 8
/* ISR handler macros */
/*
* Disable all interrupts for an RTEMS critical section. The previous
* level is returned in _isr_cookie.
*/
#define loc_string(a,b) a " (" #b ")\n"
#ifndef ASM
static inline unsigned32 _CPU_ISR_Get_level( void )
{
register unsigned int msr;
_CPU_MSR_GET(msr);
if (msr & MSR_EE) return 0;
else return 1;
}
static inline void _CPU_ISR_Set_level( unsigned32 level )
{
register unsigned int msr;
_CPU_MSR_GET(msr);
if (!(level & CPU_MODES_INTERRUPT_MASK)) {
msr |= MSR_EE;
}
else {
msr &= ~MSR_EE;
}
_CPU_MSR_SET(msr);
}
#define _CPU_ISR_install_vector(irq, new, old) {BSP_panic("_CPU_ISR_install_vector called\n");}
/* Context handler macros */
/*
* Initialize the context to a state suitable for starting a
* task after a context restore operation. Generally, this
* involves:
*
* - setting a starting address
* - preparing the stack
* - preparing the stack and frame pointers
* - setting the proper interrupt level in the context
* - initializing the floating point context
*
* This routine generally does not set any unnecessary register
* in the context. The state of the "general data" registers is
* undefined at task start time.
*
* NOTE: Implemented as a subroutine for the SPARC port.
*/
void _CPU_Context_Initialize(
Context_Control *the_context,
unsigned32 *stack_base,
unsigned32 size,
unsigned32 new_level,
void *entry_point,
boolean is_fp
);
/*
* This routine is responsible for somehow restarting the currently
* executing task. If you are lucky, then all that is necessary
* is restoring the context. Otherwise, there will need to be
* a special assembly routine which does something special in this
* case. Context_Restore should work most of the time. It will
* not work if restarting self conflicts with the stack frame
* assumptions of restoring a context.
*/
#define _CPU_Context_Restart_self( _the_context ) \
_CPU_Context_restore( (_the_context) );
/*
* The purpose of this macro is to allow the initial pointer into
* a floating point context area (used to save the floating point
* context) to be at an arbitrary place in the floating point
* context area.
*
* This is necessary because some FP units are designed to have
* their context saved as a stack which grows into lower addresses.
* Other FP units can be saved by simply moving registers into offsets
* from the base of the context area. Finally some FP units provide
* a "dump context" instruction which could fill in from high to low
* or low to high based on the whim of the CPU designers.
*/
#define _CPU_Context_Fp_start( _base, _offset ) \
( (void *) _Addresses_Add_offset( (_base), (_offset) ) )
/*
* This routine initializes the FP context area passed to it to.
* There are a few standard ways in which to initialize the
* floating point context. The code included for this macro assumes
* that this is a CPU in which a "initial" FP context was saved into
* _CPU_Null_fp_context and it simply copies it to the destination
* context passed to it.
*
* Other models include (1) not doing anything, and (2) putting
* a "null FP status word" in the correct place in the FP context.
*/
#define _CPU_Context_Initialize_fp( _destination ) \
{ \
((Context_Control_fp *) *((void **) _destination))->fpscr = PPC_INIT_FPSCR; \
}
/* end of Context handler macros */
/* Fatal Error manager macros */
/*
* This routine copies _error into a known place -- typically a stack
* location or a register, optionally disables interrupts, and
* halts/stops the CPU.
*/
#define _CPU_Fatal_halt( _error ) \
_BSP_Fatal_error(_error)
/* end of Fatal Error manager macros */
/* Bitfield handler macros */
/*
* This routine sets _output to the bit number of the first bit
* set in _value. _value is of CPU dependent type Priority_Bit_map_control.
* This type may be either 16 or 32 bits wide although only the 16
* least significant bits will be used.
*
* There are a number of variables in using a "find first bit" type
* instruction.
*
* (1) What happens when run on a value of zero?
* (2) Bits may be numbered from MSB to LSB or vice-versa.
* (3) The numbering may be zero or one based.
* (4) The "find first bit" instruction may search from MSB or LSB.
*
* RTEMS guarantees that (1) will never happen so it is not a concern.
* (2),(3), (4) are handled by the macros _CPU_Priority_mask() and
* _CPU_Priority_Bits_index(). These three form a set of routines
* which must logically operate together. Bits in the _value are
* set and cleared based on masks built by _CPU_Priority_mask().
* The basic major and minor values calculated by _Priority_Major()
* and _Priority_Minor() are "massaged" by _CPU_Priority_Bits_index()
* to properly range between the values returned by the "find first bit"
* instruction. This makes it possible for _Priority_Get_highest() to
* calculate the major and directly index into the minor table.
* This mapping is necessary to ensure that 0 (a high priority major/minor)
* is the first bit found.
*
* This entire "find first bit" and mapping process depends heavily
* on the manner in which a priority is broken into a major and minor
* components with the major being the 4 MSB of a priority and minor
* the 4 LSB. Thus (0 << 4) + 0 corresponds to priority 0 -- the highest
* priority. And (15 << 4) + 14 corresponds to priority 254 -- the next
* to the lowest priority.
*
* If your CPU does not have a "find first bit" instruction, then
* there are ways to make do without it. Here are a handful of ways
* to implement this in software:
*
* - a series of 16 bit test instructions
* - a "binary search using if's"
* - _number = 0
* if _value > 0x00ff
* _value >>=8
* _number = 8;
*
* if _value > 0x0000f
* _value >=8
* _number += 4
*
* _number += bit_set_table[ _value ]
*
* where bit_set_table[ 16 ] has values which indicate the first
* bit set
*/
#define _CPU_Bitfield_Find_first_bit( _value, _output ) \
{ \
asm volatile ("cntlzw %0, %1" : "=r" ((_output)), "=r" ((_value)) : \
"1" ((_value))); \
}
/* end of Bitfield handler macros */
/*
* This routine builds the mask which corresponds to the bit fields
* as searched by _CPU_Bitfield_Find_first_bit(). See the discussion
* for that routine.
*/
#define _CPU_Priority_Mask( _bit_number ) \
( 0x80000000 >> (_bit_number) )
/*
* This routine translates the bit numbers returned by
* _CPU_Bitfield_Find_first_bit() into something suitable for use as
* a major or minor component of a priority. See the discussion
* for that routine.
*/
#define _CPU_Priority_bits_index( _priority ) \
(_priority)
/* end of Priority handler macros */
/* variables */
extern const unsigned32 _CPU_msrs[4];
/* functions */
/*
* _CPU_Initialize
*
* This routine performs CPU dependent initialization.
*/
void _CPU_Initialize(
rtems_cpu_table *cpu_table,
void (*thread_dispatch)
);
/*
* _CPU_Install_interrupt_stack
*
* This routine installs the hardware interrupt stack pointer.
*
* NOTE: It need only be provided if CPU_HAS_HARDWARE_INTERRUPT_STACK
* is TRUE.
*/
void _CPU_Install_interrupt_stack( void );
/*
* _CPU_Context_switch
*
* This routine switches from the run context to the heir context.
*/
void _CPU_Context_switch(
Context_Control *run,
Context_Control *heir
);
/*
* _CPU_Context_restore
*
* This routine is generallu used only to restart self in an
* efficient manner. It may simply be a label in _CPU_Context_switch.
*
* NOTE: May be unnecessary to reload some registers.
*/
void _CPU_Context_restore(
Context_Control *new_context
);
/*
* _CPU_Context_save_fp
*
* This routine saves the floating point context passed to it.
*/
void _CPU_Context_save_fp(
void **fp_context_ptr
);
/*
* _CPU_Context_restore_fp
*
* This routine restores the floating point context passed to it.
*/
void _CPU_Context_restore_fp(
void **fp_context_ptr
);
void _CPU_Fatal_error(
unsigned32 _error
);
/* The following routine swaps the endian format of an unsigned int.
* It must be static because it is referenced indirectly.
*
* This version will work on any processor, but if there is a better
* way for your CPU PLEASE use it. The most common way to do this is to:
*
* swap least significant two bytes with 16-bit rotate
* swap upper and lower 16-bits
* swap most significant two bytes with 16-bit rotate
*
* Some CPUs have special instructions which swap a 32-bit quantity in
* a single instruction (e.g. i486). It is probably best to avoid
* an "endian swapping control bit" in the CPU. One good reason is
* that interrupts would probably have to be disabled to insure that
* an interrupt does not try to access the same "chunk" with the wrong
* endian. Another good reason is that on some CPUs, the endian bit
* endianness for ALL fetches -- both code and data -- so the code
* will be fetched incorrectly.
*/
static inline unsigned int CPU_swap_u32(
unsigned int value
)
{
unsigned32 swapped;
asm volatile("rlwimi %0,%1,8,24,31;"
"rlwimi %0,%1,24,16,23;"
"rlwimi %0,%1,8,8,15;"
"rlwimi %0,%1,24,0,7;" :
"=&r" ((swapped)) : "r" ((value)));
return( swapped );
}
#define CPU_swap_u16( value ) \
(((value&0xff) << 8) | ((value >> 8)&0xff))
/*
* Routines to access the decrementer register
*/
#define PPC_Set_decrementer( _clicks ) \
do { \
asm volatile( "mtdec %0" : "=r" ((_clicks)) : "r" ((_clicks)) ); \
} while (0)
/*
* Routines to access the time base register
*/
static inline unsigned64 PPC_Get_timebase_register( void )
{
unsigned32 tbr_low;
unsigned32 tbr_high;
unsigned32 tbr_high_old;
unsigned64 tbr;
do {
asm volatile( "mftbu %0" : "=r" (tbr_high_old));
asm volatile( "mftb %0" : "=r" (tbr_low));
asm volatile( "mftbu %0" : "=r" (tbr_high));
} while ( tbr_high_old != tbr_high );
tbr = tbr_high;
tbr <<= 32;
tbr |= tbr_low;
return tbr;
}
#endif /* ndef ASM */
#ifdef __cplusplus
}
#endif
#endif

View File

@@ -0,0 +1,396 @@
/* cpu_asm.s 1.1 - 95/12/04
*
* This file contains the assembly code for the PowerPC implementation
* of RTEMS.
*
* Author: Andrew Bray <andy@i-cubed.co.uk>
*
* COPYRIGHT (c) 1995 by i-cubed ltd.
*
* To anyone who acknowledges that this file is provided "AS IS"
* without any express or implied warranty:
* permission to use, copy, modify, and distribute this file
* for any purpose is hereby granted without fee, provided that
* the above copyright notice and this notice appears in all
* copies, and that the name of i-cubed limited not be used in
* advertising or publicity pertaining to distribution of the
* software without specific, written prior permission.
* i-cubed limited makes no representations about the suitability
* of this software for any purpose.
*
* Derived from c/src/exec/cpu/no_cpu/cpu_asm.c:
*
* COPYRIGHT (c) 1989-1997.
* On-Line Applications Research Corporation (OAR).
* Copyright assigned to U.S. Government, 1994.
*
* The license and distribution terms for this file may in
* the file LICENSE in this distribution or at
* http://www.OARcorp.com/rtems/license.html.
*
* $Id$
*/
#include <asm.h>
/*
* Offsets for various Contexts
*/
.set GP_1, 0
.set GP_2, (GP_1 + 4)
.set GP_13, (GP_2 + 4)
.set GP_14, (GP_13 + 4)
.set GP_15, (GP_14 + 4)
.set GP_16, (GP_15 + 4)
.set GP_17, (GP_16 + 4)
.set GP_18, (GP_17 + 4)
.set GP_19, (GP_18 + 4)
.set GP_20, (GP_19 + 4)
.set GP_21, (GP_20 + 4)
.set GP_22, (GP_21 + 4)
.set GP_23, (GP_22 + 4)
.set GP_24, (GP_23 + 4)
.set GP_25, (GP_24 + 4)
.set GP_26, (GP_25 + 4)
.set GP_27, (GP_26 + 4)
.set GP_28, (GP_27 + 4)
.set GP_29, (GP_28 + 4)
.set GP_30, (GP_29 + 4)
.set GP_31, (GP_30 + 4)
.set GP_CR, (GP_31 + 4)
.set GP_PC, (GP_CR + 4)
.set GP_MSR, (GP_PC + 4)
.set FP_0, 0
.set FP_1, (FP_0 + 4)
.set FP_2, (FP_1 + 4)
.set FP_3, (FP_2 + 4)
.set FP_4, (FP_3 + 4)
.set FP_5, (FP_4 + 4)
.set FP_6, (FP_5 + 4)
.set FP_7, (FP_6 + 4)
.set FP_8, (FP_7 + 4)
.set FP_9, (FP_8 + 4)
.set FP_10, (FP_9 + 4)
.set FP_11, (FP_10 + 4)
.set FP_12, (FP_11 + 4)
.set FP_13, (FP_12 + 4)
.set FP_14, (FP_13 + 4)
.set FP_15, (FP_14 + 4)
.set FP_16, (FP_15 + 4)
.set FP_17, (FP_16 + 4)
.set FP_18, (FP_17 + 4)
.set FP_19, (FP_18 + 4)
.set FP_20, (FP_19 + 4)
.set FP_21, (FP_20 + 4)
.set FP_22, (FP_21 + 4)
.set FP_23, (FP_22 + 4)
.set FP_24, (FP_23 + 4)
.set FP_25, (FP_24 + 4)
.set FP_26, (FP_25 + 4)
.set FP_27, (FP_26 + 4)
.set FP_28, (FP_27 + 4)
.set FP_29, (FP_28 + 4)
.set FP_30, (FP_29 + 4)
.set FP_31, (FP_30 + 4)
.set FP_FPSCR, (FP_31 + 4)
.set IP_LINK, 0
.set IP_0, (IP_LINK + 8)
.set IP_2, (IP_0 + 4)
.set IP_3, (IP_2 + 4)
.set IP_4, (IP_3 + 4)
.set IP_5, (IP_4 + 4)
.set IP_6, (IP_5 + 4)
.set IP_7, (IP_6 + 4)
.set IP_8, (IP_7 + 4)
.set IP_9, (IP_8 + 4)
.set IP_10, (IP_9 + 4)
.set IP_11, (IP_10 + 4)
.set IP_12, (IP_11 + 4)
.set IP_13, (IP_12 + 4)
.set IP_28, (IP_13 + 4)
.set IP_29, (IP_28 + 4)
.set IP_30, (IP_29 + 4)
.set IP_31, (IP_30 + 4)
.set IP_CR, (IP_31 + 4)
.set IP_CTR, (IP_CR + 4)
.set IP_XER, (IP_CTR + 4)
.set IP_LR, (IP_XER + 4)
.set IP_PC, (IP_LR + 4)
.set IP_MSR, (IP_PC + 4)
.set IP_END, (IP_MSR + 16)
BEGIN_CODE
/*
* _CPU_Context_save_fp_context
*
* This routine is responsible for saving the FP context
* at *fp_context_ptr. If the point to load the FP context
* from is changed then the pointer is modified by this routine.
*
* Sometimes a macro implementation of this is in cpu.h which dereferences
* the ** and a similarly named routine in this file is passed something
* like a (Context_Control_fp *). The general rule on making this decision
* is to avoid writing assembly language.
*/
ALIGN (PPC_CACHE_ALIGNMENT, PPC_CACHE_ALIGN_POWER)
PUBLIC_PROC (_CPU_Context_save_fp)
PROC (_CPU_Context_save_fp):
#if (PPC_HAS_FPU == 1)
lwz r3, 0(r3)
stfs f0, FP_0(r3)
stfs f1, FP_1(r3)
stfs f2, FP_2(r3)
stfs f3, FP_3(r3)
stfs f4, FP_4(r3)
stfs f5, FP_5(r3)
stfs f6, FP_6(r3)
stfs f7, FP_7(r3)
stfs f8, FP_8(r3)
stfs f9, FP_9(r3)
stfs f10, FP_10(r3)
stfs f11, FP_11(r3)
stfs f12, FP_12(r3)
stfs f13, FP_13(r3)
stfs f14, FP_14(r3)
stfs f15, FP_15(r3)
stfs f16, FP_16(r3)
stfs f17, FP_17(r3)
stfs f18, FP_18(r3)
stfs f19, FP_19(r3)
stfs f20, FP_20(r3)
stfs f21, FP_21(r3)
stfs f22, FP_22(r3)
stfs f23, FP_23(r3)
stfs f24, FP_24(r3)
stfs f25, FP_25(r3)
stfs f26, FP_26(r3)
stfs f27, FP_27(r3)
stfs f28, FP_28(r3)
stfs f29, FP_29(r3)
stfs f30, FP_30(r3)
stfs f31, FP_31(r3)
mffs f2
stfs f2, FP_FPSCR(r3)
#endif
blr
/*
* _CPU_Context_restore_fp_context
*
* This routine is responsible for restoring the FP context
* at *fp_context_ptr. If the point to load the FP context
* from is changed then the pointer is modified by this routine.
*
* Sometimes a macro implementation of this is in cpu.h which dereferences
* the ** and a similarly named routine in this file is passed something
* like a (Context_Control_fp *). The general rule on making this decision
* is to avoid writing assembly language.
*/
ALIGN (PPC_CACHE_ALIGNMENT, PPC_CACHE_ALIGN_POWER)
PUBLIC_PROC (_CPU_Context_restore_fp)
PROC (_CPU_Context_restore_fp):
#if (PPC_HAS_FPU == 1)
lwz r3, 0(r3)
lfs f2, FP_FPSCR(r3)
mtfsf 255, f2
lfs f0, FP_0(r3)
lfs f1, FP_1(r3)
lfs f2, FP_2(r3)
lfs f3, FP_3(r3)
lfs f4, FP_4(r3)
lfs f5, FP_5(r3)
lfs f6, FP_6(r3)
lfs f7, FP_7(r3)
lfs f8, FP_8(r3)
lfs f9, FP_9(r3)
lfs f10, FP_10(r3)
lfs f11, FP_11(r3)
lfs f12, FP_12(r3)
lfs f13, FP_13(r3)
lfs f14, FP_14(r3)
lfs f15, FP_15(r3)
lfs f16, FP_16(r3)
lfs f17, FP_17(r3)
lfs f18, FP_18(r3)
lfs f19, FP_19(r3)
lfs f20, FP_20(r3)
lfs f21, FP_21(r3)
lfs f22, FP_22(r3)
lfs f23, FP_23(r3)
lfs f24, FP_24(r3)
lfs f25, FP_25(r3)
lfs f26, FP_26(r3)
lfs f27, FP_27(r3)
lfs f28, FP_28(r3)
lfs f29, FP_29(r3)
lfs f30, FP_30(r3)
lfs f31, FP_31(r3)
#endif
blr
/* _CPU_Context_switch
*
* This routine performs a normal non-FP context switch.
*/
ALIGN (PPC_CACHE_ALIGNMENT, PPC_CACHE_ALIGN_POWER)
PUBLIC_PROC (_CPU_Context_switch)
PROC (_CPU_Context_switch):
sync
isync
/* This assumes that all the registers are in the given order */
li r5, 32
addi r3,r3,-4
#if ( PPC_USE_DATA_CACHE )
dcbz r5, r3
#endif
stw r1, GP_1+4(r3)
stw r2, GP_2+4(r3)
#if (PPC_USE_MULTIPLE == 1)
addi r3, r3, GP_18+4
#if ( PPC_USE_DATA_CACHE )
dcbz r5, r3
#endif
stmw r13, GP_13-GP_18(r3)
#else
stw r13, GP_13+4(r3)
stw r14, GP_14+4(r3)
stw r15, GP_15+4(r3)
stw r16, GP_16+4(r3)
stw r17, GP_17+4(r3)
stwu r18, GP_18+4(r3)
#if ( PPC_USE_DATA_CACHE )
dcbz r5, r3
#endif
stw r19, GP_19-GP_18(r3)
stw r20, GP_20-GP_18(r3)
stw r21, GP_21-GP_18(r3)
stw r22, GP_22-GP_18(r3)
stw r23, GP_23-GP_18(r3)
stw r24, GP_24-GP_18(r3)
stw r25, GP_25-GP_18(r3)
stw r26, GP_26-GP_18(r3)
stw r27, GP_27-GP_18(r3)
stw r28, GP_28-GP_18(r3)
stw r29, GP_29-GP_18(r3)
stw r30, GP_30-GP_18(r3)
stw r31, GP_31-GP_18(r3)
#endif
#if ( PPC_USE_DATA_CACHE )
dcbt r0, r4
#endif
mfcr r6
stw r6, GP_CR-GP_18(r3)
mflr r7
stw r7, GP_PC-GP_18(r3)
mfmsr r8
stw r8, GP_MSR-GP_18(r3)
#if ( PPC_USE_DATA_CACHE )
dcbt r5, r4
#endif
lwz r1, GP_1(r4)
lwz r2, GP_2(r4)
#if (PPC_USE_MULTIPLE == 1)
addi r4, r4, GP_19
#if ( PPC_USE_DATA_CACHE )
dcbt r5, r4
#endif
lmw r13, GP_13-GP_19(r4)
#else
lwz r13, GP_13(r4)
lwz r14, GP_14(r4)
lwz r15, GP_15(r4)
lwz r16, GP_16(r4)
lwz r17, GP_17(r4)
lwz r18, GP_18(r4)
lwzu r19, GP_19(r4)
#if ( PPC_USE_DATA_CACHE )
dcbt r5, r4
#endif
lwz r20, GP_20-GP_19(r4)
lwz r21, GP_21-GP_19(r4)
lwz r22, GP_22-GP_19(r4)
lwz r23, GP_23-GP_19(r4)
lwz r24, GP_24-GP_19(r4)
lwz r25, GP_25-GP_19(r4)
lwz r26, GP_26-GP_19(r4)
lwz r27, GP_27-GP_19(r4)
lwz r28, GP_28-GP_19(r4)
lwz r29, GP_29-GP_19(r4)
lwz r30, GP_30-GP_19(r4)
lwz r31, GP_31-GP_19(r4)
#endif
lwz r6, GP_CR-GP_19(r4)
lwz r7, GP_PC-GP_19(r4)
lwz r8, GP_MSR-GP_19(r4)
mtcrf 255, r6
mtlr r7
mtmsr r8
blr
/*
* _CPU_Context_restore
*
* This routine is generallu used only to restart self in an
* efficient manner. It may simply be a label in _CPU_Context_switch.
*
* NOTE: May be unnecessary to reload some registers.
*/
/*
* ACB: Don't worry about cache optimisation here - this is not THAT critical.
*/
ALIGN (PPC_CACHE_ALIGNMENT, PPC_CACHE_ALIGN_POWER)
PUBLIC_PROC (_CPU_Context_restore)
PROC (_CPU_Context_restore):
lwz r5, GP_CR(r3)
lwz r6, GP_PC(r3)
lwz r7, GP_MSR(r3)
mtcrf 255, r5
mtlr r6
mtmsr r7
lwz r1, GP_1(r3)
lwz r2, GP_2(r3)
#if (PPC_USE_MULTIPLE == 1)
lmw r13, GP_13(r3)
#else
lwz r13, GP_13(r3)
lwz r14, GP_14(r3)
lwz r15, GP_15(r3)
lwz r16, GP_16(r3)
lwz r17, GP_17(r3)
lwz r18, GP_18(r3)
lwz r19, GP_19(r3)
lwz r20, GP_20(r3)
lwz r21, GP_21(r3)
lwz r22, GP_22(r3)
lwz r23, GP_23(r3)
lwz r24, GP_24(r3)
lwz r25, GP_25(r3)
lwz r26, GP_26(r3)
lwz r27, GP_27(r3)
lwz r28, GP_28(r3)
lwz r29, GP_29(r3)
lwz r30, GP_30(r3)
lwz r31, GP_31(r3)
#endif
blr

View File

@@ -0,0 +1,90 @@
#
# $Id$
#
@SET_MAKE@
srcdir = @srcdir@
top_srcdir = @top_srcdir@
top_builddir = ../..
subdir = powerpc/old_exception_processing
RTEMS_ROOT = @RTEMS_ROOT@
PROJECT_ROOT = @PROJECT_ROOT@
VPATH = @srcdir@
RELS = ../$(ARCH)/rtems-cpu.rel
# C source names, if any, go here -- minus the .c
C_PIECES = cpu ppccache
C_FILES = $(C_PIECES:%=%.c)
C_O_FILES = $(C_PIECES:%=${ARCH}/%.o)
ROOT_H_PIECES =
ROOT_H_FILES = $(ROOT_H_PIECES:%=$(srcdir)/%)
RTEMS_SCORE_H_PIECES = cpu.h
RTEMS_SCORE_H_FILES = $(RTEMS_SCORE_H_PIECES:%=$(srcdir)/%)
H_PIECES = $(ROOT_H_PIECES) $(RTEMS_SCORE_H_PIECES)
H_FILES = $(H_PIECES%=$(srcdir)/%)
I_PIECES = c_isr
I_FILES = $(I_PIECES:%=$(srcdir)/%.inl)
# Assembly source names, if any, go here -- minus the .S
S_PIECES = cpu_asm rtems # irq_stub
S_FILES = $(S_PIECES:%=%.S)
S_O_FILES = $(S_FILES:%.S=${ARCH}/%.o)
SRCS = $(C_FILES) $(CC_FILES) $(H_FILES) $(S_FILES) $(EXTERNAL_H_FILES) \
$(I_FILES)
OBJS = $(C_O_FILES) $(CC_O_FILES) $(S_O_FILES)
include $(RTEMS_ROOT)/make/custom/@RTEMS_BSP@.cfg
include $(RTEMS_ROOT)/make/leaf.cfg
INSTALL_CHANGE = @INSTALL_CHANGE@
mkinstalldirs = $(SHELL) $(top_srcdir)/@RTEMS_TOPdir@/mkinstalldirs
INSTALLDIRS = $(PROJECT_INCLUDE)/rtems/score $(PROJECT_INCLUDE)
$(INSTALLDIRS):
@$(mkinstalldirs) $(INSTALLDIRS)
#
# (OPTIONAL) Add local stuff here using +=
#
DEFINES +=
CPPFLAGS +=
CFLAGS += $(CFLAGS_OS_V)
LD_PATHS +=
LD_LIBS +=
LDFLAGS +=
#
# Add your list of files to delete here. The config files
# already know how to delete some stuff, so you may want
# to just run 'make clean' first to see what gets missed.
# 'make clobber' already includes 'make clean'
#
CLEAN_ADDITIONS +=
CLOBBER_ADDITIONS +=
../$(ARCH)/rtems-cpu.rel: $(OBJS)
test -d ../$(ARCH) || mkdir ../$(ARCH)
$(make-rel)
all: ${ARCH} $(SRCS) preinstall $(OBJS) $(RELS)
# Install the program(s), appending _g or _p as appropriate.
# for include files, just use $(INSTALL_CHANGE)
install: all
preinstall: ${ARCH}
@$(INSTALL_CHANGE) -m 644 $(RTEMS_SCORE_H_FILES) $(I_FILES) $(PROJECT_INCLUDE)/rtems/score
@$(INSTALL_CHANGE) -m 644 $(ROOT_H_FILES) $(PROJECT_INCLUDE)
Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
cd $(top_builddir) \
&& CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status

View File

@@ -0,0 +1,80 @@
#
# $Id$
#
There are various issues regarding this port:
1) Legal
This port is written by Andrew Bray <andy@i-cubed.co.uk>, and
is copyright 1995 i-cubed ltd.
This port was later updated by Joel Sherrill <joel@OARcorp.com>
to test the support for the PPC603, PPC603e, and MPC604. This
was tested on the PowerPC simulator PSIM and a VMEbus single board
computer.
2) CPU support.
This release fully supports the PPC403GA, PPC403GB, PPC603, PPC603e,
MPC604, MPC750, and numerous MPC8xx processors. A good faith attempt
has been made to include support other models based upon available
documentation including the MPC5xx. There are two interrupt structures
supported by the PowerPC port. The newer structure is supported by
all the MPC750 and MPC604 BSPs. This structure is required to use
the RDBG remote debugging support.
This port was originally written and tested on the PPC403GA (using
software floating point). Current ports are tested primarily on
60x CPUs using the PowerPC simulator PSIM.
Andrew Bray received assistance during the initial porting effort
from IBM and Blue Micro and we would like to gratefully acknowledge
that help.
The support for the PPC602 processor is incomplete as only sketchy
data is currently available. Perhaps this model has been dropped.
3) Application Binary Interface
In the context of RTEMS, the ABI is of interest for the following
aspects:
a) Register usage. Which registers are used to provide static variable
linkage, stack pointer etc.
b) Function calling convention. How parameters are passed, how function
variables should be invoked, how values are returned, etc.
c) Stack frame layout.
I am aware of a number of ABIs for the PowerPC:
a) The PowerOpen ABI. This is the original Power ABI used on the RS/6000.
This is the only ABI supported by versions of GCC before 2.7.0.
b) The SVR4 ABI. This is the ABI defined by SunSoft for the Solaris port
to the PowerPC.
c) The Embedded ABI. This is an embedded ABI for PowerPC use, which has no
operating system interface defined. It is promoted by SunSoft, Motorola,
and Cygnus Support. Cygnus are porting the GNU toolchain to this ABI.
d) GCC 2.7.0. This compiler is partway along the road to supporting the EABI,
but is currently halfway in between.
This port was built and tested using the PowerOpen ABI, with the following
caveat: we used an ELF assembler and linker. So some attention may be
required on the assembler files to get them through a traditional (XCOFF)
PowerOpen assembler.
This port contains support for the other ABIs, but this may prove to be
incomplete as it is untested.
The RTEMS PowerPC port supports EABI as the primary ABI. The powerpc-rtems
GNU toolset configuration is EABI.
Andrew Bray, 4 December 1995
Joel Sherrill, 16 July 1997

View File

@@ -0,0 +1,8 @@
#
# $Id$
#
Todo list:
Maybe decode external interrupts like the HPPA does.
See c/src/lib/libcpu/powerpc/ppc403/ictrl/* for implementation on ppc403

View File

@@ -0,0 +1,4 @@
RTEMS_INLINE_ROUTINE boolean _ISR_Is_in_progress( void )
{
return (_ISR_Nest_level != 0);
}

View File

@@ -0,0 +1,853 @@
/*
* PowerPC CPU Dependent Source
*
* Author: Andrew Bray <andy@i-cubed.co.uk>
*
* COPYRIGHT (c) 1995 by i-cubed ltd.
*
* To anyone who acknowledges that this file is provided "AS IS"
* without any express or implied warranty:
* permission to use, copy, modify, and distribute this file
* for any purpose is hereby granted without fee, provided that
* the above copyright notice and this notice appears in all
* copies, and that the name of i-cubed limited not be used in
* advertising or publicity pertaining to distribution of the
* software without specific, written prior permission.
* i-cubed limited makes no representations about the suitability
* of this software for any purpose.
*
* Derived from c/src/exec/cpu/no_cpu/cpu.c:
*
* COPYRIGHT (c) 1989-1997.
* On-Line Applications Research Corporation (OAR).
* Copyright assigned to U.S. Government, 1994.
*
* The license and distribution terms for this file may be found in
* the file LICENSE in this distribution or at
* http://www.OARcorp.com/rtems/license.html.
*
* $Id$
*/
#include <rtems/system.h>
#include <rtems/score/isr.h>
#include <rtems/score/context.h>
#include <rtems/score/thread.h>
#include <rtems/score/interr.h>
/*
* These are for testing purposes.
*/
/* _CPU_Initialize
*
* This routine performs processor dependent initialization.
*
* INPUT PARAMETERS:
* cpu_table - CPU table to initialize
* thread_dispatch - address of disptaching routine
*/
static void ppc_spurious(int, CPU_Interrupt_frame *);
void _CPU_Initialize(
rtems_cpu_table *cpu_table,
void (*thread_dispatch) /* ignored on this CPU */
)
{
proc_ptr handler = (proc_ptr)ppc_spurious;
int i;
#if (PPC_ABI != PPC_ABI_POWEROPEN)
register unsigned32 r2 = 0;
#if (PPC_ABI != PPC_ABI_GCC27)
register unsigned32 r13 = 0;
asm ("mr %0,13" : "=r" ((r13)) : "0" ((r13)));
_CPU_IRQ_info.Default_r13 = r13;
#endif
asm ("mr %0,2" : "=r" ((r2)) : "0" ((r2)));
_CPU_IRQ_info.Default_r2 = r2;
#endif
_CPU_IRQ_info.Nest_level = &_ISR_Nest_level;
_CPU_IRQ_info.Disable_level = &_Thread_Dispatch_disable_level;
_CPU_IRQ_info.Vector_table = _ISR_Vector_table;
#if (PPC_ABI == PPC_ABI_POWEROPEN)
_CPU_IRQ_info.Dispatch_r2 = ((unsigned32 *)_Thread_Dispatch)[1];
#endif
_CPU_IRQ_info.Switch_necessary = &_Context_Switch_necessary;
_CPU_IRQ_info.Signal = &_ISR_Signals_to_thread_executing;
#if (PPC_USE_SPRG)
i = (int)&_CPU_IRQ_info;
asm volatile("mtspr 0x113, %0" : "=r" (i) : "0" (i)); /* SPRG 3 */
#endif
/*
* Store Msr Value in the IRQ info structure.
*/
_CPU_MSR_Value(_CPU_IRQ_info.msr_initial);
#if (PPC_USE_SPRG)
i = _CPU_IRQ_info.msr_initial;
asm volatile("mtspr 0x112, %0" : "=r" (i) : "0" (i)); /* SPRG 2 */
#endif
if ( cpu_table->spurious_handler )
handler = (proc_ptr)cpu_table->spurious_handler;
for (i = 0; i < PPC_INTERRUPT_MAX; i++)
_ISR_Vector_table[i] = handler;
_CPU_Table = *cpu_table;
}
/*PAGE
*
* _CPU_ISR_Calculate_level
*
* The PowerPC puts its interrupt enable status in the MSR register
* which also contains things like endianness control. To be more
* awkward, the layout varies from processor to processor. This
* is why it was necessary to adopt a scheme which allowed the user
* to specify specifically which interrupt sources were enabled.
*/
unsigned32 _CPU_ISR_Calculate_level(
unsigned32 new_level
)
{
register unsigned32 new_msr = 0;
/*
* Set the critical interrupt enable bit
*/
#if (PPC_HAS_RFCI)
if ( !(new_level & PPC_INTERRUPT_LEVEL_CE) )
new_msr |= PPC_MSR_CE;
#endif
if ( !(new_level & PPC_INTERRUPT_LEVEL_ME) )
new_msr |= PPC_MSR_ME;
if ( !(new_level & PPC_INTERRUPT_LEVEL_EE) )
new_msr |= PPC_MSR_EE;
return new_msr;
}
/*PAGE
*
* _CPU_ISR_Set_level
*
* This routine sets the requested level in the MSR.
*/
void _CPU_ISR_Set_level(
unsigned32 new_level
)
{
register unsigned32 tmp = 0;
register unsigned32 new_msr;
new_msr = _CPU_ISR_Calculate_level( new_level );
asm volatile (
"mfmsr %0; andc %0,%0,%1; and %2, %2, %1; or %0, %0, %2; mtmsr %0" :
"=&r" ((tmp)) :
"r" ((PPC_MSR_DISABLE_MASK)), "r" ((new_msr)), "0" ((tmp))
);
}
/*PAGE
*
* _CPU_ISR_Get_level
*
* This routine gets the current interrupt level from the MSR and
* converts it to an RTEMS interrupt level.
*/
unsigned32 _CPU_ISR_Get_level( void )
{
unsigned32 level = 0;
unsigned32 msr;
asm volatile("mfmsr %0" : "=r" ((msr)));
msr &= PPC_MSR_DISABLE_MASK;
/*
* Set the critical interrupt enable bit
*/
#if (PPC_HAS_RFCI)
if ( !(msr & PPC_MSR_CE) )
level |= PPC_INTERRUPT_LEVEL_CE;
#endif
if ( !(msr & PPC_MSR_ME) )
level |= PPC_INTERRUPT_LEVEL_ME;
if ( !(msr & PPC_MSR_EE) )
level |= PPC_INTERRUPT_LEVEL_EE;
return level;
}
/*PAGE
*
* _CPU_Context_Initialize
*/
#if (PPC_ABI == PPC_ABI_POWEROPEN)
#define CPU_MINIMUM_STACK_FRAME_SIZE 56
#else /* PPC_ABI_SVR4 or PPC_ABI_EABI */
#define CPU_MINIMUM_STACK_FRAME_SIZE 8
#endif
void _CPU_Context_Initialize(
Context_Control *the_context,
unsigned32 *stack_base,
unsigned32 size,
unsigned32 new_level,
void *entry_point,
boolean is_fp
)
{
unsigned32 msr_value;
unsigned32 sp;
sp = (unsigned32)stack_base + size - CPU_MINIMUM_STACK_FRAME_SIZE;
*((unsigned32 *)sp) = 0;
the_context->gpr1 = sp;
the_context->msr = _CPU_ISR_Calculate_level( new_level );
/*
* The FP bit of the MSR should only be enabled if this is a floating
* point task. Unfortunately, the vfprintf_r routine in newlib
* ends up pushing a floating point register regardless of whether or
* not a floating point number is being printed. Serious restructuring
* of vfprintf.c will be required to avoid this behavior. At this
* time (7 July 1997), this restructuring is not being done.
*/
/*if ( is_fp ) */
the_context->msr |= PPC_MSR_FP;
/*
* Calculate the task's MSR value:
*
* + Set the exception prefix bit to point to the exception table
* + Force the RI bit
* + Use the DR and IR bits
*/
_CPU_MSR_Value( msr_value );
the_context->msr |= (msr_value & PPC_MSR_EP);
the_context->msr |= PPC_MSR_RI;
the_context->msr |= msr_value & (PPC_MSR_DR|PPC_MSR_IR);
#if (PPC_ABI == PPC_ABI_POWEROPEN)
{ unsigned32 *desc = (unsigned32 *)entry_point;
the_context->pc = desc[0];
the_context->gpr2 = desc[1];
}
#endif
#if (PPC_ABI == PPC_ABI_SVR4)
{ unsigned r13 = 0;
asm volatile ("mr %0, 13" : "=r" ((r13)));
the_context->pc = (unsigned32)entry_point;
the_context->gpr13 = r13;
}
#endif
#if (PPC_ABI == PPC_ABI_EABI)
{ unsigned32 r2 = 0;
unsigned r13 = 0;
asm volatile ("mr %0,2; mr %1,13" : "=r" ((r2)), "=r" ((r13)));
the_context->pc = (unsigned32)entry_point;
the_context->gpr2 = r2;
the_context->gpr13 = r13;
}
#endif
}
/* _CPU_ISR_install_vector
*
* This kernel routine installs the RTEMS handler for the
* specified vector.
*
* Input parameters:
* vector - interrupt vector number
* old_handler - former ISR for this vector number
* new_handler - replacement ISR for this vector number
*
* Output parameters: NONE
*
*/
void _CPU_ISR_install_vector(
unsigned32 vector,
proc_ptr new_handler,
proc_ptr *old_handler
)
{
proc_ptr ignored;
*old_handler = _ISR_Vector_table[ vector ];
/*
* If the interrupt vector table is a table of pointer to isr entry
* points, then we need to install the appropriate RTEMS interrupt
* handler for this vector number.
*/
/*
* Install the wrapper so this ISR can be invoked properly.
*/
if (_CPU_Table.exceptions_in_RAM)
_CPU_ISR_install_raw_handler( vector, _ISR_Handler, &ignored );
/*
* We put the actual user ISR address in '_ISR_vector_table'. This will
* be used by the _ISR_Handler so the user gets control.
*/
_ISR_Vector_table[ vector ] = new_handler ? (ISR_Handler_entry)new_handler :
_CPU_Table.spurious_handler ?
(ISR_Handler_entry)_CPU_Table.spurious_handler :
(ISR_Handler_entry)ppc_spurious;
}
/*PAGE
*
* _CPU_Install_interrupt_stack
*/
void _CPU_Install_interrupt_stack( void )
{
#if (PPC_ABI == PPC_ABI_POWEROPEN || PPC_ABI == PPC_ABI_GCC27)
_CPU_IRQ_info.Stack = _CPU_Interrupt_stack_high - 56;
#else
_CPU_IRQ_info.Stack = _CPU_Interrupt_stack_high - 8;
#endif
}
/* Handle a spurious interrupt */
static void ppc_spurious(int v, CPU_Interrupt_frame *i)
{
#if 0
printf("Spurious interrupt on vector %d from %08.8x\n",
v, i->pc);
#endif
#ifdef ppc403
if (v == PPC_IRQ_EXTERNAL)
{
register int r = 0;
asm volatile("mtdcr 0x42, %0" :
"=&r" ((r)) : "0" ((r))); /* EXIER */
}
else if (v == PPC_IRQ_PIT)
{
register int r = 0x08000000;
asm volatile("mtspr 0x3d8, %0" :
"=&r" ((r)) : "0" ((r))); /* TSR */
}
else if (v == PPC_IRQ_FIT)
{
register int r = 0x04000000;
asm volatile("mtspr 0x3d8, %0" :
"=&r" ((r)) : "0" ((r))); /* TSR */
}
#endif
}
void _CPU_Fatal_error(unsigned32 _error)
{
asm volatile ("mr 3, %0" : : "r" ((_error)));
asm volatile ("tweq 5,5");
asm volatile ("li 0,0; mtmsr 0");
while (1) ;
}
#define PPC_SYNCHRONOUS_TRAP_BIT_MASK 0x100
#define PPC_ASYNCHRONOUS_TRAP( _trap ) (_trap)
#define PPC_SYNCHRONOUS_TRAP ( _trap ) ((_trap)+PPC_SYNCHRONOUS_TRAP_BIT_MASK)
#define PPC_REAL_TRAP_NUMBER ( _trap ) ((_trap)%PPC_SYNCHRONOUS_TRAP_BIT_MASK)
const CPU_Trap_table_entry _CPU_Trap_slot_template = {
#if (PPC_ABI == PPC_ABI_POWEROPEN || PPC_ABI == PPC_ABI_GCC27)
#error " Vector install not tested."
#if (PPC_HAS_FPU)
#error " Vector install not tested."
0x9421feb0, /* stwu r1, -(20*4 + 18*8 + IP_END)(r1) */
#else
#error " Vector install not tested."
0x9421ff40, /* stwu r1, -(20*4 + IP_END)(r1) */
#endif
#else
0x9421ff90, /* stwu r1, -(IP_END)(r1) */
#endif
0x90010008, /* stw %r0, IP_0(%r1) */
0x38000000, /* li %r0, PPC_IRQ */
0x48000002 /* ba PROC (_ISR_Handler) */
};
#if defined(mpc860) || defined(mpc821)
const CPU_Trap_table_entry _CPU_Trap_slot_template_m860 = {
0x7c0803ac, /* mtlr %r0 */
0x81210028, /* lwz %r9, IP_9(%r1) */
0x38000000, /* li %r0, PPC_IRQ */
0x48000002 /* b PROC (_ISR_Handler) */
};
#endif /* mpc860 */
unsigned32 ppc_exception_vector_addr(
unsigned32 vector
);
/*PAGE
*
* _CPU_ISR_install_raw_handler
*
* This routine installs the specified handler as a "raw" non-executive
* supported trap handler (a.k.a. interrupt service routine).
*
* Input Parameters:
* vector - trap table entry number plus synchronous
* vs. asynchronous information
* new_handler - address of the handler to be installed
* old_handler - pointer to an address of the handler previously installed
*
* Output Parameters: NONE
* *new_handler - address of the handler previously installed
*
* NOTE:
*
* This routine is based on the SPARC routine _CPU_ISR_install_raw_handler.
* Install a software trap handler as an executive interrupt handler
* (which is desirable since RTEMS takes care of window and register issues),
* then the executive needs to know that the return address is to the trap
* rather than the instruction following the trap.
*
*/
void _CPU_ISR_install_raw_handler(
unsigned32 vector,
proc_ptr new_handler,
proc_ptr *old_handler
)
{
unsigned32 real_vector;
CPU_Trap_table_entry *slot;
unsigned32 u32_handler=0;
/*
* Get the "real" trap number for this vector ignoring the synchronous
* versus asynchronous indicator included with our vector numbers.
*/
real_vector = vector;
/*
* Get the current base address of the trap table and calculate a pointer
* to the slot we are interested in.
*/
slot = (CPU_Trap_table_entry *)ppc_exception_vector_addr( real_vector );
/*
* Get the address of the old_handler from the trap table.
*
* NOTE: The old_handler returned will be bogus if it does not follow
* the RTEMS model.
*/
#define HIGH_BITS_MASK 0xFFFFFC00
#define HIGH_BITS_SHIFT 10
#define LOW_BITS_MASK 0x000003FF
if (slot->stwu_r1 == _CPU_Trap_slot_template.stwu_r1) {
/*
* Set u32_handler = to target address
*/
u32_handler = slot->b_Handler & 0x03fffffc;
/* IMD FIX: sign extend address fragment... */
if (u32_handler & 0x02000000) {
u32_handler |= 0xfc000000;
}
*old_handler = (proc_ptr) u32_handler;
} else
/* There are two kinds of handlers for the MPC860. One is the 'standard'
* one like above. The other is for the cascaded interrupts from the SIU
* and CPM. Therefore we must check for the alternate one if the standard
* one is not present
*/
#if defined(mpc860) || defined(mpc821)
if (slot->stwu_r1 == _CPU_Trap_slot_template_m860.stwu_r1) {
/*
* Set u32_handler = to target address
*/
u32_handler = slot->b_Handler & 0x03fffffc;
*old_handler = (proc_ptr) u32_handler;
} else
#endif /* mpc860 */
*old_handler = 0;
/*
* Copy the template to the slot and then fix it.
*/
#if defined(mpc860) || defined(mpc821)
if (vector >= PPC_IRQ_IRQ0)
*slot = _CPU_Trap_slot_template_m860;
else
#endif /* mpc860 */
*slot = _CPU_Trap_slot_template;
u32_handler = (unsigned32) new_handler;
/*
* IMD FIX: insert address fragment only (bits 6..29)
* therefore check for proper address range
* and remove unwanted bits
*/
if ((u32_handler & 0xfc000000) == 0xfc000000) {
u32_handler &= ~0xfc000000;
}
else if ((u32_handler & 0xfc000000) != 0x00000000) {
_Internal_error_Occurred(INTERNAL_ERROR_CORE,
TRUE,
u32_handler);
}
slot->b_Handler |= u32_handler;
slot->li_r0_IRQ |= vector;
_CPU_Data_Cache_Block_Flush( slot );
}
unsigned32 ppc_exception_vector_addr(
unsigned32 vector
)
{
#if (!PPC_HAS_EVPR)
unsigned32 Msr;
#endif
unsigned32 Top = 0;
unsigned32 Offset = 0x000;
#if (PPC_HAS_EXCEPTION_PREFIX)
_CPU_MSR_Value ( Msr );
if ( ( Msr & PPC_MSR_EP) != 0 ) /* Vectors at FFFx_xxxx */
Top = 0xfff00000;
#elif (PPC_HAS_EVPR)
asm volatile( "mfspr %0,0x3d6" : "=r" (Top)); /* EVPR */
Top = Top & 0xffff0000;
#endif
switch ( vector ) {
case PPC_IRQ_SYSTEM_RESET: /* on 40x aka PPC_IRQ_CRIT */
Offset = 0x00100;
break;
case PPC_IRQ_MCHECK:
Offset = 0x00200;
break;
case PPC_IRQ_PROTECT:
Offset = 0x00300;
break;
case PPC_IRQ_ISI:
Offset = 0x00400;
break;
case PPC_IRQ_EXTERNAL:
Offset = 0x00500;
break;
case PPC_IRQ_ALIGNMENT:
Offset = 0x00600;
break;
case PPC_IRQ_PROGRAM:
Offset = 0x00700;
break;
case PPC_IRQ_NOFP:
Offset = 0x00800;
break;
case PPC_IRQ_DECREMENTER:
Offset = 0x00900;
break;
case PPC_IRQ_RESERVED_A:
Offset = 0x00a00;
break;
case PPC_IRQ_RESERVED_B:
Offset = 0x00b00;
break;
case PPC_IRQ_SCALL:
Offset = 0x00c00;
break;
case PPC_IRQ_TRACE:
Offset = 0x00d00;
break;
case PPC_IRQ_FP_ASST:
Offset = 0x00e00;
break;
#if defined(ppc403)
/* PPC_IRQ_CRIT is the same vector as PPC_IRQ_RESET
case PPC_IRQ_CRIT:
Offset = 0x00100;
break;
*/
case PPC_IRQ_PIT:
Offset = 0x01000;
break;
case PPC_IRQ_FIT:
Offset = 0x01010;
break;
case PPC_IRQ_WATCHDOG:
Offset = 0x01020;
break;
case PPC_IRQ_DEBUG:
Offset = 0x02000;
break;
#elif defined(ppc601)
case PPC_IRQ_TRACE:
Offset = 0x02000;
break;
#elif defined(ppc603)
case PPC_IRQ_TRANS_MISS:
Offset = 0x1000;
break;
case PPC_IRQ_DATA_LOAD:
Offset = 0x1100;
break;
case PPC_IRQ_DATA_STORE:
Offset = 0x1200;
break;
case PPC_IRQ_ADDR_BRK:
Offset = 0x1300;
break;
case PPC_IRQ_SYS_MGT:
Offset = 0x1400;
break;
#elif defined(ppc603e)
case PPC_TLB_INST_MISS:
Offset = 0x1000;
break;
case PPC_TLB_LOAD_MISS:
Offset = 0x1100;
break;
case PPC_TLB_STORE_MISS:
Offset = 0x1200;
break;
case PPC_IRQ_ADDRBRK:
Offset = 0x1300;
break;
case PPC_IRQ_SYS_MGT:
Offset = 0x1400;
break;
#elif defined(mpc604)
case PPC_IRQ_ADDR_BRK:
Offset = 0x1300;
break;
case PPC_IRQ_SYS_MGT:
Offset = 0x1400;
break;
#elif defined(mpc860) || defined(mpc821)
case PPC_IRQ_EMULATE:
Offset = 0x1000;
break;
case PPC_IRQ_INST_MISS:
Offset = 0x1100;
break;
case PPC_IRQ_DATA_MISS:
Offset = 0x1200;
break;
case PPC_IRQ_INST_ERR:
Offset = 0x1300;
break;
case PPC_IRQ_DATA_ERR:
Offset = 0x1400;
break;
case PPC_IRQ_DATA_BPNT:
Offset = 0x1c00;
break;
case PPC_IRQ_INST_BPNT:
Offset = 0x1d00;
break;
case PPC_IRQ_IO_BPNT:
Offset = 0x1e00;
break;
case PPC_IRQ_DEV_PORT:
Offset = 0x1f00;
break;
case PPC_IRQ_IRQ0:
Offset = 0x2000;
break;
case PPC_IRQ_LVL0:
Offset = 0x2040;
break;
case PPC_IRQ_IRQ1:
Offset = 0x2080;
break;
case PPC_IRQ_LVL1:
Offset = 0x20c0;
break;
case PPC_IRQ_IRQ2:
Offset = 0x2100;
break;
case PPC_IRQ_LVL2:
Offset = 0x2140;
break;
case PPC_IRQ_IRQ3:
Offset = 0x2180;
break;
case PPC_IRQ_LVL3:
Offset = 0x21c0;
break;
case PPC_IRQ_IRQ4:
Offset = 0x2200;
break;
case PPC_IRQ_LVL4:
Offset = 0x2240;
break;
case PPC_IRQ_IRQ5:
Offset = 0x2280;
break;
case PPC_IRQ_LVL5:
Offset = 0x22c0;
break;
case PPC_IRQ_IRQ6:
Offset = 0x2300;
break;
case PPC_IRQ_LVL6:
Offset = 0x2340;
break;
case PPC_IRQ_IRQ7:
Offset = 0x2380;
break;
case PPC_IRQ_LVL7:
Offset = 0x23c0;
break;
case PPC_IRQ_CPM_RESERVED_0:
Offset = 0x2400;
break;
case PPC_IRQ_CPM_PC4:
Offset = 0x2410;
break;
case PPC_IRQ_CPM_PC5:
Offset = 0x2420;
break;
case PPC_IRQ_CPM_SMC2:
Offset = 0x2430;
break;
case PPC_IRQ_CPM_SMC1:
Offset = 0x2440;
break;
case PPC_IRQ_CPM_SPI:
Offset = 0x2450;
break;
case PPC_IRQ_CPM_PC6:
Offset = 0x2460;
break;
case PPC_IRQ_CPM_TIMER4:
Offset = 0x2470;
break;
case PPC_IRQ_CPM_RESERVED_8:
Offset = 0x2480;
break;
case PPC_IRQ_CPM_PC7:
Offset = 0x2490;
break;
case PPC_IRQ_CPM_PC8:
Offset = 0x24a0;
break;
case PPC_IRQ_CPM_PC9:
Offset = 0x24b0;
break;
case PPC_IRQ_CPM_TIMER3:
Offset = 0x24c0;
break;
case PPC_IRQ_CPM_RESERVED_D:
Offset = 0x24d0;
break;
case PPC_IRQ_CPM_PC10:
Offset = 0x24e0;
break;
case PPC_IRQ_CPM_PC11:
Offset = 0x24f0;
break;
case PPC_IRQ_CPM_I2C:
Offset = 0x2500;
break;
case PPC_IRQ_CPM_RISC_TIMER:
Offset = 0x2510;
break;
case PPC_IRQ_CPM_TIMER2:
Offset = 0x2520;
break;
case PPC_IRQ_CPM_RESERVED_13:
Offset = 0x2530;
break;
case PPC_IRQ_CPM_IDMA2:
Offset = 0x2540;
break;
case PPC_IRQ_CPM_IDMA1:
Offset = 0x2550;
break;
case PPC_IRQ_CPM_SDMA_ERROR:
Offset = 0x2560;
break;
case PPC_IRQ_CPM_PC12:
Offset = 0x2570;
break;
case PPC_IRQ_CPM_PC13:
Offset = 0x2580;
break;
case PPC_IRQ_CPM_TIMER1:
Offset = 0x2590;
break;
case PPC_IRQ_CPM_PC14:
Offset = 0x25a0;
break;
case PPC_IRQ_CPM_SCC4:
Offset = 0x25b0;
break;
case PPC_IRQ_CPM_SCC3:
Offset = 0x25c0;
break;
case PPC_IRQ_CPM_SCC2:
Offset = 0x25d0;
break;
case PPC_IRQ_CPM_SCC1:
Offset = 0x25e0;
break;
case PPC_IRQ_CPM_PC15:
Offset = 0x25f0;
break;
#endif
}
Top += Offset;
return Top;
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,809 @@
/* cpu_asm.s 1.1 - 95/12/04
*
* This file contains the assembly code for the PowerPC implementation
* of RTEMS.
*
* Author: Andrew Bray <andy@i-cubed.co.uk>
*
* COPYRIGHT (c) 1995 by i-cubed ltd.
*
* To anyone who acknowledges that this file is provided "AS IS"
* without any express or implied warranty:
* permission to use, copy, modify, and distribute this file
* for any purpose is hereby granted without fee, provided that
* the above copyright notice and this notice appears in all
* copies, and that the name of i-cubed limited not be used in
* advertising or publicity pertaining to distribution of the
* software without specific, written prior permission.
* i-cubed limited makes no representations about the suitability
* of this software for any purpose.
*
* Derived from c/src/exec/cpu/no_cpu/cpu_asm.c:
*
* COPYRIGHT (c) 1989-1997.
* On-Line Applications Research Corporation (OAR).
* Copyright assigned to U.S. Government, 1994.
*
* The license and distribution terms for this file may in
* the file LICENSE in this distribution or at
* http://www.OARcorp.com/rtems/license.html.
*
* $Id$
*/
#include <asm.h>
/*
* Offsets for various Contexts
*/
.set GP_1, 0
.set GP_2, (GP_1 + 4)
.set GP_13, (GP_2 + 4)
.set GP_14, (GP_13 + 4)
.set GP_15, (GP_14 + 4)
.set GP_16, (GP_15 + 4)
.set GP_17, (GP_16 + 4)
.set GP_18, (GP_17 + 4)
.set GP_19, (GP_18 + 4)
.set GP_20, (GP_19 + 4)
.set GP_21, (GP_20 + 4)
.set GP_22, (GP_21 + 4)
.set GP_23, (GP_22 + 4)
.set GP_24, (GP_23 + 4)
.set GP_25, (GP_24 + 4)
.set GP_26, (GP_25 + 4)
.set GP_27, (GP_26 + 4)
.set GP_28, (GP_27 + 4)
.set GP_29, (GP_28 + 4)
.set GP_30, (GP_29 + 4)
.set GP_31, (GP_30 + 4)
.set GP_CR, (GP_31 + 4)
.set GP_PC, (GP_CR + 4)
.set GP_MSR, (GP_PC + 4)
#if (PPC_HAS_DOUBLE == 1)
.set FP_0, 0
.set FP_1, (FP_0 + 8)
.set FP_2, (FP_1 + 8)
.set FP_3, (FP_2 + 8)
.set FP_4, (FP_3 + 8)
.set FP_5, (FP_4 + 8)
.set FP_6, (FP_5 + 8)
.set FP_7, (FP_6 + 8)
.set FP_8, (FP_7 + 8)
.set FP_9, (FP_8 + 8)
.set FP_10, (FP_9 + 8)
.set FP_11, (FP_10 + 8)
.set FP_12, (FP_11 + 8)
.set FP_13, (FP_12 + 8)
.set FP_14, (FP_13 + 8)
.set FP_15, (FP_14 + 8)
.set FP_16, (FP_15 + 8)
.set FP_17, (FP_16 + 8)
.set FP_18, (FP_17 + 8)
.set FP_19, (FP_18 + 8)
.set FP_20, (FP_19 + 8)
.set FP_21, (FP_20 + 8)
.set FP_22, (FP_21 + 8)
.set FP_23, (FP_22 + 8)
.set FP_24, (FP_23 + 8)
.set FP_25, (FP_24 + 8)
.set FP_26, (FP_25 + 8)
.set FP_27, (FP_26 + 8)
.set FP_28, (FP_27 + 8)
.set FP_29, (FP_28 + 8)
.set FP_30, (FP_29 + 8)
.set FP_31, (FP_30 + 8)
.set FP_FPSCR, (FP_31 + 8)
#else
.set FP_0, 0
.set FP_1, (FP_0 + 4)
.set FP_2, (FP_1 + 4)
.set FP_3, (FP_2 + 4)
.set FP_4, (FP_3 + 4)
.set FP_5, (FP_4 + 4)
.set FP_6, (FP_5 + 4)
.set FP_7, (FP_6 + 4)
.set FP_8, (FP_7 + 4)
.set FP_9, (FP_8 + 4)
.set FP_10, (FP_9 + 4)
.set FP_11, (FP_10 + 4)
.set FP_12, (FP_11 + 4)
.set FP_13, (FP_12 + 4)
.set FP_14, (FP_13 + 4)
.set FP_15, (FP_14 + 4)
.set FP_16, (FP_15 + 4)
.set FP_17, (FP_16 + 4)
.set FP_18, (FP_17 + 4)
.set FP_19, (FP_18 + 4)
.set FP_20, (FP_19 + 4)
.set FP_21, (FP_20 + 4)
.set FP_22, (FP_21 + 4)
.set FP_23, (FP_22 + 4)
.set FP_24, (FP_23 + 4)
.set FP_25, (FP_24 + 4)
.set FP_26, (FP_25 + 4)
.set FP_27, (FP_26 + 4)
.set FP_28, (FP_27 + 4)
.set FP_29, (FP_28 + 4)
.set FP_30, (FP_29 + 4)
.set FP_31, (FP_30 + 4)
.set FP_FPSCR, (FP_31 + 4)
#endif
.set IP_LINK, 0
#if (PPC_ABI == PPC_ABI_POWEROPEN || PPC_ABI == PPC_ABI_GCC27)
.set IP_0, (IP_LINK + 56)
#else
.set IP_0, (IP_LINK + 8)
#endif
.set IP_2, (IP_0 + 4)
.set IP_3, (IP_2 + 4)
.set IP_4, (IP_3 + 4)
.set IP_5, (IP_4 + 4)
.set IP_6, (IP_5 + 4)
.set IP_7, (IP_6 + 4)
.set IP_8, (IP_7 + 4)
.set IP_9, (IP_8 + 4)
.set IP_10, (IP_9 + 4)
.set IP_11, (IP_10 + 4)
.set IP_12, (IP_11 + 4)
.set IP_13, (IP_12 + 4)
.set IP_28, (IP_13 + 4)
.set IP_29, (IP_28 + 4)
.set IP_30, (IP_29 + 4)
.set IP_31, (IP_30 + 4)
.set IP_CR, (IP_31 + 4)
.set IP_CTR, (IP_CR + 4)
.set IP_XER, (IP_CTR + 4)
.set IP_LR, (IP_XER + 4)
.set IP_PC, (IP_LR + 4)
.set IP_MSR, (IP_PC + 4)
.set IP_END, (IP_MSR + 16)
/* _CPU_IRQ_info offsets */
/* These must be in this order */
.set Nest_level, 0
.set Disable_level, 4
.set Vector_table, 8
.set Stack, 12
#if (PPC_ABI == PPC_ABI_POWEROPEN)
.set Dispatch_r2, 16
.set Switch_necessary, 20
#else
.set Default_r2, 16
#if (PPC_ABI != PPC_ABI_GCC27)
.set Default_r13, 20
.set Switch_necessary, 24
#else
.set Switch_necessary, 20
#endif
#endif
.set Signal, Switch_necessary + 4
.set msr_initial, Signal + 4
BEGIN_CODE
/*
* _CPU_Context_save_fp_context
*
* This routine is responsible for saving the FP context
* at *fp_context_ptr. If the point to load the FP context
* from is changed then the pointer is modified by this routine.
*
* Sometimes a macro implementation of this is in cpu.h which dereferences
* the ** and a similarly named routine in this file is passed something
* like a (Context_Control_fp *). The general rule on making this decision
* is to avoid writing assembly language.
*/
ALIGN (PPC_CACHE_ALIGNMENT, PPC_CACHE_ALIGN_POWER)
PUBLIC_PROC (_CPU_Context_save_fp)
PROC (_CPU_Context_save_fp):
#if (PPC_HAS_FPU == 1)
lwz r3, 0(r3)
#if (PPC_HAS_DOUBLE == 1)
stfd f0, FP_0(r3)
stfd f1, FP_1(r3)
stfd f2, FP_2(r3)
stfd f3, FP_3(r3)
stfd f4, FP_4(r3)
stfd f5, FP_5(r3)
stfd f6, FP_6(r3)
stfd f7, FP_7(r3)
stfd f8, FP_8(r3)
stfd f9, FP_9(r3)
stfd f10, FP_10(r3)
stfd f11, FP_11(r3)
stfd f12, FP_12(r3)
stfd f13, FP_13(r3)
stfd f14, FP_14(r3)
stfd f15, FP_15(r3)
stfd f16, FP_16(r3)
stfd f17, FP_17(r3)
stfd f18, FP_18(r3)
stfd f19, FP_19(r3)
stfd f20, FP_20(r3)
stfd f21, FP_21(r3)
stfd f22, FP_22(r3)
stfd f23, FP_23(r3)
stfd f24, FP_24(r3)
stfd f25, FP_25(r3)
stfd f26, FP_26(r3)
stfd f27, FP_27(r3)
stfd f28, FP_28(r3)
stfd f29, FP_29(r3)
stfd f30, FP_30(r3)
stfd f31, FP_31(r3)
mffs f2
stfd f2, FP_FPSCR(r3)
#else
stfs f0, FP_0(r3)
stfs f1, FP_1(r3)
stfs f2, FP_2(r3)
stfs f3, FP_3(r3)
stfs f4, FP_4(r3)
stfs f5, FP_5(r3)
stfs f6, FP_6(r3)
stfs f7, FP_7(r3)
stfs f8, FP_8(r3)
stfs f9, FP_9(r3)
stfs f10, FP_10(r3)
stfs f11, FP_11(r3)
stfs f12, FP_12(r3)
stfs f13, FP_13(r3)
stfs f14, FP_14(r3)
stfs f15, FP_15(r3)
stfs f16, FP_16(r3)
stfs f17, FP_17(r3)
stfs f18, FP_18(r3)
stfs f19, FP_19(r3)
stfs f20, FP_20(r3)
stfs f21, FP_21(r3)
stfs f22, FP_22(r3)
stfs f23, FP_23(r3)
stfs f24, FP_24(r3)
stfs f25, FP_25(r3)
stfs f26, FP_26(r3)
stfs f27, FP_27(r3)
stfs f28, FP_28(r3)
stfs f29, FP_29(r3)
stfs f30, FP_30(r3)
stfs f31, FP_31(r3)
mffs f2
stfs f2, FP_FPSCR(r3)
#endif
#endif
blr
/*
* _CPU_Context_restore_fp_context
*
* This routine is responsible for restoring the FP context
* at *fp_context_ptr. If the point to load the FP context
* from is changed then the pointer is modified by this routine.
*
* Sometimes a macro implementation of this is in cpu.h which dereferences
* the ** and a similarly named routine in this file is passed something
* like a (Context_Control_fp *). The general rule on making this decision
* is to avoid writing assembly language.
*/
ALIGN (PPC_CACHE_ALIGNMENT, PPC_CACHE_ALIGN_POWER)
PUBLIC_PROC (_CPU_Context_restore_fp)
PROC (_CPU_Context_restore_fp):
#if (PPC_HAS_FPU == 1)
lwz r3, 0(r3)
#if (PPC_HAS_DOUBLE == 1)
lfd f2, FP_FPSCR(r3)
mtfsf 255, f2
lfd f0, FP_0(r3)
lfd f1, FP_1(r3)
lfd f2, FP_2(r3)
lfd f3, FP_3(r3)
lfd f4, FP_4(r3)
lfd f5, FP_5(r3)
lfd f6, FP_6(r3)
lfd f7, FP_7(r3)
lfd f8, FP_8(r3)
lfd f9, FP_9(r3)
lfd f10, FP_10(r3)
lfd f11, FP_11(r3)
lfd f12, FP_12(r3)
lfd f13, FP_13(r3)
lfd f14, FP_14(r3)
lfd f15, FP_15(r3)
lfd f16, FP_16(r3)
lfd f17, FP_17(r3)
lfd f18, FP_18(r3)
lfd f19, FP_19(r3)
lfd f20, FP_20(r3)
lfd f21, FP_21(r3)
lfd f22, FP_22(r3)
lfd f23, FP_23(r3)
lfd f24, FP_24(r3)
lfd f25, FP_25(r3)
lfd f26, FP_26(r3)
lfd f27, FP_27(r3)
lfd f28, FP_28(r3)
lfd f29, FP_29(r3)
lfd f30, FP_30(r3)
lfd f31, FP_31(r3)
#else
lfs f2, FP_FPSCR(r3)
mtfsf 255, f2
lfs f0, FP_0(r3)
lfs f1, FP_1(r3)
lfs f2, FP_2(r3)
lfs f3, FP_3(r3)
lfs f4, FP_4(r3)
lfs f5, FP_5(r3)
lfs f6, FP_6(r3)
lfs f7, FP_7(r3)
lfs f8, FP_8(r3)
lfs f9, FP_9(r3)
lfs f10, FP_10(r3)
lfs f11, FP_11(r3)
lfs f12, FP_12(r3)
lfs f13, FP_13(r3)
lfs f14, FP_14(r3)
lfs f15, FP_15(r3)
lfs f16, FP_16(r3)
lfs f17, FP_17(r3)
lfs f18, FP_18(r3)
lfs f19, FP_19(r3)
lfs f20, FP_20(r3)
lfs f21, FP_21(r3)
lfs f22, FP_22(r3)
lfs f23, FP_23(r3)
lfs f24, FP_24(r3)
lfs f25, FP_25(r3)
lfs f26, FP_26(r3)
lfs f27, FP_27(r3)
lfs f28, FP_28(r3)
lfs f29, FP_29(r3)
lfs f30, FP_30(r3)
lfs f31, FP_31(r3)
#endif
#endif
blr
/* _CPU_Context_switch
*
* This routine performs a normal non-FP context switch.
*/
ALIGN (PPC_CACHE_ALIGNMENT, PPC_CACHE_ALIGN_POWER)
PUBLIC_PROC (_CPU_Context_switch)
PROC (_CPU_Context_switch):
sync
isync
#if (PPC_CACHE_ALIGNMENT == 4) /* No cache */
stw r1, GP_1(r3)
lwz r1, GP_1(r4)
stw r2, GP_2(r3)
lwz r2, GP_2(r4)
#if (PPC_USE_MULTIPLE == 1)
stmw r13, GP_13(r3)
lmw r13, GP_13(r4)
#else
stw r13, GP_13(r3)
lwz r13, GP_13(r4)
stw r14, GP_14(r3)
lwz r14, GP_14(r4)
stw r15, GP_15(r3)
lwz r15, GP_15(r4)
stw r16, GP_16(r3)
lwz r16, GP_16(r4)
stw r17, GP_17(r3)
lwz r17, GP_17(r4)
stw r18, GP_18(r3)
lwz r18, GP_18(r4)
stw r19, GP_19(r3)
lwz r19, GP_19(r4)
stw r20, GP_20(r3)
lwz r20, GP_20(r4)
stw r21, GP_21(r3)
lwz r21, GP_21(r4)
stw r22, GP_22(r3)
lwz r22, GP_22(r4)
stw r23, GP_23(r3)
lwz r23, GP_23(r4)
stw r24, GP_24(r3)
lwz r24, GP_24(r4)
stw r25, GP_25(r3)
lwz r25, GP_25(r4)
stw r26, GP_26(r3)
lwz r26, GP_26(r4)
stw r27, GP_27(r3)
lwz r27, GP_27(r4)
stw r28, GP_28(r3)
lwz r28, GP_28(r4)
stw r29, GP_29(r3)
lwz r29, GP_29(r4)
stw r30, GP_30(r3)
lwz r30, GP_30(r4)
stw r31, GP_31(r3)
lwz r31, GP_31(r4)
#endif
mfcr r5
stw r5, GP_CR(r3)
lwz r5, GP_CR(r4)
mflr r6
mtcrf 255, r5
stw r6, GP_PC(r3)
lwz r6, GP_PC(r4)
mfmsr r7
mtlr r6
stw r7, GP_MSR(r3)
lwz r7, GP_MSR(r4)
mtmsr r7
#endif
#if (PPC_CACHE_ALIGNMENT == 16)
/* This assumes that all the registers are in the given order */
li r5, 16
addi r3,r3,-4
#if ( PPC_USE_DATA_CACHE )
dcbz r5, r3
#endif
stw r1, GP_1+4(r3)
stw r2, GP_2+4(r3)
#if (PPC_USE_MULTIPLE == 1)
addi r3, r3, GP_14+4
#if ( PPC_USE_DATA_CACHE )
dcbz r5, r3
#endif
addi r3, r3, GP_18-GP_14
#if ( PPC_USE_DATA_CACHE )
dcbz r5, r3
#endif
addi r3, r3, GP_22-GP_18
#if ( PPC_USE_DATA_CACHE )
dcbz r5, r3
#endif
addi r3, r3, GP_26-GP_22
#if ( PPC_USE_DATA_CACHE )
dcbz r5, r3
#endif
stmw r13, GP_13-GP_26(r3)
#else
stw r13, GP_13+4(r3)
stwu r14, GP_14+4(r3)
#if ( PPC_USE_DATA_CACHE )
dcbz r5, r3
#endif
stw r15, GP_15-GP_14(r3)
stw r16, GP_16-GP_14(r3)
stw r17, GP_17-GP_14(r3)
stwu r18, GP_18-GP_14(r3)
#if ( PPC_USE_DATA_CACHE )
dcbz r5, r3
#endif
stw r19, GP_19-GP_18(r3)
stw r20, GP_20-GP_18(r3)
stw r21, GP_21-GP_18(r3)
stwu r22, GP_22-GP_18(r3)
#if ( PPC_USE_DATA_CACHE )
dcbz r5, r3
#endif
stw r23, GP_23-GP_22(r3)
stw r24, GP_24-GP_22(r3)
stw r25, GP_25-GP_22(r3)
stwu r26, GP_26-GP_22(r3)
#if ( PPC_USE_DATA_CACHE )
dcbz r5, r3
#endif
stw r27, GP_27-GP_26(r3)
stw r28, GP_28-GP_26(r3)
stw r29, GP_29-GP_26(r3)
stw r30, GP_30-GP_26(r3)
stw r31, GP_31-GP_26(r3)
#endif
#if ( PPC_USE_DATA_CACHE )
dcbt r0, r4
#endif
mfcr r6
stw r6, GP_CR-GP_26(r3)
mflr r7
stw r7, GP_PC-GP_26(r3)
mfmsr r8
stw r8, GP_MSR-GP_26(r3)
#if ( PPC_USE_DATA_CACHE )
dcbt r5, r4
#endif
lwz r1, GP_1(r4)
lwz r2, GP_2(r4)
#if (PPC_USE_MULTIPLE == 1)
addi r4, r4, GP_15
#if ( PPC_USE_DATA_CACHE )
dcbt r5, r4
#endif
addi r4, r4, GP_19-GP_15
#if ( PPC_USE_DATA_CACHE )
dcbt r5, r4
#endif
addi r4, r4, GP_23-GP_19
#if ( PPC_USE_DATA_CACHE )
dcbt r5, r4
#endif
addi r4, r4, GP_27-GP_23
#if ( PPC_USE_DATA_CACHE )
dcbt r5, r4
#endif
lmw r13, GP_13-GP_27(r4)
#else
lwz r13, GP_13(r4)
lwz r14, GP_14(r4)
lwzu r15, GP_15(r4)
#if ( PPC_USE_DATA_CACHE )
dcbt r5, r4
#endif
lwz r16, GP_16-GP_15(r4)
lwz r17, GP_17-GP_15(r4)
lwz r18, GP_18-GP_15(r4)
lwzu r19, GP_19-GP_15(r4)
#if ( PPC_USE_DATA_CACHE )
dcbt r5, r4
#endif
lwz r20, GP_20-GP_19(r4)
lwz r21, GP_21-GP_19(r4)
lwz r22, GP_22-GP_19(r4)
lwzu r23, GP_23-GP_19(r4)
#if ( PPC_USE_DATA_CACHE )
dcbt r5, r4
#endif
lwz r24, GP_24-GP_23(r4)
lwz r25, GP_25-GP_23(r4)
lwz r26, GP_26-GP_23(r4)
lwzu r27, GP_27-GP_23(r4)
#if ( PPC_USE_DATA_CACHE )
dcbt r5, r4
#endif
lwz r28, GP_28-GP_27(r4)
lwz r29, GP_29-GP_27(r4)
lwz r30, GP_30-GP_27(r4)
lwz r31, GP_31-GP_27(r4)
#endif
lwz r6, GP_CR-GP_27(r4)
lwz r7, GP_PC-GP_27(r4)
lwz r8, GP_MSR-GP_27(r4)
mtcrf 255, r6
mtlr r7
mtmsr r8
#endif
#if (PPC_CACHE_ALIGNMENT == 32)
/* This assumes that all the registers are in the given order */
li r5, 32
addi r3,r3,-4
#if ( PPC_USE_DATA_CACHE )
dcbz r5, r3
#endif
stw r1, GP_1+4(r3)
stw r2, GP_2+4(r3)
#if (PPC_USE_MULTIPLE == 1)
addi r3, r3, GP_18+4
#if ( PPC_USE_DATA_CACHE )
dcbz r5, r3
#endif
stmw r13, GP_13-GP_18(r3)
#else
stw r13, GP_13+4(r3)
stw r14, GP_14+4(r3)
stw r15, GP_15+4(r3)
stw r16, GP_16+4(r3)
stw r17, GP_17+4(r3)
stwu r18, GP_18+4(r3)
#if ( PPC_USE_DATA_CACHE )
dcbz r5, r3
#endif
stw r19, GP_19-GP_18(r3)
stw r20, GP_20-GP_18(r3)
stw r21, GP_21-GP_18(r3)
stw r22, GP_22-GP_18(r3)
stw r23, GP_23-GP_18(r3)
stw r24, GP_24-GP_18(r3)
stw r25, GP_25-GP_18(r3)
stw r26, GP_26-GP_18(r3)
stw r27, GP_27-GP_18(r3)
stw r28, GP_28-GP_18(r3)
stw r29, GP_29-GP_18(r3)
stw r30, GP_30-GP_18(r3)
stw r31, GP_31-GP_18(r3)
#endif
#if ( PPC_USE_DATA_CACHE )
dcbt r0, r4
#endif
mfcr r6
stw r6, GP_CR-GP_18(r3)
mflr r7
stw r7, GP_PC-GP_18(r3)
mfmsr r8
stw r8, GP_MSR-GP_18(r3)
#if ( PPC_USE_DATA_CACHE )
dcbt r5, r4
#endif
lwz r1, GP_1(r4)
lwz r2, GP_2(r4)
#if (PPC_USE_MULTIPLE == 1)
addi r4, r4, GP_19
#if ( PPC_USE_DATA_CACHE )
dcbt r5, r4
#endif
lmw r13, GP_13-GP_19(r4)
#else
lwz r13, GP_13(r4)
lwz r14, GP_14(r4)
lwz r15, GP_15(r4)
lwz r16, GP_16(r4)
lwz r17, GP_17(r4)
lwz r18, GP_18(r4)
lwzu r19, GP_19(r4)
#if ( PPC_USE_DATA_CACHE )
dcbt r5, r4
#endif
lwz r20, GP_20-GP_19(r4)
lwz r21, GP_21-GP_19(r4)
lwz r22, GP_22-GP_19(r4)
lwz r23, GP_23-GP_19(r4)
lwz r24, GP_24-GP_19(r4)
lwz r25, GP_25-GP_19(r4)
lwz r26, GP_26-GP_19(r4)
lwz r27, GP_27-GP_19(r4)
lwz r28, GP_28-GP_19(r4)
lwz r29, GP_29-GP_19(r4)
lwz r30, GP_30-GP_19(r4)
lwz r31, GP_31-GP_19(r4)
#endif
lwz r6, GP_CR-GP_19(r4)
lwz r7, GP_PC-GP_19(r4)
lwz r8, GP_MSR-GP_19(r4)
mtcrf 255, r6
mtlr r7
mtmsr r8
#endif
blr
/*
* _CPU_Context_restore
*
* This routine is generallu used only to restart self in an
* efficient manner. It may simply be a label in _CPU_Context_switch.
*
* NOTE: May be unnecessary to reload some registers.
*/
/*
* ACB: Don't worry about cache optimisation here - this is not THAT critical.
*/
ALIGN (PPC_CACHE_ALIGNMENT, PPC_CACHE_ALIGN_POWER)
PUBLIC_PROC (_CPU_Context_restore)
PROC (_CPU_Context_restore):
lwz r5, GP_CR(r3)
lwz r6, GP_PC(r3)
lwz r7, GP_MSR(r3)
mtcrf 255, r5
mtlr r6
mtmsr r7
lwz r1, GP_1(r3)
lwz r2, GP_2(r3)
#if (PPC_USE_MULTIPLE == 1)
lmw r13, GP_13(r3)
#else
lwz r13, GP_13(r3)
lwz r14, GP_14(r3)
lwz r15, GP_15(r3)
lwz r16, GP_16(r3)
lwz r17, GP_17(r3)
lwz r18, GP_18(r3)
lwz r19, GP_19(r3)
lwz r20, GP_20(r3)
lwz r21, GP_21(r3)
lwz r22, GP_22(r3)
lwz r23, GP_23(r3)
lwz r24, GP_24(r3)
lwz r25, GP_25(r3)
lwz r26, GP_26(r3)
lwz r27, GP_27(r3)
lwz r28, GP_28(r3)
lwz r29, GP_29(r3)
lwz r30, GP_30(r3)
lwz r31, GP_31(r3)
#endif
blr
/* Individual interrupt prologues look like this:
* #if (PPC_ABI == PPC_ABI_POWEROPEN || PPC_ABI == PPC_ABI_GCC27)
* #if (PPC_HAS_FPU)
* stwu r1, -(20*4 + 18*8 + IP_END)(r1)
* #else
* stwu r1, -(20*4 + IP_END)(r1)
* #endif
* #else
* stwu r1, -(IP_END)(r1)
* #endif
* stw r0, IP_0(r1)
*
* li r0, vectornum
* b PROC (_ISR_Handler{,C})
*/
/* void __ISR_Handler()
*
* This routine provides the RTEMS interrupt management.
* The vector number is in r0. R0 has already been stacked.
*
*/
ALIGN (PPC_CACHE_ALIGNMENT, PPC_CACHE_ALIGN_POWER)
PUBLIC_PROC (_ISR_Handler)
PROC (_ISR_Handler):
#define LABEL(x) x
/* XXX ??
#define MTSAVE(x) mtspr sprg0, x
#define MFSAVE(x) mfspr x, sprg0
*/
#define MTPC(x) mtspr srr0, x
#define MFPC(x) mfspr x, srr0
#define MTMSR(x) mtspr srr1, x
#define MFMSR(x) mfspr x, srr1
#include "irq_stub.S"
rfi
#if (PPC_HAS_RFCI == 1)
/* void __ISR_HandlerC()
*
* This routine provides the RTEMS interrupt management.
* For critical interrupts
*
*/
ALIGN (PPC_CACHE_ALIGNMENT, PPC_CACHE_ALIGN_POWER)
PUBLIC_PROC (_ISR_HandlerC)
PROC (_ISR_HandlerC):
#undef LABEL
#undef MTSAVE
#undef MFSAVE
#undef MTPC
#undef MFPC
#undef MTMSR
#undef MFMSR
#define LABEL(x) x##_C
/* XXX??
#define MTSAVE(x) mtspr sprg1, x
#define MFSAVE(x) mfspr x, sprg1
*/
#define MTPC(x) mtspr srr2, x
#define MFPC(x) mfspr x, srr2
#define MTMSR(x) mtspr srr3, x
#define MFMSR(x) mfspr x, srr3
#include "irq_stub.S"
rfci
#endif
/* PowerOpen descriptors for indirect function calls.
*/
#if (PPC_ABI == PPC_ABI_POWEROPEN)
DESCRIPTOR (_CPU_Context_save_fp)
DESCRIPTOR (_CPU_Context_restore_fp)
DESCRIPTOR (_CPU_Context_switch)
DESCRIPTOR (_CPU_Context_restore)
DESCRIPTOR (_ISR_Handler)
#if (PPC_HAS_RFCI == 1)
DESCRIPTOR (_ISR_HandlerC)
#endif
#endif

View File

@@ -0,0 +1,268 @@
/*
* This file contains the interrupt handler assembly code for the PowerPC
* implementation of RTEMS. It is #included from cpu_asm.s.
*
* Author: Andrew Bray <andy@i-cubed.co.uk>
*
* COPYRIGHT (c) 1995 by i-cubed ltd.
*
* To anyone who acknowledges that this file is provided "AS IS"
* without any express or implied warranty:
* permission to use, copy, modify, and distribute this file
* for any purpose is hereby granted without fee, provided that
* the above copyright notice and this notice appears in all
* copies, and that the name of i-cubed limited not be used in
* advertising or publicity pertaining to distribution of the
* software without specific, written prior permission.
* i-cubed limited makes no representations about the suitability
* of this software for any purpose.
*
* $Id$
*/
/* void __ISR_Handler()
*
* This routine provides the RTEMS interrupt management.
* The vector number is in r0. R0 has already been stacked.
*
*/
PUBLIC_VAR (_CPU_IRQ_info )
/* Finish off the interrupt frame */
stw r2, IP_2(r1)
stw r3, IP_3(r1)
stw r4, IP_4(r1)
stw r5, IP_5(r1)
stw r6, IP_6(r1)
stw r7, IP_7(r1)
stw r8, IP_8(r1)
stw r9, IP_9(r1)
stw r10, IP_10(r1)
stw r11, IP_11(r1)
stw r12, IP_12(r1)
stw r13, IP_13(r1)
stmw r28, IP_28(r1)
mfcr r5
mfctr r6
mfxer r7
mflr r8
MFPC (r9)
MFMSR (r10)
/* Establish addressing */
#if (PPC_USE_SPRG)
mfspr r11, sprg3
#else
lis r11,_CPU_IRQ_info@ha
addi r11,r11,_CPU_IRQ_info@l
#endif
dcbt r0, r11
stw r5, IP_CR(r1)
stw r6, IP_CTR(r1)
stw r7, IP_XER(r1)
stw r8, IP_LR(r1)
stw r9, IP_PC(r1)
stw r10, IP_MSR(r1)
lwz r30, Vector_table(r11)
slwi r4,r0,2
lwz r28, Nest_level(r11)
add r4, r4, r30
lwz r30, 0(r28)
mr r3, r0
lwz r31, Stack(r11)
/*
* #if ( CPU_HAS_SOFTWARE_INTERRUPT_STACK == TRUE )
* if ( _ISR_Nest_level == 0 )
* switch to software interrupt stack
* #endif
*/
/* Switch stacks, here we must prevent ALL interrupts */
#if (PPC_USE_SPRG)
mfmsr r5
mfspr r6, sprg2
#else
lwz r6,msr_initial(r11)
lis r5,~PPC_MSR_DISABLE_MASK@ha
ori r5,r5,~PPC_MSR_DISABLE_MASK@l
and r6,r6,r5
mfmsr r5
#endif
mtmsr r6
cmpwi r30, 0
lwz r29, Disable_level(r11)
subf r31,r1,r31
bne LABEL (nested)
stwux r1,r1,r31
LABEL (nested):
/*
* _ISR_Nest_level++;
*/
lwz r31, 0(r29)
addi r30,r30,1
stw r30,0(r28)
/* From here on out, interrupts can be re-enabled. RTEMS
* convention says not.
*/
lwz r4,0(r4)
/*
* _Thread_Dispatch_disable_level++;
*/
addi r31,r31,1
stw r31, 0(r29)
/* SCE 980217
*
* We need address translation ON when we call our ISR routine
mtmsr r5
*/
/*
* (*_ISR_Vector_table[ vector ])( vector );
*/
#if (PPC_ABI == PPC_ABI_POWEROPEN)
lwz r6,0(r4)
lwz r2,4(r4)
mtlr r6
lwz r11,8(r4)
#endif
#if (PPC_ABI == PPC_ABI_GCC27)
lwz r2, Default_r2(r11)
mtlr r4
#lwz r2, 0(r2)
#endif
#if (PPC_ABI == PPC_ABI_SVR4 || PPC_ABI == PPC_ABI_EABI)
mtlr r4
lwz r2, Default_r2(r11)
lwz r13, Default_r13(r11)
#lwz r2, 0(r2)
#lwz r13, 0(r13)
#endif
mr r4,r1
blrl
/* NOP marker for debuggers */
or r6,r6,r6
/* We must re-disable the interrupts */
#if (PPC_USE_SPRG)
mfspr r11, sprg3
mfspr r0, sprg2
#else
lis r11,_CPU_IRQ_info@ha
addi r11,r11,_CPU_IRQ_info@l
lwz r0,msr_initial(r11)
lis r30,~PPC_MSR_DISABLE_MASK@ha
ori r30,r30,~PPC_MSR_DISABLE_MASK@l
and r0,r0,r30
#endif
mtmsr r0
lwz r30, 0(r28)
lwz r31, 0(r29)
/*
* if (--Thread_Dispatch_disable,--_ISR_Nest_level)
* goto easy_exit;
*/
addi r30, r30, -1
cmpwi r30, 0
addi r31, r31, -1
stw r30, 0(r28)
stw r31, 0(r29)
bne LABEL (easy_exit)
cmpwi r31, 0
lwz r30, Switch_necessary(r11)
/*
* #if ( CPU_HAS_SOFTWARE_INTERRUPT_STACK == TRUE )
* restore stack
* #endif
*/
lwz r1,0(r1)
bne LABEL (easy_exit)
lwz r30, 0(r30)
lwz r31, Signal(r11)
/*
* if ( _Context_Switch_necessary )
* goto switch
*/
cmpwi r30, 0
lwz r28, 0(r31)
li r6,0
bne LABEL (switch)
/*
* if ( !_ISR_Signals_to_thread_executing )
* goto easy_exit
* _ISR_Signals_to_thread_executing = 0;
*/
cmpwi r28, 0
beq LABEL (easy_exit)
/*
* switch:
* call _Thread_Dispatch() or prepare to return to _ISR_Dispatch
*/
LABEL (switch):
stw r6, 0(r31)
/* Re-enable interrupts */
lwz r0, IP_MSR(r1)
#if (PPC_ABI == PPC_ABI_POWEROPEN)
lwz r2, Dispatch_r2(r11)
#else
/* R2 and R13 still hold their values from the last call */
#endif
mtmsr r0
bl SYM (_Thread_Dispatch)
/* NOP marker for debuggers */
or r6,r6,r6
/*
* prepare to get out of interrupt
*/
/* Re-disable IRQs */
#if (PPC_USE_SPRG)
mfspr r0, sprg2
#else
lis r11,_CPU_IRQ_info@ha
addi r11,r11,_CPU_IRQ_info@l
lwz r0,msr_initial(r11)
lis r5,~PPC_MSR_DISABLE_MASK@ha
ori r5,r5,~PPC_MSR_DISABLE_MASK@l
and r0,r0,r5
#endif
mtmsr r0
/*
* easy_exit:
* prepare to get out of interrupt
* return from interrupt
*/
LABEL (easy_exit):
lwz r5, IP_CR(r1)
lwz r6, IP_CTR(r1)
lwz r7, IP_XER(r1)
lwz r8, IP_LR(r1)
lwz r9, IP_PC(r1)
lwz r10, IP_MSR(r1)
mtcrf 255,r5
mtctr r6
mtxer r7
mtlr r8
MTPC (r9)
MTMSR (r10)
lwz r0, IP_0(r1)
lwz r2, IP_2(r1)
lwz r3, IP_3(r1)
lwz r4, IP_4(r1)
lwz r5, IP_5(r1)
lwz r6, IP_6(r1)
lwz r7, IP_7(r1)
lwz r8, IP_8(r1)
lwz r9, IP_9(r1)
lwz r10, IP_10(r1)
lwz r11, IP_11(r1)
lwz r12, IP_12(r1)
lwz r13, IP_13(r1)
lmw r28, IP_28(r1)
lwz r1, 0(r1)

View File

@@ -0,0 +1,61 @@
/*
* PowerPC Cache enable routines
*
* $Id$
*/
#include <rtems/system.h>
#define PPC_Get_HID0( _value ) \
do { \
_value = 0; /* to avoid warnings */ \
asm volatile( \
"mfspr %0, 0x3f0;" /* get HID0 */ \
"isync" \
: "=r" (_value) \
: "0" (_value) \
); \
} while (0)
#define PPC_Set_HID0( _value ) \
do { \
asm volatile( \
"isync;" \
"mtspr 0x3f0, %0;" /* load HID0 */ \
"isync" \
: "=r" (_value) \
: "0" (_value) \
); \
} while (0)
void powerpc_instruction_cache_enable ()
{
unsigned32 value;
/*
* Enable the instruction cache
*/
PPC_Get_HID0( value );
value |= 0x00008000; /* Set ICE bit */
PPC_Set_HID0( value );
}
void powerpc_data_cache_enable ()
{
unsigned32 value;
/*
* enable data cache
*/
PPC_Get_HID0( value );
value |= 0x00004000; /* set DCE bit */
PPC_Set_HID0( value );
}

View File

@@ -0,0 +1,132 @@
/* rtems.s
*
* This file contains the single entry point code for
* the PowerPC implementation of RTEMS.
*
* Author: Andrew Bray <andy@i-cubed.co.uk>
*
* COPYRIGHT (c) 1995 by i-cubed ltd.
*
* To anyone who acknowledges that this file is provided "AS IS"
* without any express or implied warranty:
* permission to use, copy, modify, and distribute this file
* for any purpose is hereby granted without fee, provided that
* the above copyright notice and this notice appears in all
* copies, and that the name of i-cubed limited not be used in
* advertising or publicity pertaining to distribution of the
* software without specific, written prior permission.
* i-cubed limited makes no representations about the suitability
* of this software for any purpose.
*
* Derived from c/src/exec/cpu/no_cpu/rtems.c:
*
* COPYRIGHT (c) 1989-1997.
* On-Line Applications Research Corporation (OAR).
* Copyright assigned to U.S. Government, 1994.
*
* The license and distribution terms for this file may in
* the file LICENSE in this distribution or at
* http://www.OARcorp.com/rtems/license.html.
*
* $Id$
*/
#include <asm.h>
BEGIN_CODE
/*
* RTEMS
*
* This routine jumps to the directive indicated in r11.
* This routine is used when RTEMS is linked by itself and placed
* in ROM. This routine is the first address in the ROM space for
* RTEMS. The user "calls" this address with the directive arguments
* in the normal place.
* This routine then jumps indirectly to the correct directive
* preserving the arguments. The directive should not realize
* it has been "wrapped" in this way. The table "_Entry_points"
* is used to look up the directive.
*/
ALIGN (4, 2)
PUBLIC_PROC (RTEMS)
PROC (RTEMS):
#if (PPC_ABI == PPC_ABI_POWEROPEN)
mflr r0
stw r0, 8(r1)
stwu r1, -64(r1)
/* Establish addressing */
bl base
base:
mflr r12
addi r12, r12, tabaddr - base
lwz r12, Entry_points-abase(r12)
slwi r11, r11, 2
lwzx r12, r12, r11
stw r2, 56(r1)
lwz r0, 0(r12)
mtlr r0
lwz r2, 4(r12)
lwz r11, 8(r12)
blrl
lwz r2, 56(r1)
addi r1, r1, 64
lwz r0, 8(r1)
mtlr r0
#else
mflr r0
stw r0, 4(r1)
stwu r1, -16(r1)
/* Establish addressing */
bl base
base:
mflr r12
addi r12, r12, tabaddr - base
lwz r12, Entry_points-abase(r12)
slwi r11, r11, 2
lwzx r11, r12, r11
stw r2, 8(r1)
#if (PPC_ABI != PPC_ABI_GCC27)
stw r13, 12(r1)
#endif
mtlr r11
lwz r11, irqinfo-abase(r12)
lwz r2, 0(r11)
#if (PPC_ABI != PPC_ABI_GCC27)
lwz r13, 4(r11)
#endif
blrl
lwz r2, 8(r1)
#if (PPC_ABI != PPC_ABI_GCC27)
lwz r13, 12(r1)
#endif
addi r1, r1, 16
lwz r0, 4(r1)
mtlr r0
#endif
blr
/* Addressability stuff */
tabaddr:
abase:
EXTERN_VAR (_Entry_points)
Entry_points:
EXT_SYM_REF (_Entry_points)
#if (PPC_ABI != PPC_ABI_POWEROPEN)
EXTERN_VAR (_CPU_IRQ_info)
irqinfo:
EXT_SYM_REF (_CPU_IRQ_info)
#endif
#if (PPC_ABI == PPC_ABI_POWEROPEN)
DESCRIPTOR (RTEMS)
#endif

View File

@@ -185,7 +185,7 @@ extern "C" {
#define PPC_LOW_POWER_MODE PPC_LOW_POWER_MODE_STANDARD #define PPC_LOW_POWER_MODE PPC_LOW_POWER_MODE_STANDARD
#elif defined(ppc604) #elif defined(mpc604)
/* /*
* Submitted with original port -- book checked only. * Submitted with original port -- book checked only.
*/ */
@@ -475,7 +475,7 @@ extern "C" {
#define PPC_IRQ_LAST PPC_IRQ_SYS_MGT #define PPC_IRQ_LAST PPC_IRQ_SYS_MGT
#elif defined(ppc604) #elif defined(mpc604)
#define PPC_IRQ_ADDR_BRK (PPC_STD_IRQ_LAST+1) /*0x1300- Inst. addr break */ #define PPC_IRQ_ADDR_BRK (PPC_STD_IRQ_LAST+1) /*0x1300- Inst. addr break */
#define PPC_IRQ_SYS_MGT (PPC_STD_IRQ_LAST+2) /*0x1400- System Management */ #define PPC_IRQ_SYS_MGT (PPC_STD_IRQ_LAST+2) /*0x1400- System Management */
#define PPC_IRQ_LAST PPC_IRQ_SYS_MGT #define PPC_IRQ_LAST PPC_IRQ_SYS_MGT

View File

@@ -185,7 +185,7 @@ extern "C" {
#define PPC_LOW_POWER_MODE PPC_LOW_POWER_MODE_STANDARD #define PPC_LOW_POWER_MODE PPC_LOW_POWER_MODE_STANDARD
#elif defined(ppc604) #elif defined(mpc604)
/* /*
* Submitted with original port -- book checked only. * Submitted with original port -- book checked only.
*/ */
@@ -475,7 +475,7 @@ extern "C" {
#define PPC_IRQ_LAST PPC_IRQ_SYS_MGT #define PPC_IRQ_LAST PPC_IRQ_SYS_MGT
#elif defined(ppc604) #elif defined(mpc604)
#define PPC_IRQ_ADDR_BRK (PPC_STD_IRQ_LAST+1) /*0x1300- Inst. addr break */ #define PPC_IRQ_ADDR_BRK (PPC_STD_IRQ_LAST+1) /*0x1300- Inst. addr break */
#define PPC_IRQ_SYS_MGT (PPC_STD_IRQ_LAST+2) /*0x1400- System Management */ #define PPC_IRQ_SYS_MGT (PPC_STD_IRQ_LAST+2) /*0x1400- System Management */
#define PPC_IRQ_LAST PPC_IRQ_SYS_MGT #define PPC_IRQ_LAST PPC_IRQ_SYS_MGT

View File

@@ -23,7 +23,7 @@ VPATH = @srcdir@/..
RELS = ../$(ARCH)/rtems-cpu.rel RELS = ../$(ARCH)/rtems-cpu.rel
# C source names, if any, go here -- minus the .c # C source names, if any, go here -- minus the .c
C_PIECES = cpu ppccache C_PIECES =
C_FILES = $(C_PIECES:%=%.c) C_FILES = $(C_PIECES:%=%.c)
C_O_FILES = $(C_PIECES:%=${ARCH}/%.o) C_O_FILES = $(C_PIECES:%=${ARCH}/%.o)

View File

@@ -29,7 +29,7 @@ NETWORK = $(NETWORK_$(HAS_NETWORKING)_V)
# wrapup is the one that actually builds and installs the library # wrapup is the one that actually builds and installs the library
# from the individual .rel files built in other directories # from the individual .rel files built in other directories
SUBDIRS = clock console include pci residual openpic irq vectors start \ SUBDIRS = clock console include pci residual openpic irq vectors start \
startup bootloader $(NETWORK) wrapup startup bootloader $(NETWORK) motorola wrapup
Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
cd $(top_builddir) \ cd $(top_builddir) \

View File

@@ -11,7 +11,7 @@ subdir = powerpc/mcp750/bootloader
RTEMS_ROOT = @RTEMS_ROOT@ RTEMS_ROOT = @RTEMS_ROOT@
PROJECT_ROOT = @PROJECT_ROOT@ PROJECT_ROOT = @PROJECT_ROOT@
VPATH = @srcdir@:@srcdir@/../../../shared:@srcdir@/../console VPATH = @srcdir@:@srcdir@/../../../shared:@srcdir@/../../shared/console:@srcdir@/../../shared/bootloader
# C source names, if any, go here -- minus the .c # C source names, if any, go here -- minus the .c
C_PIECES = misc pci zlib mm em86 polled_io lib C_PIECES = misc pci zlib mm em86 polled_io lib
@@ -77,7 +77,7 @@ CLOBBER_ADDITIONS += $(IMAGES)
# #
bootloader : ${OBJS} $(IMAGES) $(BINARY_LOADED) ppcboot.lds bootloader : ${OBJS} $(IMAGES) $(BINARY_LOADED) ppcboot.lds
$(LD) -o bootloader $(OBJS) --just-symbols=$(BINARY_LOADED) \ $(LD) -o bootloader $(OBJS) --just-symbols=$(BINARY_LOADED) \
-b binary $(IMAGES) -T @srcdir@/ppcboot.lds \ -b binary $(IMAGES) -T @srcdir@/../../shared/bootloader/ppcboot.lds \
-Map bootloader.map -Map bootloader.map
check_unresolved : ${OBJS} check_unresolved : ${OBJS}

View File

@@ -11,9 +11,7 @@ subdir = powerpc/mcp750/clock
RTEMS_ROOT = @RTEMS_ROOT@ RTEMS_ROOT = @RTEMS_ROOT@
PROJECT_ROOT = @PROJECT_ROOT@ PROJECT_ROOT = @PROJECT_ROOT@
VPATH = @srcdir@ VPATH = @srcdir@:@srcdir@/../../shared/clock
PGM = ${ARCH}/clock.rel
# C source names, if any, go here -- minus the .c # C source names, if any, go here -- minus the .c
C_PIECES = p_clock C_PIECES = p_clock
@@ -58,10 +56,7 @@ LDFLAGS +=
CLEAN_ADDITIONS += CLEAN_ADDITIONS +=
CLOBBER_ADDITIONS += CLOBBER_ADDITIONS +=
$(PGM): ${OBJS} all: ${ARCH} $(SRCS) $(OBJS)
$(make-rel)
all: ${ARCH} $(SRCS) $(PGM)
# the .rel file built here will be put into libbsp.a by ../wrapup/Makefile # the .rel file built here will be put into libbsp.a by ../wrapup/Makefile
install: all install: all

View File

@@ -1,5 +1,5 @@
# #
# $Id: # $Id$
# #
@SET_MAKE@ @SET_MAKE@
@@ -11,14 +11,14 @@ subdir = powerpc/mcp750/console
RTEMS_ROOT = @RTEMS_ROOT@ RTEMS_ROOT = @RTEMS_ROOT@
PROJECT_ROOT = @PROJECT_ROOT@ PROJECT_ROOT = @PROJECT_ROOT@
VPATH = @srcdir@:@srcdir@/../../../shared VPATH = @srcdir@:@srcdir@/../../shared/console:@srcdir@/../../../shared
# C source names, if any, go here -- minus the .c # C source names, if any, go here -- minus the .c
C_PIECES = polled_io uart console inch console_reserve_resources C_PIECES = polled_io uart console inch
C_FILES = $(C_PIECES:%=%.c) C_FILES = $(C_PIECES:%=%.c)
C_O_FILES = $(C_PIECES:%=${ARCH}/%.o) C_O_FILES = $(C_PIECES:%=${ARCH}/%.o)
H_FILES = $(srcdir)/consoleIo.h $(srcdir)/keyboard.h $(srcdir)/uart.h H_FILES = $(srcdir)/../../shared/console/consoleIo.h $(srcdir)/../../shared/console/keyboard.h $(srcdir)/../../shared/console/uart.h
# Assembly source names, if any, go here -- minus the .s # Assembly source names, if any, go here -- minus the .s
S_PIECES = S_PIECES =
@@ -48,6 +48,7 @@ CC_O_FILES = $(CC_PIECES:%=${ARCH}/%.o)
# #
CPPFLAGS += -DSTATIC_LOG_ALLOC CPPFLAGS += -DSTATIC_LOG_ALLOC
CFLAGS +=
# #
# Add your list of files to delete here. The config files # Add your list of files to delete here. The config files
# already know how to delete some stuff, so you may want # already know how to delete some stuff, so you may want
@@ -56,11 +57,7 @@ CPPFLAGS += -DSTATIC_LOG_ALLOC
# 'make clobber' already includes 'make clean' # 'make clobber' already includes 'make clean'
# #
preinstall: all: ${ARCH} $(SRCS) ${OBJS}
@$(mkinstalldirs) $(PROJECT_INCLUDE)/bsp
@$(INSTALL_CHANGE) -m 644 $(H_FILES) $(PROJECT_INCLUDE)/bsp
all: ${ARCH} $(SRCS) preinstall ${OBJS}
Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
cd $(top_builddir) \ cd $(top_builddir) \

View File

@@ -1,61 +0,0 @@
/*
* console.c -- console I/O package
*
* Copyright (C) 1999 Eric Valette. valette@crf.canon.fr
*
* This code is based on the pc386 BSP console.c so the following
* copyright also applies :
*
* (C) Copyright 1997 -
* - NavIST Group - Real-Time Distributed Systems and Industrial Automation
*
* http://pandora.ist.utl.pt
*
* Instituto Superior Tecnico * Lisboa * PORTUGAL
* The license and distribution terms for this file may be
* found in found in the file LICENSE in this distribution or at
* http://www.OARcorp.com/rtems/license.html.
*
* $Id$
*/
#include <stdlib.h>
#include <assert.h>
#include <stdlib.h>
#undef __assert
void __assert (const char *file, int line, const char *msg);
extern int close(int fd);
#include <bsp.h>
#include <bsp/irq.h>
#include <rtems/libio.h>
#include <termios.h>
#include <bsp/uart.h>
#include <bsp/consoleIo.h>
/* Definitions for BSPConsolePort */
#define BSP_CONSOLE_PORT_CONSOLE (-1)
#define BSP_CONSOLE_PORT_COM1 (BSP_UART_COM1)
#define BSP_CONSOLE_PORT_COM2 (BSP_UART_COM2)
/*
* Possible value for console input/output :
* BSP_CONSOLE_PORT_CONSOLE
* BSP_UART_COM1
* BSP_UART_COM2
*/
int BSPConsolePort = BSP_UART_COM1;
/* int BSPConsolePort = BSP_UART_COM2; */
int BSPBaseBaud = 115200;
void console_reserve_resources(rtems_configuration_table *conf)
{
if(BSPConsolePort != BSP_CONSOLE_PORT_CONSOLE)
{
rtems_termios_reserve_resources(conf, 1);
}
return;
}

View File

@@ -13,7 +13,13 @@ PROJECT_ROOT = @PROJECT_ROOT@
VPATH = @srcdir@ VPATH = @srcdir@
H_FILES = $(srcdir)/nvram.h $(srcdir)/bsp.h H_FILES = $(srcdir)/../../shared/include/nvram.h \
$(srcdir)/../../shared/include/bsp.h
BSP_H_FILES = $(srcdir)/../../shared/console/consoleIo.h \
$(srcdir)/../../shared/console/uart.h \
$(srcdir)/../../shared/irq/irq.h \
$(srcdir)/../../shared/motorola/motorola.h
# #
# Equate files are for including from assembly preprocessed by # Equate files are for including from assembly preprocessed by
@@ -43,7 +49,9 @@ CLOBBER_ADDITIONS +=
preinstall: preinstall:
$(mkinstalldirs) $(PROJECT_INCLUDE) $(mkinstalldirs) $(PROJECT_INCLUDE)
$(mkinstalldirs) $(PROJECT_INCLUDE)/bsp
@$(INSTALL_CHANGE) -m 644 $(H_FILES) $(PROJECT_INCLUDE) @$(INSTALL_CHANGE) -m 644 $(H_FILES) $(PROJECT_INCLUDE)
@$(INSTALL_CHANGE) -m 644 $(BSP_H_FILES) $(PROJECT_INCLUDE)/bsp
all: $(SRCS) preinstall all: $(SRCS) preinstall

View File

@@ -11,14 +11,14 @@ subdir = powerpc/mcp750/irq
RTEMS_ROOT = @RTEMS_ROOT@ RTEMS_ROOT = @RTEMS_ROOT@
PROJECT_ROOT = @PROJECT_ROOT@ PROJECT_ROOT = @PROJECT_ROOT@
VPATH = @srcdir@ VPATH = @srcdir@:@srcdir@/../../shared/irq
# C source names, if any, go here -- minus the .c # C source names, if any, go here -- minus the .c
C_PIECES = irq_init i8259 irq C_PIECES = irq_init i8259 irq
C_FILES = $(C_PIECES:%=%.c) C_FILES = $(C_PIECES:%=%.c)
C_O_FILES = $(C_PIECES:%=${ARCH}/%.o) C_O_FILES = $(C_PIECES:%=${ARCH}/%.o)
H_FILES = $(srcdir)/irq.h H_FILES = $(srcdir)/../../shared/irq/irq.h
# Assembly source names, if any, go here -- minus the .s # Assembly source names, if any, go here -- minus the .s
S_PIECES = irq_asm S_PIECES = irq_asm
@@ -61,11 +61,7 @@ LDFLAGS +=
CLEAN_ADDITIONS += CLEAN_ADDITIONS +=
CLOBBER_ADDITIONS += CLOBBER_ADDITIONS +=
preinstall: all: ${ARCH} $(SRCS) ${OBJS}
@$(mkinstalldirs) $(PROJECT_INCLUDE)/bsp
@$(INSTALL_CHANGE) -m 644 $(H_FILES) $(PROJECT_INCLUDE)/bsp
all: ${ARCH} $(SRCS) preinstall ${OBJS}
install: all install: all

View File

@@ -11,16 +11,14 @@ subdir = powerpc/mcp750/openpic
RTEMS_ROOT = @RTEMS_ROOT@ RTEMS_ROOT = @RTEMS_ROOT@
PROJECT_ROOT = @PROJECT_ROOT@ PROJECT_ROOT = @PROJECT_ROOT@
VPATH = @srcdir@ VPATH = @srcdir@:@srcdir@/../../shared/openpic
PGM = ${ARCH}/openpic.rel
# C source names, if any, go here -- minus the .c # C source names, if any, go here -- minus the .c
C_PIECES = $(OPENPIC_C_PIECES) C_PIECES = $(OPENPIC_C_PIECES)
C_FILES = $(C_PIECES:%=%.c) C_FILES = $(C_PIECES:%=%.c)
C_O_FILES = $(C_PIECES:%=${ARCH}/%.o) C_O_FILES = $(C_PIECES:%=${ARCH}/%.o)
H_FILES = $(srcdir)/openpic.h H_FILES = $(srcdir)/../../shared/openpic/openpic.h
SRCS = $(C_FILES) $(H_FILES) SRCS = $(C_FILES) $(H_FILES)
OBJS = $(C_O_FILES) OBJS = $(C_O_FILES)
@@ -60,14 +58,11 @@ LDFLAGS +=
CLEAN_ADDITIONS += CLEAN_ADDITIONS +=
CLOBBER_ADDITIONS += CLOBBER_ADDITIONS +=
$(PGM): ${OBJS}
$(make-rel)
preinstall: preinstall:
@$(mkinstalldirs) $(PROJECT_INCLUDE)/bsp @$(mkinstalldirs) $(PROJECT_INCLUDE)/bsp
@$(INSTALL_CHANGE) -m 644 $(H_FILES) $(PROJECT_INCLUDE)/bsp @$(INSTALL_CHANGE) -m 644 $(H_FILES) $(PROJECT_INCLUDE)/bsp
all: ${ARCH} $(SRCS) preinstall $(PGM) all: ${ARCH} $(SRCS) preinstall $(OBJS)
# the .rel file built here will be put into libbsp.a by ../wrapup/Makefile # the .rel file built here will be put into libbsp.a by ../wrapup/Makefile
install: all install: all

View File

@@ -11,16 +11,14 @@ subdir = powerpc/mcp750/pci
RTEMS_ROOT = @RTEMS_ROOT@ RTEMS_ROOT = @RTEMS_ROOT@
PROJECT_ROOT = @PROJECT_ROOT@ PROJECT_ROOT = @PROJECT_ROOT@
VPATH = @srcdir@ VPATH = @srcdir@:@srcdir@/../../shared/pci
PGM = ${ARCH}/pci.rel
# C source names, if any, go here -- minus the .c # C source names, if any, go here -- minus the .c
C_PIECES = $(PCI_C_PIECES) C_PIECES = pci
C_FILES = $(C_PIECES:%=%.c) C_FILES = $(C_PIECES:%=%.c)
C_O_FILES = $(C_PIECES:%=${ARCH}/%.o) C_O_FILES = $(C_PIECES:%=${ARCH}/%.o)
H_FILES = $(srcdir)/pci.h H_FILES = $(srcdir)/../../shared/pci/pci.h
SRCS = $(C_FILES) $(H_FILES) SRCS = $(C_FILES) $(H_FILES)
OBJS = $(C_O_FILES) OBJS = $(C_O_FILES)
@@ -36,8 +34,6 @@ INSTALLDIRS = $(PROJECT_INCLUDE)/bsp
$(INSTALLDIRS): $(INSTALLDIRS):
@$(mkinstalldirs) $(INSTALLDIRS) @$(mkinstalldirs) $(INSTALLDIRS)
PCI_C_PIECES = pci
# #
# (OPTIONAL) Add local stuff here using += # (OPTIONAL) Add local stuff here using +=
# #
@@ -60,14 +56,11 @@ LDFLAGS +=
CLEAN_ADDITIONS += CLEAN_ADDITIONS +=
CLOBBER_ADDITIONS += CLOBBER_ADDITIONS +=
$(PGM): ${OBJS}
$(make-rel)
preinstall: preinstall:
@$(mkinstalldirs) $(PROJECT_INCLUDE)/bsp @$(mkinstalldirs) $(PROJECT_INCLUDE)/bsp
@$(INSTALL_CHANGE) -m 644 $(H_FILES) $(PROJECT_INCLUDE)/bsp @$(INSTALL_CHANGE) -m 644 $(H_FILES) $(PROJECT_INCLUDE)/bsp
all: ${ARCH} $(SRCS) preinstall $(PGM) all: ${ARCH} $(SRCS) preinstall $(OBJS)
# the .rel file built here will be put into libbsp.a by ../wrapup/Makefile # the .rel file built here will be put into libbsp.a by ../wrapup/Makefile
install: all install: all

View File

@@ -11,16 +11,14 @@ subdir = powerpc/mcp750/residual
RTEMS_ROOT = @RTEMS_ROOT@ RTEMS_ROOT = @RTEMS_ROOT@
PROJECT_ROOT = @PROJECT_ROOT@ PROJECT_ROOT = @PROJECT_ROOT@
VPATH = @srcdir@ VPATH = @srcdir@:@srcdir@/../../shared/residual
PGM = ${ARCH}/residual.rel
# C source names, if any, go here -- minus the .c # C source names, if any, go here -- minus the .c
C_PIECES = $(RESIDUAL_C_PIECES) C_PIECES = $(RESIDUAL_C_PIECES)
C_FILES = $(C_PIECES:%=%.c) C_FILES = $(C_PIECES:%=%.c)
C_O_FILES = $(C_PIECES:%=${ARCH}/%.o) C_O_FILES = $(C_PIECES:%=${ARCH}/%.o)
H_FILES = $(srcdir)/pnp.h $(srcdir)/residual.h H_FILES = $(srcdir)/../../shared/residual/pnp.h $(srcdir)/../../shared/residual/residual.h
SRCS = $(C_FILES) $(H_FILES) SRCS = $(C_FILES) $(H_FILES)
OBJS = $(C_O_FILES) OBJS = $(C_O_FILES)
@@ -64,10 +62,7 @@ preinstall:
@$(mkinstalldirs) $(PROJECT_INCLUDE)/bsp @$(mkinstalldirs) $(PROJECT_INCLUDE)/bsp
@$(INSTALL_CHANGE) -m 644 $(H_FILES) $(PROJECT_INCLUDE)/bsp @$(INSTALL_CHANGE) -m 644 $(H_FILES) $(PROJECT_INCLUDE)/bsp
$(PGM): ${OBJS} all: ${ARCH} $(SRCS) preinstall $(OBJS)
$(make-rel)
all: ${ARCH} $(SRCS) preinstall $(PGM)
# the .rel file built here will be put into libbsp.a by ../wrapup/Makefile # the .rel file built here will be put into libbsp.a by ../wrapup/Makefile
install: all install: all

View File

@@ -11,7 +11,7 @@ subdir = powerpc/mcp750/start
RTEMS_ROOT = @RTEMS_ROOT@ RTEMS_ROOT = @RTEMS_ROOT@
PROJECT_ROOT = @PROJECT_ROOT@ PROJECT_ROOT = @PROJECT_ROOT@
VPATH = @srcdir@ VPATH = @srcdir@:@srcdir@/../../shared/start
PGM = ${ARCH}/start.o PGM = ${ARCH}/start.o

View File

@@ -11,7 +11,7 @@ subdir = powerpc/mcp750/startup
RTEMS_ROOT = @RTEMS_ROOT@ RTEMS_ROOT = @RTEMS_ROOT@
PROJECT_ROOT = @PROJECT_ROOT@ PROJECT_ROOT = @PROJECT_ROOT@
VPATH = @srcdir@:@srcdir@/../console:@srcdir@/../../../shared VPATH = @srcdir@:@srcdir@/../console:@srcdir@/../../../shared:@srcdir@/../../shared/startup
# C source names, if any, go here -- minus the .c # C source names, if any, go here -- minus the .c
C_PIECES = bootcard main bspstart bsppost bsplibc sbrk bspclean \ C_PIECES = bootcard main bspstart bsppost bsplibc sbrk bspclean \

View File

@@ -11,16 +11,14 @@ subdir = powerpc/mcp750/vectors
RTEMS_ROOT = @RTEMS_ROOT@ RTEMS_ROOT = @RTEMS_ROOT@
PROJECT_ROOT = @PROJECT_ROOT@ PROJECT_ROOT = @PROJECT_ROOT@
VPATH = @srcdir@:@srcdir@/../console: VPATH = @srcdir@:@srcdir@/../console:@srcdir@/../../shared/vectors
PGM = ${ARCH}/vectors.rel
# C source names, if any, go here -- minus the .c # C source names, if any, go here -- minus the .c
C_PIECES = vectors_init C_PIECES = vectors_init
C_FILES = $(C_PIECES:%=%.c) C_FILES = $(C_PIECES:%=%.c)
C_O_FILES = $(C_PIECES:%=${ARCH}/%.o) C_O_FILES = $(C_PIECES:%=${ARCH}/%.o)
H_FILES = $(srcdir)/vectors.h H_FILES = $(srcdir)/../../shared/vectors/vectors.h
# Assembly source names, if any, go here -- minus the .s # Assembly source names, if any, go here -- minus the .s
S_PIECES = vectors S_PIECES = vectors

View File

@@ -18,7 +18,7 @@ NETWORK_yes_V = dec21140
NETWORK = $(NETWORK_$(HAS_NETWORKING)_V) NETWORK = $(NETWORK_$(HAS_NETWORKING)_V)
BSP_PIECES = clock console irq openpic pci residual startup $(NETWORK) \ BSP_PIECES = clock console irq openpic pci residual startup $(NETWORK) \
vectors vectors motorola
GENERIC_PIECES = GENERIC_PIECES =
# bummer; have to use $foreach since % pattern subst rules only replace 1x # bummer; have to use $foreach since % pattern subst rules only replace 1x

View File

@@ -29,7 +29,7 @@ NETWORK = $(NETWORK_$(HAS_NETWORKING)_V)
# wrapup is the one that actually builds and installs the library # wrapup is the one that actually builds and installs the library
# from the individual .rel files built in other directories # from the individual .rel files built in other directories
SUBDIRS = clock console include pci residual openpic irq vectors start \ SUBDIRS = clock console include pci residual openpic irq vectors start \
startup bootloader $(NETWORK) wrapup startup bootloader $(NETWORK) motorola wrapup
Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
cd $(top_builddir) \ cd $(top_builddir) \

View File

@@ -11,7 +11,7 @@ subdir = powerpc/mcp750/bootloader
RTEMS_ROOT = @RTEMS_ROOT@ RTEMS_ROOT = @RTEMS_ROOT@
PROJECT_ROOT = @PROJECT_ROOT@ PROJECT_ROOT = @PROJECT_ROOT@
VPATH = @srcdir@:@srcdir@/../../../shared:@srcdir@/../console VPATH = @srcdir@:@srcdir@/../../../shared:@srcdir@/../../shared/console:@srcdir@/../../shared/bootloader
# C source names, if any, go here -- minus the .c # C source names, if any, go here -- minus the .c
C_PIECES = misc pci zlib mm em86 polled_io lib C_PIECES = misc pci zlib mm em86 polled_io lib
@@ -77,7 +77,7 @@ CLOBBER_ADDITIONS += $(IMAGES)
# #
bootloader : ${OBJS} $(IMAGES) $(BINARY_LOADED) ppcboot.lds bootloader : ${OBJS} $(IMAGES) $(BINARY_LOADED) ppcboot.lds
$(LD) -o bootloader $(OBJS) --just-symbols=$(BINARY_LOADED) \ $(LD) -o bootloader $(OBJS) --just-symbols=$(BINARY_LOADED) \
-b binary $(IMAGES) -T @srcdir@/ppcboot.lds \ -b binary $(IMAGES) -T @srcdir@/../../shared/bootloader/ppcboot.lds \
-Map bootloader.map -Map bootloader.map
check_unresolved : ${OBJS} check_unresolved : ${OBJS}

View File

@@ -11,9 +11,7 @@ subdir = powerpc/mcp750/clock
RTEMS_ROOT = @RTEMS_ROOT@ RTEMS_ROOT = @RTEMS_ROOT@
PROJECT_ROOT = @PROJECT_ROOT@ PROJECT_ROOT = @PROJECT_ROOT@
VPATH = @srcdir@ VPATH = @srcdir@:@srcdir@/../../shared/clock
PGM = ${ARCH}/clock.rel
# C source names, if any, go here -- minus the .c # C source names, if any, go here -- minus the .c
C_PIECES = p_clock C_PIECES = p_clock
@@ -58,10 +56,7 @@ LDFLAGS +=
CLEAN_ADDITIONS += CLEAN_ADDITIONS +=
CLOBBER_ADDITIONS += CLOBBER_ADDITIONS +=
$(PGM): ${OBJS} all: ${ARCH} $(SRCS) $(OBJS)
$(make-rel)
all: ${ARCH} $(SRCS) $(PGM)
# the .rel file built here will be put into libbsp.a by ../wrapup/Makefile # the .rel file built here will be put into libbsp.a by ../wrapup/Makefile
install: all install: all

View File

@@ -1,5 +1,5 @@
# #
# $Id: # $Id$
# #
@SET_MAKE@ @SET_MAKE@
@@ -11,14 +11,14 @@ subdir = powerpc/mcp750/console
RTEMS_ROOT = @RTEMS_ROOT@ RTEMS_ROOT = @RTEMS_ROOT@
PROJECT_ROOT = @PROJECT_ROOT@ PROJECT_ROOT = @PROJECT_ROOT@
VPATH = @srcdir@:@srcdir@/../../../shared VPATH = @srcdir@:@srcdir@/../../shared/console:@srcdir@/../../../shared
# C source names, if any, go here -- minus the .c # C source names, if any, go here -- minus the .c
C_PIECES = polled_io uart console inch console_reserve_resources C_PIECES = polled_io uart console inch
C_FILES = $(C_PIECES:%=%.c) C_FILES = $(C_PIECES:%=%.c)
C_O_FILES = $(C_PIECES:%=${ARCH}/%.o) C_O_FILES = $(C_PIECES:%=${ARCH}/%.o)
H_FILES = $(srcdir)/consoleIo.h $(srcdir)/keyboard.h $(srcdir)/uart.h H_FILES = $(srcdir)/../../shared/console/consoleIo.h $(srcdir)/../../shared/console/keyboard.h $(srcdir)/../../shared/console/uart.h
# Assembly source names, if any, go here -- minus the .s # Assembly source names, if any, go here -- minus the .s
S_PIECES = S_PIECES =
@@ -48,6 +48,7 @@ CC_O_FILES = $(CC_PIECES:%=${ARCH}/%.o)
# #
CPPFLAGS += -DSTATIC_LOG_ALLOC CPPFLAGS += -DSTATIC_LOG_ALLOC
CFLAGS +=
# #
# Add your list of files to delete here. The config files # Add your list of files to delete here. The config files
# already know how to delete some stuff, so you may want # already know how to delete some stuff, so you may want
@@ -56,11 +57,7 @@ CPPFLAGS += -DSTATIC_LOG_ALLOC
# 'make clobber' already includes 'make clean' # 'make clobber' already includes 'make clean'
# #
preinstall: all: ${ARCH} $(SRCS) ${OBJS}
@$(mkinstalldirs) $(PROJECT_INCLUDE)/bsp
@$(INSTALL_CHANGE) -m 644 $(H_FILES) $(PROJECT_INCLUDE)/bsp
all: ${ARCH} $(SRCS) preinstall ${OBJS}
Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
cd $(top_builddir) \ cd $(top_builddir) \

View File

@@ -1,382 +0,0 @@
/*
* console.c -- console I/O package
*
* Copyright (C) 1999 Eric Valette. valette@crf.canon.fr
*
* This code is based on the pc386 BSP console.c so the following
* copyright also applies :
*
* (C) Copyright 1997 -
* - NavIST Group - Real-Time Distributed Systems and Industrial Automation
*
* http://pandora.ist.utl.pt
*
* Instituto Superior Tecnico * Lisboa * PORTUGAL
* The license and distribution terms for this file may be
* found in found in the file LICENSE in this distribution or at
* http://www.OARcorp.com/rtems/license.html.
*
* $Id$
*/
#include <stdlib.h>
#include <assert.h>
#include <stdlib.h>
#undef __assert
void __assert (const char *file, int line, const char *msg);
extern int close(int fd);
#include <bsp.h>
#include <bsp/irq.h>
#include <rtems/libio.h>
#include <termios.h>
#include <bsp/uart.h>
#include <bsp/consoleIo.h>
/* Definitions for BSPConsolePort */
#define BSP_CONSOLE_PORT_CONSOLE (-1)
#define BSP_CONSOLE_PORT_COM1 (BSP_UART_COM1)
#define BSP_CONSOLE_PORT_COM2 (BSP_UART_COM2)
/*
* Possible value for console input/output :
* BSP_CONSOLE_PORT_CONSOLE
* BSP_UART_COM1
* BSP_UART_COM2
*/
extern int BSPConsolePort;
/* int BSPConsolePort = BSP_UART_COM2; */
extern int BSPBaseBaud;
/*-------------------------------------------------------------------------+
| External Prototypes
+--------------------------------------------------------------------------*/
static int conSetAttr(int minor, const struct termios *);
static void isr_on(const rtems_irq_connect_data *);
static void isr_off(const rtems_irq_connect_data *);
static int isr_is_on(const rtems_irq_connect_data *);
static rtems_irq_connect_data console_isr_data = {BSP_ISA_UART_COM1_IRQ,
BSP_uart_termios_isr_com1,
isr_on,
isr_off,
isr_is_on};
static void
isr_on(const rtems_irq_connect_data *unused)
{
return;
}
static void
isr_off(const rtems_irq_connect_data *unused)
{
return;
}
static int
isr_is_on(const rtems_irq_connect_data *irq)
{
return BSP_irq_enabled_at_i8259s(irq->name);
}
/*
void console_reserve_resources(rtems_configuration_table *conf)
{
if(BSPConsolePort != BSP_CONSOLE_PORT_CONSOLE)
{
rtems_termios_reserve_resources(conf, 1);
}
return;
}
*/
void __assert (const char *file, int line, const char *msg)
{
static char exit_msg[] = "EXECUTIVE SHUTDOWN! Any key to reboot...";
unsigned char ch;
/*
* Note we cannot call exit or printf from here,
* assert can fail inside ISR too
*/
/*
* Close console
*/
close(2);
close(1);
close(0);
printk("\nassert failed: %s: ", file);
printk("%d: ", line);
printk("%s\n\n", msg);
printk(exit_msg);
ch = debug_getc();
printk("\n\n");
rtemsReboot();
}
/*-------------------------------------------------------------------------+
| Console device driver INITIALIZE entry point.
+--------------------------------------------------------------------------+
| Initilizes the I/O console (keyboard + VGA display) driver.
+--------------------------------------------------------------------------*/
rtems_device_driver
console_initialize(rtems_device_major_number major,
rtems_device_minor_number minor,
void *arg)
{
rtems_status_code status;
/*
* The video was initialized in the start.s code and does not need
* to be reinitialized.
*/
/*
* Set up TERMIOS
*/
rtems_termios_initialize ();
/*
* Do device-specific initialization
*/
/* 9600-8-N-1 */
BSP_uart_init(BSPConsolePort, 9600, 0);
/* Set interrupt handler */
if(BSPConsolePort == BSP_UART_COM1)
{
console_isr_data.name = BSP_ISA_UART_COM1_IRQ;
console_isr_data.hdl = BSP_uart_termios_isr_com1;
}
else
{
assert(BSPConsolePort == BSP_UART_COM2);
console_isr_data.name = BSP_ISA_UART_COM2_IRQ;
console_isr_data.hdl = BSP_uart_termios_isr_com2;
}
status = BSP_install_rtems_irq_handler(&console_isr_data);
if (!status){
printk("Error installing serial console interrupt handler!\n");
rtems_fatal_error_occurred(status);
}
/*
* Register the device
*/
status = rtems_io_register_name ("/dev/console", major, 0);
if (status != RTEMS_SUCCESSFUL)
{
printk("Error registering console device!\n");
rtems_fatal_error_occurred (status);
}
if(BSPConsolePort == BSP_UART_COM1)
{
printk("Initialized console on port COM1 9600-8-N-1\n\n");
}
else
{
printk("Initialized console on port COM2 9600-8-N-1\n\n");
}
return RTEMS_SUCCESSFUL;
} /* console_initialize */
static int console_last_close(int major, int minor, void *arg)
{
BSP_remove_rtems_irq_handler (&console_isr_data);
return 0;
}
/*-------------------------------------------------------------------------+
| Console device driver OPEN entry point
+--------------------------------------------------------------------------*/
rtems_device_driver
console_open(rtems_device_major_number major,
rtems_device_minor_number minor,
void *arg)
{
rtems_status_code status;
static rtems_termios_callbacks cb =
{
NULL, /* firstOpen */
console_last_close, /* lastClose */
NULL, /* pollRead */
BSP_uart_termios_write_com1, /* write */
conSetAttr, /* setAttributes */
NULL, /* stopRemoteTx */
NULL, /* startRemoteTx */
1 /* outputUsesInterrupts */
};
if(BSPConsolePort == BSP_UART_COM2)
{
cb.write = BSP_uart_termios_write_com2;
}
status = rtems_termios_open (major, minor, arg, &cb);
if(status != RTEMS_SUCCESSFUL)
{
printk("Error openning console device\n");
return status;
}
/*
* Pass data area info down to driver
*/
BSP_uart_termios_set(BSPConsolePort,
((rtems_libio_open_close_args_t *)arg)->iop->data1);
/* Enable interrupts on channel */
BSP_uart_intr_ctrl(BSPConsolePort, BSP_UART_INTR_CTRL_TERMIOS);
return RTEMS_SUCCESSFUL;
}
/*-------------------------------------------------------------------------+
| Console device driver CLOSE entry point
+--------------------------------------------------------------------------*/
rtems_device_driver
console_close(rtems_device_major_number major,
rtems_device_minor_number minor,
void *arg)
{
rtems_device_driver res = RTEMS_SUCCESSFUL;
res = rtems_termios_close (arg);
return res;
} /* console_close */
/*-------------------------------------------------------------------------+
| Console device driver READ entry point.
+--------------------------------------------------------------------------+
| Read characters from the I/O console. We only have stdin.
+--------------------------------------------------------------------------*/
rtems_device_driver
console_read(rtems_device_major_number major,
rtems_device_minor_number minor,
void *arg)
{
return rtems_termios_read (arg);
} /* console_read */
/*-------------------------------------------------------------------------+
| Console device driver WRITE entry point.
+--------------------------------------------------------------------------+
| Write characters to the I/O console. Stderr and stdout are the same.
+--------------------------------------------------------------------------*/
rtems_device_driver
console_write(rtems_device_major_number major,
rtems_device_minor_number minor,
void * arg)
{
return rtems_termios_write (arg);
} /* console_write */
/*
* Handle ioctl request.
*/
rtems_device_driver
console_control(rtems_device_major_number major,
rtems_device_minor_number minor,
void * arg
)
{
return rtems_termios_ioctl (arg);
}
static int
conSetAttr(int minor, const struct termios *t)
{
int baud;
switch (t->c_cflag & CBAUD)
{
case B50:
baud = 50;
break;
case B75:
baud = 75;
break;
case B110:
baud = 110;
break;
case B134:
baud = 134;
break;
case B150:
baud = 150;
break;
case B200:
baud = 200;
break;
case B300:
baud = 300;
break;
case B600:
baud = 600;
break;
case B1200:
baud = 1200;
break;
case B1800:
baud = 1800;
break;
case B2400:
baud = 2400;
break;
case B4800:
baud = 4800;
break;
case B9600:
baud = 9600;
break;
case B19200:
baud = 19200;
break;
case B38400:
baud = 38400;
break;
case B57600:
baud = 57600;
break;
case B115200:
baud = 115200;
break;
default:
baud = 0;
rtems_fatal_error_occurred (RTEMS_INTERNAL_ERROR);
return 0;
}
BSP_uart_set_baud(BSPConsolePort, baud);
return 0;
}

View File

@@ -1,61 +0,0 @@
/*
* console.c -- console I/O package
*
* Copyright (C) 1999 Eric Valette. valette@crf.canon.fr
*
* This code is based on the pc386 BSP console.c so the following
* copyright also applies :
*
* (C) Copyright 1997 -
* - NavIST Group - Real-Time Distributed Systems and Industrial Automation
*
* http://pandora.ist.utl.pt
*
* Instituto Superior Tecnico * Lisboa * PORTUGAL
* The license and distribution terms for this file may be
* found in found in the file LICENSE in this distribution or at
* http://www.OARcorp.com/rtems/license.html.
*
* $Id$
*/
#include <stdlib.h>
#include <assert.h>
#include <stdlib.h>
#undef __assert
void __assert (const char *file, int line, const char *msg);
extern int close(int fd);
#include <bsp.h>
#include <bsp/irq.h>
#include <rtems/libio.h>
#include <termios.h>
#include <bsp/uart.h>
#include <bsp/consoleIo.h>
/* Definitions for BSPConsolePort */
#define BSP_CONSOLE_PORT_CONSOLE (-1)
#define BSP_CONSOLE_PORT_COM1 (BSP_UART_COM1)
#define BSP_CONSOLE_PORT_COM2 (BSP_UART_COM2)
/*
* Possible value for console input/output :
* BSP_CONSOLE_PORT_CONSOLE
* BSP_UART_COM1
* BSP_UART_COM2
*/
int BSPConsolePort = BSP_UART_COM1;
/* int BSPConsolePort = BSP_UART_COM2; */
int BSPBaseBaud = 115200;
void console_reserve_resources(rtems_configuration_table *conf)
{
if(BSPConsolePort != BSP_CONSOLE_PORT_CONSOLE)
{
rtems_termios_reserve_resources(conf, 1);
}
return;
}

View File

@@ -13,7 +13,13 @@ PROJECT_ROOT = @PROJECT_ROOT@
VPATH = @srcdir@ VPATH = @srcdir@
H_FILES = $(srcdir)/nvram.h $(srcdir)/bsp.h H_FILES = $(srcdir)/../../shared/include/nvram.h \
$(srcdir)/../../shared/include/bsp.h
BSP_H_FILES = $(srcdir)/../../shared/console/consoleIo.h \
$(srcdir)/../../shared/console/uart.h \
$(srcdir)/../../shared/irq/irq.h \
$(srcdir)/../../shared/motorola/motorola.h
# #
# Equate files are for including from assembly preprocessed by # Equate files are for including from assembly preprocessed by
@@ -43,7 +49,9 @@ CLOBBER_ADDITIONS +=
preinstall: preinstall:
$(mkinstalldirs) $(PROJECT_INCLUDE) $(mkinstalldirs) $(PROJECT_INCLUDE)
$(mkinstalldirs) $(PROJECT_INCLUDE)/bsp
@$(INSTALL_CHANGE) -m 644 $(H_FILES) $(PROJECT_INCLUDE) @$(INSTALL_CHANGE) -m 644 $(H_FILES) $(PROJECT_INCLUDE)
@$(INSTALL_CHANGE) -m 644 $(BSP_H_FILES) $(PROJECT_INCLUDE)/bsp
all: $(SRCS) preinstall all: $(SRCS) preinstall

View File

@@ -11,14 +11,14 @@ subdir = powerpc/mcp750/irq
RTEMS_ROOT = @RTEMS_ROOT@ RTEMS_ROOT = @RTEMS_ROOT@
PROJECT_ROOT = @PROJECT_ROOT@ PROJECT_ROOT = @PROJECT_ROOT@
VPATH = @srcdir@ VPATH = @srcdir@:@srcdir@/../../shared/irq
# C source names, if any, go here -- minus the .c # C source names, if any, go here -- minus the .c
C_PIECES = irq_init i8259 irq C_PIECES = irq_init i8259 irq
C_FILES = $(C_PIECES:%=%.c) C_FILES = $(C_PIECES:%=%.c)
C_O_FILES = $(C_PIECES:%=${ARCH}/%.o) C_O_FILES = $(C_PIECES:%=${ARCH}/%.o)
H_FILES = $(srcdir)/irq.h H_FILES = $(srcdir)/../../shared/irq/irq.h
# Assembly source names, if any, go here -- minus the .s # Assembly source names, if any, go here -- minus the .s
S_PIECES = irq_asm S_PIECES = irq_asm
@@ -61,11 +61,7 @@ LDFLAGS +=
CLEAN_ADDITIONS += CLEAN_ADDITIONS +=
CLOBBER_ADDITIONS += CLOBBER_ADDITIONS +=
preinstall: all: ${ARCH} $(SRCS) ${OBJS}
@$(mkinstalldirs) $(PROJECT_INCLUDE)/bsp
@$(INSTALL_CHANGE) -m 644 $(H_FILES) $(PROJECT_INCLUDE)/bsp
all: ${ARCH} $(SRCS) preinstall ${OBJS}
install: all install: all

View File

@@ -11,16 +11,14 @@ subdir = powerpc/mcp750/openpic
RTEMS_ROOT = @RTEMS_ROOT@ RTEMS_ROOT = @RTEMS_ROOT@
PROJECT_ROOT = @PROJECT_ROOT@ PROJECT_ROOT = @PROJECT_ROOT@
VPATH = @srcdir@ VPATH = @srcdir@:@srcdir@/../../shared/openpic
PGM = ${ARCH}/openpic.rel
# C source names, if any, go here -- minus the .c # C source names, if any, go here -- minus the .c
C_PIECES = $(OPENPIC_C_PIECES) C_PIECES = $(OPENPIC_C_PIECES)
C_FILES = $(C_PIECES:%=%.c) C_FILES = $(C_PIECES:%=%.c)
C_O_FILES = $(C_PIECES:%=${ARCH}/%.o) C_O_FILES = $(C_PIECES:%=${ARCH}/%.o)
H_FILES = $(srcdir)/openpic.h H_FILES = $(srcdir)/../../shared/openpic/openpic.h
SRCS = $(C_FILES) $(H_FILES) SRCS = $(C_FILES) $(H_FILES)
OBJS = $(C_O_FILES) OBJS = $(C_O_FILES)
@@ -60,14 +58,11 @@ LDFLAGS +=
CLEAN_ADDITIONS += CLEAN_ADDITIONS +=
CLOBBER_ADDITIONS += CLOBBER_ADDITIONS +=
$(PGM): ${OBJS}
$(make-rel)
preinstall: preinstall:
@$(mkinstalldirs) $(PROJECT_INCLUDE)/bsp @$(mkinstalldirs) $(PROJECT_INCLUDE)/bsp
@$(INSTALL_CHANGE) -m 644 $(H_FILES) $(PROJECT_INCLUDE)/bsp @$(INSTALL_CHANGE) -m 644 $(H_FILES) $(PROJECT_INCLUDE)/bsp
all: ${ARCH} $(SRCS) preinstall $(PGM) all: ${ARCH} $(SRCS) preinstall $(OBJS)
# the .rel file built here will be put into libbsp.a by ../wrapup/Makefile # the .rel file built here will be put into libbsp.a by ../wrapup/Makefile
install: all install: all

View File

@@ -11,16 +11,14 @@ subdir = powerpc/mcp750/pci
RTEMS_ROOT = @RTEMS_ROOT@ RTEMS_ROOT = @RTEMS_ROOT@
PROJECT_ROOT = @PROJECT_ROOT@ PROJECT_ROOT = @PROJECT_ROOT@
VPATH = @srcdir@ VPATH = @srcdir@:@srcdir@/../../shared/pci
PGM = ${ARCH}/pci.rel
# C source names, if any, go here -- minus the .c # C source names, if any, go here -- minus the .c
C_PIECES = $(PCI_C_PIECES) C_PIECES = pci
C_FILES = $(C_PIECES:%=%.c) C_FILES = $(C_PIECES:%=%.c)
C_O_FILES = $(C_PIECES:%=${ARCH}/%.o) C_O_FILES = $(C_PIECES:%=${ARCH}/%.o)
H_FILES = $(srcdir)/pci.h H_FILES = $(srcdir)/../../shared/pci/pci.h
SRCS = $(C_FILES) $(H_FILES) SRCS = $(C_FILES) $(H_FILES)
OBJS = $(C_O_FILES) OBJS = $(C_O_FILES)
@@ -36,8 +34,6 @@ INSTALLDIRS = $(PROJECT_INCLUDE)/bsp
$(INSTALLDIRS): $(INSTALLDIRS):
@$(mkinstalldirs) $(INSTALLDIRS) @$(mkinstalldirs) $(INSTALLDIRS)
PCI_C_PIECES = pci
# #
# (OPTIONAL) Add local stuff here using += # (OPTIONAL) Add local stuff here using +=
# #
@@ -60,14 +56,11 @@ LDFLAGS +=
CLEAN_ADDITIONS += CLEAN_ADDITIONS +=
CLOBBER_ADDITIONS += CLOBBER_ADDITIONS +=
$(PGM): ${OBJS}
$(make-rel)
preinstall: preinstall:
@$(mkinstalldirs) $(PROJECT_INCLUDE)/bsp @$(mkinstalldirs) $(PROJECT_INCLUDE)/bsp
@$(INSTALL_CHANGE) -m 644 $(H_FILES) $(PROJECT_INCLUDE)/bsp @$(INSTALL_CHANGE) -m 644 $(H_FILES) $(PROJECT_INCLUDE)/bsp
all: ${ARCH} $(SRCS) preinstall $(PGM) all: ${ARCH} $(SRCS) preinstall $(OBJS)
# the .rel file built here will be put into libbsp.a by ../wrapup/Makefile # the .rel file built here will be put into libbsp.a by ../wrapup/Makefile
install: all install: all

View File

@@ -11,16 +11,14 @@ subdir = powerpc/mcp750/residual
RTEMS_ROOT = @RTEMS_ROOT@ RTEMS_ROOT = @RTEMS_ROOT@
PROJECT_ROOT = @PROJECT_ROOT@ PROJECT_ROOT = @PROJECT_ROOT@
VPATH = @srcdir@ VPATH = @srcdir@:@srcdir@/../../shared/residual
PGM = ${ARCH}/residual.rel
# C source names, if any, go here -- minus the .c # C source names, if any, go here -- minus the .c
C_PIECES = $(RESIDUAL_C_PIECES) C_PIECES = $(RESIDUAL_C_PIECES)
C_FILES = $(C_PIECES:%=%.c) C_FILES = $(C_PIECES:%=%.c)
C_O_FILES = $(C_PIECES:%=${ARCH}/%.o) C_O_FILES = $(C_PIECES:%=${ARCH}/%.o)
H_FILES = $(srcdir)/pnp.h $(srcdir)/residual.h H_FILES = $(srcdir)/../../shared/residual/pnp.h $(srcdir)/../../shared/residual/residual.h
SRCS = $(C_FILES) $(H_FILES) SRCS = $(C_FILES) $(H_FILES)
OBJS = $(C_O_FILES) OBJS = $(C_O_FILES)
@@ -64,10 +62,7 @@ preinstall:
@$(mkinstalldirs) $(PROJECT_INCLUDE)/bsp @$(mkinstalldirs) $(PROJECT_INCLUDE)/bsp
@$(INSTALL_CHANGE) -m 644 $(H_FILES) $(PROJECT_INCLUDE)/bsp @$(INSTALL_CHANGE) -m 644 $(H_FILES) $(PROJECT_INCLUDE)/bsp
$(PGM): ${OBJS} all: ${ARCH} $(SRCS) preinstall $(OBJS)
$(make-rel)
all: ${ARCH} $(SRCS) preinstall $(PGM)
# the .rel file built here will be put into libbsp.a by ../wrapup/Makefile # the .rel file built here will be put into libbsp.a by ../wrapup/Makefile
install: all install: all

View File

@@ -11,7 +11,7 @@ subdir = powerpc/mcp750/start
RTEMS_ROOT = @RTEMS_ROOT@ RTEMS_ROOT = @RTEMS_ROOT@
PROJECT_ROOT = @PROJECT_ROOT@ PROJECT_ROOT = @PROJECT_ROOT@
VPATH = @srcdir@ VPATH = @srcdir@:@srcdir@/../../shared/start
PGM = ${ARCH}/start.o PGM = ${ARCH}/start.o

View File

@@ -11,7 +11,7 @@ subdir = powerpc/mcp750/startup
RTEMS_ROOT = @RTEMS_ROOT@ RTEMS_ROOT = @RTEMS_ROOT@
PROJECT_ROOT = @PROJECT_ROOT@ PROJECT_ROOT = @PROJECT_ROOT@
VPATH = @srcdir@:@srcdir@/../console:@srcdir@/../../../shared VPATH = @srcdir@:@srcdir@/../console:@srcdir@/../../../shared:@srcdir@/../../shared/startup
# C source names, if any, go here -- minus the .c # C source names, if any, go here -- minus the .c
C_PIECES = bootcard main bspstart bsppost bsplibc sbrk bspclean \ C_PIECES = bootcard main bspstart bsppost bsplibc sbrk bspclean \

View File

@@ -11,16 +11,14 @@ subdir = powerpc/mcp750/vectors
RTEMS_ROOT = @RTEMS_ROOT@ RTEMS_ROOT = @RTEMS_ROOT@
PROJECT_ROOT = @PROJECT_ROOT@ PROJECT_ROOT = @PROJECT_ROOT@
VPATH = @srcdir@:@srcdir@/../console: VPATH = @srcdir@:@srcdir@/../console:@srcdir@/../../shared/vectors
PGM = ${ARCH}/vectors.rel
# C source names, if any, go here -- minus the .c # C source names, if any, go here -- minus the .c
C_PIECES = vectors_init C_PIECES = vectors_init
C_FILES = $(C_PIECES:%=%.c) C_FILES = $(C_PIECES:%=%.c)
C_O_FILES = $(C_PIECES:%=${ARCH}/%.o) C_O_FILES = $(C_PIECES:%=${ARCH}/%.o)
H_FILES = $(srcdir)/vectors.h H_FILES = $(srcdir)/../../shared/vectors/vectors.h
# Assembly source names, if any, go here -- minus the .s # Assembly source names, if any, go here -- minus the .s
S_PIECES = vectors S_PIECES = vectors

View File

@@ -18,7 +18,7 @@ NETWORK_yes_V = dec21140
NETWORK = $(NETWORK_$(HAS_NETWORKING)_V) NETWORK = $(NETWORK_$(HAS_NETWORKING)_V)
BSP_PIECES = clock console irq openpic pci residual startup $(NETWORK) \ BSP_PIECES = clock console irq openpic pci residual startup $(NETWORK) \
vectors vectors motorola
GENERIC_PIECES = GENERIC_PIECES =
# bummer; have to use $foreach since % pattern subst rules only replace 1x # bummer; have to use $foreach since % pattern subst rules only replace 1x

View File

@@ -0,0 +1,36 @@
#
# $Id$
#
@SET_MAKE@
srcdir = @srcdir@
top_srcdir = @top_srcdir@
top_builddir = ../..
subdir = powerpc/shared
RTEMS_ROOT = @RTEMS_ROOT@
PROJECT_ROOT = @PROJECT_ROOT@
VPATH = @srcdir@
include $(RTEMS_ROOT)/make/custom/@RTEMS_BSP@.cfg
include $(RTEMS_ROOT)/make/directory.cfg
INSTALL_CHANGE = @INSTALL_CHANGE@
SRCS =
all: $(SRCS)
# We only build the Network library if HAS_NETWORKING was defined
NETWORK_yes_V = dec21140
NETWORK = $(NETWORK_$(HAS_NETWORKING)_V)
# wrapup is the one that actually builds and installs the library
# from the individual .rel files built in other directories
SUB_DIRS = clock console include pci residual openpic irq vectors \
start startup motorola bootloader $(NETWORK)
Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
cd $(top_builddir) \
&& CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status

View File

@@ -0,0 +1,44 @@
#
# $Id$
#
@SET_MAKE@
srcdir = @srcdir@
top_srcdir = @top_srcdir@
top_builddir = ../../..
subdir = powerpc/shared/bootloader
RTEMS_ROOT = @RTEMS_ROOT@
PROJECT_ROOT = @PROJECT_ROOT@
VPATH = @srcdir@:@srcdir@/../../../shared:@srcdir@/../console
# C source names, if any, go here -- minus the .c
C_PIECES =
C_FILES = $(C_PIECES:%=%.c)
C_O_FILES = $(C_PIECES:%=${ARCH}/%.o)
H_FILES = @srcdir@/bootldr.h @srcdir@/zlib.h @srcdir@/pci.h
# Assembly source names, if any, go here -- minus the .s
S_PIECES =
S_FILES = $(S_PIECES:%=%.S)
S_O_FILES = $(S_FILES:%.S=${ARCH}/%.o)
SRCS = $(C_FILES) $(CC_FILES) $(H_FILES) $(S_FILES)
OBJS = $(S_O_FILES) $(C_O_FILES)
include $(RTEMS_ROOT)/make/custom/@RTEMS_BSP@.cfg
include $(RTEMS_ROOT)/make/leaf.cfg
INSTALL_CHANGE = @INSTALL_CHANGE@
CC_PIECES =
CC_FILES = $(CC_PIECES:%=%.cc)
CC_O_FILES = $(CC_PIECES:%=${ARCH}/%.o)
all: ${ARCH} $(SRCS) ${OBJ}
Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
cd $(top_builddir) \
&& CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status

View File

@@ -0,0 +1,41 @@
#
# $Id$
#
The code in this directory has been taken WITH PERMISSION from
Gabriel Paubert, paubert@iram.es. The main reason for having
a separate bootloader for PreP compliant firmware is that the
initial code is relocated by firmware at an unknow address
(actually 0x5000 on motorola MCP750) and that as Gabriel I
think having a relocatable bootloder code is a must.
So the way of building a binary executable that can be booted via
hard disk or network boot goes like this :
- make a RTEMS executable,
- put is as data section in the bootloder binary,
- relink the loader (see make-exe macros for details),
I would like to thank Gabriel for his support and his code.
The original code can be found in form of a patch to official linux
kernel at (I insist not vger ppc kernel or Imac ppc kernels!!) :
<ftp://vlab1.iram.es/pub/linux-2.2/>
After applying the patch, the code is located in a new directory
called prepboot.
(NB : note use ftp not netscape...)
Note that the actual code differs a lot since Gabriel choose to use
a CHRP compliant mapping instead of a Prep Mapping to save
BATs. I had no time to upgrade the code to its new one allthough
I agree it should be done...
I have also splitted the original code to have a more modular
design enabling to reuse code between the loader and RTEMS
initialization (e.g printk, ...).
Eric Valette (valette@crf.canon.fr)

View File

@@ -0,0 +1,258 @@
/*
* bootldr.h -- Include file for bootloader.
*
* Copyright (C) 1998, 1999 Gabriel Paubert, paubert@iram.es
*
* Modified to compile in RTEMS development environment
* by Eric Valette
*
* Copyright (C) 1999 Eric Valette. valette@crf.canon.fr
*
* The license and distribution terms for this file may be
* found in found in the file LICENSE in this distribution or at
* http://www.OARcorp.com/rtems/license.html.
*
* $Id$
*/
#ifndef _PPC_BOOTLDR_H
#define _PPC_BOOTLDR_H
#ifndef ASM
#include <bsp/residual.h>
#include <bsp/consoleIo.h>
#include "pci.h"
#define abs __builtin_abs
#define PTE_REFD 0x100
#define PTE_CHNG (0x80|PTE_REFD) /* Modified implies referenced */
#define PTE_WTHR 0x040
#define PTE_CINH 0x020
#define PTE_COHER 0x010
#define PTE_GUAR 0x008
#define PTE_RO 0x003
#define PTE_RW 0x002
#define PTE_RAM (PTE_CHNG|PTE_COHER|PTE_RW)
#define PTE_ROM (PTE_REFD|PTE_RO)
#define PTE_IO (PTE_CHNG|PTE_CINH|PTE_GUAR|PTE_RW)
typedef struct {}opaque;
/* The context passed during MMU interrupts. */
typedef struct _ctxt {
u_long lr, ctr;
u_int cr, xer;
u_long nip, msr;
u_long regs[32];
} ctxt;
/* The main structure which is pointed to permanently by r13. Things
* are not separated very well between parts because it would cause
* too much code bloat for such a simple program like the bootloader.
* The code is designed to be compiled with the -m relocatable option and
* tries to minimize the number of relocations/fixups and the number of
* functions who have to access the .got2 sections (this increases the
* size of the prologue in every function).
*/
typedef struct _boot_data {
RESIDUAL *residual;
void *load_address;
void *of_entry;
void *r6, *r7, *r8, *r9, *r10;
u_long cache_lsize;
void *image; /* Where to copy ourselves */
void *stack;
void *mover; /* where to copy codemove to avoid overlays */
u_long o_msr, o_hid0, o_r31;
opaque * mm_private;
const struct pci_config_access_functions * pci_functions;
opaque * pci_private;
struct pci_dev * pci_devices;
opaque * v86_private;
char cmd_line[256];
} boot_data;
register boot_data *bd __asm__("r13");
extern inline int
pcibios_read_config_byte(u_char bus, u_char dev_fn,
u_char where, u_char * val) {
return bd->pci_functions->read_config_byte(bus, dev_fn, where, val);
}
extern inline int
pcibios_read_config_word(u_char bus, u_char dev_fn,
u_char where, u_short * val) {
return bd->pci_functions->read_config_word(bus, dev_fn, where, val);
}
extern inline int
pcibios_read_config_dword(u_char bus, u_char dev_fn,
u_char where, u_int * val) {
return bd->pci_functions->read_config_dword(bus, dev_fn, where, val);
}
extern inline int
pcibios_write_config_byte(u_char bus, u_char dev_fn,
u_char where, u_char val) {
return bd->pci_functions->write_config_byte(bus, dev_fn, where, val);
}
extern inline int
pcibios_write_config_word(u_char bus, u_char dev_fn,
u_char where, u_short val) {
return bd->pci_functions->write_config_word(bus, dev_fn, where, val);
}
extern inline int
pcibios_write_config_dword(u_char bus, u_char dev_fn,
u_char where, u_int val) {
return bd->pci_functions->write_config_dword(bus, dev_fn, where, val);
}
extern inline int
pci_read_config_byte(struct pci_dev *dev, u_char where, u_char * val) {
return bd->pci_functions->read_config_byte(dev->bus->number,
dev->devfn,
where, val);
}
extern inline int
pci_read_config_word(struct pci_dev *dev, u_char where, u_short * val) {
return bd->pci_functions->read_config_word(dev->bus->number,
dev->devfn,
where, val);
}
extern inline int
pci_read_config_dword(struct pci_dev *dev, u_char where, u_int * val) {
return bd->pci_functions->read_config_dword(dev->bus->number,
dev->devfn,
where, val);
}
extern inline int
pci_write_config_byte(struct pci_dev *dev, u_char where, u_char val) {
return bd->pci_functions->write_config_byte(dev->bus->number,
dev->devfn,
where, val);
}
extern inline int
pci_write_config_word(struct pci_dev *dev, u_char where, u_short val) {
return bd->pci_functions->write_config_word(dev->bus->number,
dev->devfn,
where, val);
}
extern inline int
pci_write_config_dword(struct pci_dev *dev, u_char where, u_int val) {
return bd->pci_functions->write_config_dword(dev->bus->number,
dev->devfn,
where, val);
}
/* codemove is like memmove, but it also gets the cache line size
* as 4th parameter to synchronize them. If this last parameter is
* zero, it performs more or less like memmove. No copy is performed if
* source and destination addresses are equal. However the caches
* are synchronized. Note that the size is always rounded up to the
* next mutiple of 4.
*/
extern void * codemove(void *, const void *, size_t, unsigned long);
/* The physical memory allocator allows to align memory by
* powers of 2 given by the lower order bits of flags.
* By default it allocates from higher addresses towrds lower ones,
* setting PA_LOW reverses this behaviour.
*/
#define palloc(size) __palloc(size,0)
#define isa_io_base (bd->io_base)
void * __palloc(u_long, int);
void pfree(void *);
#define PA_LOW 0x100
#define PA_PERM 0x200 /* Not freeable by pfree */
#define PA_SUBALLOC 0x400 /* Allocate for suballocation by salloc */
#define PA_ALIGN_MASK 0x1f
void * valloc(u_long size);
void vfree(void *);
int vmap(void *, u_long, u_long);
void vunmap(void *);
void * salloc(u_long size);
void sfree(void *);
void pci_init(void);
void * memset(void *p, int c, size_t n);
void gunzip(void *, int, unsigned char *, int *);
void print_all_maps(const char *);
void print_hash_table(void);
void MMUon(void);
void MMUoff(void);
void hang(const char *, u_long, ctxt *) __attribute__((noreturn));
int init_v86(void);
void cleanup_v86_mess(void);
void em86_main(struct pci_dev *);
int find_max_mem(struct pci_dev *);
#endif
#ifdef ASM
/* These definitions simplify the ugly declarations necessary for
* GOT definitions.
*/
#define GOT_ENTRY(NAME) .L_ ## NAME = . - .LCTOC1 ; .long NAME
#define GOT(NAME) .L_ ## NAME (r30)
#define START_GOT \
.section ".got2","aw"; \
.LCTOC1 = .+ 0x8000
#define END_GOT \
.text
#define GET_GOT \
bl 1f; \
.text 2; \
0: .long .LCTOC1-1f; \
.text ; \
1: mflr r30; \
lwz r0,0b-1b(r30); \
add r30,r0,r30
#define bd r13
#define cache_lsize 32 /* Offset into bd area */
#define image 36
#define stack 40
#define mover 44
#define o_msr 48
#define o_hid0 52
#define o_r31 56
/* Stack offsets for saved registers on exceptions */
#define save_lr 8(r1)
#define save_ctr 12(r1)
#define save_cr 16(r1)
#define save_xer 20(r1)
#define save_nip 24(r1)
#define save_msr 28(r1)
#define save_r(n) 32+4*n(r1)
#endif
#endif

View File

@@ -0,0 +1,580 @@
/*
* em86.c -- Include file for bootloader.
*
* Copyright (C) 1998, 1999 Gabriel Paubert, paubert@iram.es
*
* Modified to compile in RTEMS development environment
* by Eric Valette
*
* Copyright (C) 1999 Eric Valette. valette@crf.canon.fr
*
* The license and distribution terms for this file may be
* found in found in the file LICENSE in this distribution or at
* http://www.OARcorp.com/rtems/license.html.
*
* $Id$
*/
/*****************************************************************************
*
* Code to interpret Video BIOS ROM routines.
*
*
******************************************************************************/
/* These include are for the development version only */
#include <sys/types.h>
#include "pci.h"
#include <libcpu/byteorder.h>
#ifdef __BOOT__
#include "bootldr.h"
#include <limits.h>
#endif
/* Code options, put them on the compiler command line */
/* #define EIP_STATS */ /* EIP based profiling */
/* #undef EIP_STATS */
typedef union _reg_type1 {
unsigned e;
unsigned short x;
struct {
unsigned char l, h;
} lh;
} reg_type1;
typedef union _reg_type2 {
unsigned e;
unsigned short x;
} reg_type2;
typedef struct _x86 {
reg_type1
_eax, _ecx, _edx, _ebx;
reg_type2
_esp, _ebp, _esi, _edi;
unsigned
es, cs, ss, ds, fs, gs, eip, eflags;
unsigned char
*esbase, *csbase, *ssbase, *dsbase, *fsbase, *gsbase;
volatile unsigned char *iobase;
unsigned char *ioperm;
unsigned
reason, nexteip, parm1, parm2, opcode, base;
unsigned *optable, opreg; /* no more used! */
unsigned char* vbase;
unsigned instructions;
#ifdef __BOOT__
u_char * ram;
u_char * rom;
struct pci_dev * dev;
#else
unsigned filler[14]; /* Skip to next 64 byte boundary */
unsigned eipstats[32768][2];
#endif
} x86;
x86 v86_private __attribute__((aligned(32)));
/* Emulator is in another source file */
extern
void em86_enter(x86 * p);
#define EAX (p->_eax.e)
#define ECX (p->_ecx.e)
#define EDX (p->_edx.e)
#define EBX (p->_ebx.e)
#define ESP (p->_esp.e)
#define EBP (p->_ebp.e)
#define ESI (p->_esi.e)
#define EDI (p->_edi.e)
#define AX (p->_eax.x)
#define CX (p->_ecx.x)
#define DX (p->_edx.x)
#define BX (p->_ebx.x)
#define SP (p->_esp.x)
#define BP (p->_ebp.x)
#define SI (p->_esi.x)
#define DI (p->_edi.x)
#define AL (p->_eax.lh.l)
#define CL (p->_ecx.lh.l)
#define DL (p->_edx.lh.l)
#define BL (p->_ebx.lh.l)
#define AH (p->_eax.lh.h)
#define CH (p->_ecx.lh.h)
#define DH (p->_edx.lh.h)
#define BH (p->_ebx.lh.h)
/* Function used to debug */
#ifdef __BOOT__
#define printf printk
#endif
#ifdef DEBUG
static void dump86(x86 * p){
unsigned char *s = p->csbase + p->eip;
printf("cs:eip=%04x:%08x, eax=%08x, ecx=%08x, edx=%08x, ebx=%08x\n",
p->cs, p->eip, ld_le32(&EAX),
ld_le32(&ECX), ld_le32(&EDX), ld_le32(&EBX));
printf("ss:esp=%04x:%08x, ebp=%08x, esi=%08x, edi=%08x, efl=%08x\n",
p->ss, ld_le32(&ESP), ld_le32(&EBP),
ld_le32(&ESI), ld_le32(&EDI), p->eflags);
printf("nip=%08x, ds=%04x, es=%04x, fs=%04x, gs=%04x, total=%d\n",
p->nexteip, p->ds, p->es, p->fs, p->gs, p->instructions);
printf("code: %02x %02x %02x %02x %02x %02x "
"%02x %02x %02x %02x %02x %02x\n",
s[0], s[1], s[2], s[3], s[4], s[5],
s[6], s[7], s[8], s[9], s[10], s[11]);
#ifndef __BOOT__
printf("op1=%08x, op2=%08x, result=%08x, flags=%08x\n",
p->filler[11], p->filler[12], p->filler[13], p->filler[14]);
#endif
}
#else
#define dump86(x)
#endif
int bios86pci(x86 * p) {
unsigned reg=ld_le16(&DI);
reg_type2 tmp;
if (AL>=8 && AL<=13 && reg>0xff) {
AH = PCIBIOS_BAD_REGISTER_NUMBER;
} else {
switch(AL) {
case 2: /* find_device */
/* Should be improved for BIOS able to handle
* multiple devices. We simply suppose the BIOS
* inits a single device, and return an error
* if it tries to find more...
*/
if (SI) {
AH=PCIBIOS_DEVICE_NOT_FOUND;
} else {
BH = p->dev->bus->number;
BL = p->dev->devfn;
AH = 0;
}
break;
/*
case 3: find_class not implemented for now.
*/
case 8: /* read_config_byte */
AH=pcibios_read_config_byte(BH, BL, reg, &CL);
break;
case 9: /* read_config_word */
AH=pcibios_read_config_word(BH, BL, reg, &tmp.x);
CX=ld_le16(&tmp.x);
break;
case 10: /* read_config_dword */
AH=pcibios_read_config_dword(BH, BL, reg, &tmp.e);
ECX=ld_le32(&tmp.e);
break;
case 11: /* write_config_byte */
AH=pcibios_write_config_byte(BH, BL, reg, CL);
break;
case 12: /* write_config_word */
AH=pcibios_write_config_word(BH, BL, reg, ld_le16(&CX));
break;
case 13: /* write_config_dword */
AH=pcibios_write_config_dword(BH, BL, reg, ld_le32(&ECX));
break;
default:
printf("Unimplemented or illegal PCI service call #%d!\n",
AL);
return 1;
}
}
p->eip = p->nexteip;
/* Set/clear carry according to result */
if (AH) p->eflags |= 1; else p->eflags &=~1;
return 0;
}
void push2(x86 *p, unsigned value) {
unsigned char * sbase= p->ssbase;
unsigned newsp = (ld_le16(&SP)-2)&0xffff;
st_le16(&SP,newsp);
st_le16((unsigned short *)(sbase+newsp), value);
}
unsigned pop2(x86 *p) {
unsigned char * sbase=p->ssbase;
unsigned oldsp = ld_le16(&SP);
st_le16(&SP,oldsp+2);
return ld_le16((unsigned short *)(sbase+oldsp));
}
int int10h(x86 * p) { /* Process BIOS video interrupt */
unsigned vector;
vector=ld_le32((unsigned *)p->vbase+0x10);
if (((vector&0xffff0000)>>16)==0xc000) {
push2(p, p->eflags);
push2(p, p->cs);
push2(p, p->nexteip);
p->cs=vector>>16;
p->csbase=p->vbase + (p->cs<<4);
p->eip=vector&0xffff;
#if 1
p->eflags&=0xfcff; /* Clear AC/TF/IF */
#else
p->eflags = (p->eflags&0xfcff)|0x100; /* Set TF for debugging */
#endif
/* p->eflags|=0x100; uncomment to force a trap */
return(0);
} else {
switch(AH) {
case 0x12:
switch(BL){
case 0x32:
p->eip=p->nexteip;
return(0);
break;
default:
break;
}
default:
break;
}
printf("unhandled soft interrupt 0x10: vector=%x\n", vector);
return(1);
}
}
int process_softint(x86 * p) {
#if 0
if (p->parm1!=0x10 || AH!=0x0e) {
printf("Soft interrupt\n");
dump86(p);
}
#endif
switch(p->parm1) {
case 0x10: /* BIOS video interrupt */
return int10h(p);
case 0x1a:
if(AH==0xb1) return bios86pci(p);
break;
default:
break;
}
dump86(p);
printf("Unhandled soft interrupt number 0x%04x, AX=0x%04x\n",
p->parm1, ld_le16(&AX));
return(1);
}
/* The only function called back by the emulator is em86_trap, all
instructions may that change the code segment are trapped here.
p->reason is one of the following codes. */
#define code_zerdiv 0
#define code_trap 1
#define code_int3 3
#define code_into 4
#define code_bound 5
#define code_ud 6
#define code_dna 7
#define code_iretw 256
#define code_iretl 257
#define code_lcallw 258
#define code_lcalll 259
#define code_ljmpw 260
#define code_ljmpl 261
#define code_lretw 262
#define code_lretl 263
#define code_softint 264
#define code_lock 265 /* Lock prefix */
/* Codes 1024 to 2047 are used for I/O port access instructions:
- The three LSB define the port size (1, 2 or 4)
- bit of weight 512 means out if set, in if clear
- bit of weight 256 means ins/outs if set, in/out if clear
- bit of weight 128 means use esi/edi if set, si/di if clear
(only used for ins/outs instructions, always clear for in/out)
*/
#define code_inb 1024+1
#define code_inw 1024+2
#define code_inl 1024+4
#define code_outb 1024+512+1
#define code_outw 1024+512+2
#define code_outl 1024+512+4
#define code_insb_a16 1024+256+1
#define code_insw_a16 1024+256+2
#define code_insl_a16 1024+256+4
#define code_outsb_a16 1024+512+256+1
#define code_outsw_a16 1024+512+256+2
#define code_outsl_a16 1024+512+256+4
#define code_insb_a32 1024+256+128+1
#define code_insw_a32 1024+256+128+2
#define code_insl_a32 1024+256+128+4
#define code_outsb_a32 1024+512+256+128+1
#define code_outsw_a32 1024+512+256+128+2
#define code_outsl_a32 1024+512+256+128+4
int em86_trap(x86 *p) {
#ifndef __BOOT__
int i;
unsigned char command[80];
unsigned char *verb, *t;
unsigned short *fp;
static unsigned char def=0;
static unsigned char * bptaddr=NULL; /* Breakpoint address */
static unsigned char bptopc; /* Replaced breakpoint opcode */
unsigned char cmd;
unsigned tmp;
#endif
switch(p->reason) {
case code_int3:
#ifndef __BOOT__
if(p->csbase+p->eip == bptaddr) {
*bptaddr=bptopc;
bptaddr=NULL;
}
else printf("Unexpected ");
#endif
printf("Breakpoint Interrupt !\n");
/* Note that this fallthrough (no break;) is on purpose */
#ifdef __BOOT__
return 0;
#else
case code_trap:
dump86(p);
for(;;) {
printf("b(reakpoint, g(o, q(uit, s(tack, t(race ? [%c] ", def);
fgets(command,sizeof(command),stdin);
verb = strtok(command," \n");
if(verb) cmd=*verb; else cmd=def;
def=0;
switch(cmd) {
case 'b':
case 'B':
if(bptaddr) *bptaddr=bptopc;
t=strtok(0," \n");
i=sscanf(t,"%x",&tmp);
if(i==1) {
bptaddr=p->vbase + tmp;
bptopc=*bptaddr;
*bptaddr=0xcc;
} else bptaddr=NULL;
break;
case 'q':
case 'Q':
return 1;
break;
case 'g':
case 'G':
p->eflags &= ~0x100;
return 0;
break;
case 's':
case 'S': /* Print the 8 stack top words */
fp = (unsigned short *)(p->ssbase+ld_le16(&SP));
printf("Stack [%04x:%04x]: %04x %04x %04x %04x %04x %04x %04x %04x\n",
p->ss, ld_le16(&SP),
ld_le16(fp+0), ld_le16(fp+1), ld_le16(fp+2), ld_le16(fp+3),
ld_le16(fp+4), ld_le16(fp+5), ld_le16(fp+6), ld_le16(fp+7));
break;
case 't':
case 'T':
p->eflags |= 0x10100; /* Set the resume and trap flags */
def='t';
return 0;
break;
/* Should add some code to edit registers */
}
}
#endif
break;
case code_ud:
printf("Attempt to execute an unimplemented"
"or undefined opcode!\n");
dump86(p);
return(1); /* exit interpreter */
break;
case code_dna:
printf("Attempt to execute a floating point instruction!\n");
dump86(p);
return(1);
break;
case code_softint:
return process_softint(p);
break;
case code_iretw:
p->eip=pop2(p);
p->cs=pop2(p);
p->csbase=p->vbase + (p->cs<<4);
p->eflags= (p->eflags&0xfffe0000)|pop2(p);
/* p->eflags|= 0x100; */ /* Uncomment to trap after iretws */
return(0);
break;
#ifndef __BOOT__
case code_inb:
case code_inw:
case code_inl:
case code_insb_a16:
case code_insw_a16:
case code_insl_a16:
case code_insb_a32:
case code_insw_a32:
case code_insl_a32:
case code_outb:
case code_outw:
case code_outl:
case code_outsb_a16:
case code_outsw_a16:
case code_outsl_a16:
case code_outsb_a32:
case code_outsw_a32:
case code_outsl_a32:
/* For now we simply enable I/O to the ports and continue */
for(i=p->parm1; i<p->parm1+(p->reason&7); i++) {
p->ioperm[i/8] &= ~(1<<i%8);
}
printf("Access to ports %04x-%04x enabled.\n",
p->parm1, p->parm1+(p->reason&7)-1);
return(0);
#endif
case code_lretw:
/* Check for the exit eyecatcher */
if ( *(u_int *)(p->ssbase+ld_le16(&SP)) == UINT_MAX) return 1;
/* No break on purpose */
default:
dump86(p);
printf("em86_trap called with unhandled reason code !\n");
return(1);
}
}
void cleanup_v86_mess(void) {
x86 *p = (x86 *) bd->v86_private;
/* This automatically removes the mappings ! */
vfree(p->vbase);
p->vbase = 0;
pfree(p->ram);
p->ram = 0;
sfree(p->ioperm);
p->ioperm=0;
}
int init_v86(void) {
x86 *p = (x86 *) bd->v86_private;
/* p->vbase is non null when the v86 is properly set-up */
if (p->vbase) return 0;
/* Set everything to 0 */
memset(p, 0, sizeof(*p));
p->ioperm = salloc(65536/8+1);
p->ram = palloc(0xa0000);
p->iobase = ptr_mem_map->io_base;
if (!p->ram || !p->ioperm) return 1;
/* The ioperm array must have an additional byte at the end ! */
p->ioperm[65536/8] = 0xff;
p->vbase = valloc(0x110000);
if (!p->vbase) return 1;
/* These calls should never fail. */
vmap(p->vbase, (u_long)p->ram|PTE_RAM, 0xa0000);
vmap(p->vbase+0x100000, (u_long)p->ram|PTE_RAM, 0x10000);
vmap(p->vbase+0xa0000,
((u_long)ptr_mem_map->isa_mem_base+0xa0000)|PTE_IO, 0x20000);
return 0;
}
void em86_main(struct pci_dev *dev){
x86 *p = (x86 *) bd->v86_private;
u_short signature;
u_char length;
volatile u_int *src;
u_int *dst, left, saved_rom;
#if defined(MONITOR_IO) && !defined(__BOOT__)
#define IOMASK 0xff
#else
#define IOMASK 0
#endif
#ifndef __BOOT__
int i;
/* Allow or disable access to all ports */
for(i=0; i<65536/8; i++) p->ioperm[i]=IOMASK;
p->ioperm[i] = 0xff; /* Last unused byte must have this value */
#endif
p->dev = dev;
memset(p->vbase, 0, 0xa0000);
/* Set up a few registers */
p->cs = 0xc000; p->csbase = p->vbase + 0xc0000;
p->ss = 0x1000; p->ssbase = p->vbase + 0x10000;
p->eflags=0x200;
st_le16(&SP,0xfffc); p->eip=3;
p->dsbase = p->esbase = p->fsbase = p->gsbase = p->vbase;
/* Follow the PCI BIOS specification */
AH=dev->bus->number;
AL=dev->devfn;
/* All other registers are irrelevant except ES:DI which
* should point to a PnP installation check block. This
* is not yet implemented due to lack of references. */
/* Store a return address of 0xffff:0xffff as eyecatcher */
*(u_int *)(p->ssbase+ld_le16(&SP)) = UINT_MAX;
/* Interrupt for BIOS EGA services is 0xf000:0xf065 (int 0x10) */
st_le32((u_int *)p->vbase + 0x10, 0xf000f065);
/* Enable the ROM, read it and disable it immediately */
pci_read_config_dword(dev, PCI_ROM_ADDRESS, &saved_rom);
pci_write_config_dword(dev, PCI_ROM_ADDRESS, 0x000c0001);
/* Check that there is an Intel ROM. Should we also check that
* the first instruction is a jump (0xe9 or 0xeb) ?
*/
signature = *(u_short *)(ptr_mem_map->isa_mem_base+0xc0000);
if (signature!=0x55aa) {
printf("bad signature: %04x.\n", signature);
return;
}
/* Allocate memory and copy the video rom to vbase+0xc0000; */
length = ptr_mem_map->isa_mem_base[0xc0002];
p->rom = palloc(length*512);
if (!p->rom) return;
for(dst=(u_int *) p->rom,
src=(volatile u_int *)(ptr_mem_map->isa_mem_base+0xc0000),
left = length*512/sizeof(u_int);
left--;
*dst++=*src++);
/* Disable the ROM and map the copy in virtual address space, note
* that the ROM has to be mapped as RAM since some BIOSes (at least
* Cirrus) perform write accesses to their own ROM. The reason seems
* to be that they check that they must execute from shadow RAM
* because accessing the ROM prevents accessing the video RAM
* according to comments in linux/arch/alpha/kernel/bios32.c.
*/
pci_write_config_dword(dev, PCI_ROM_ADDRESS, saved_rom);
vmap(p->vbase+0xc0000, (u_long)p->rom|PTE_RAM, length*512);
/* Now actually emulate the ROM init routine */
em86_enter(p);
/* Free the acquired resources */
vunmap(p->vbase+0xc0000);
pfree(p->rom);
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,473 @@
/*
* exception.S -- Exception handlers for early boot.
*
* Copyright (C) 1998, 1999 Gabriel Paubert, paubert@iram.es
*
* Modified to compile in RTEMS development environment
* by Eric Valette
*
* Copyright (C) 1999 Eric Valette. valette@crf.canon.fr
*
* The license and distribution terms for this file may be
* found in found in the file LICENSE in this distribution or at
* http://www.OARcorp.com/rtems/license.html.
*
* $Id$
*/
/* This is an improved version of the TLB interrupt handling code from
* the 603e users manual (603eUM.pdf) downloaded from the WWW. All the
* visible bugs have been removed. Note that many have survived in the errata
* to the 603 user manual (603UMer.pdf).
*
* This code also pays particular attention to optimization, takes into
* account the differences between 603 and 603e, single/multiple processor
* systems and tries to order instructions for dual dispatch in many places.
*
* The optimization has been performed along two lines:
* 1) to minimize the number of instruction cache lines needed for the most
* common execution paths (the ones that do not result in an exception).
* 2) then to order the code to maximize the number of dual issue and
* completion opportunities without increasing the number of cache lines
* used in the same cases.
*
* The last goal of this code is to fit inside the address range
* assigned to the interrupt vectors: 192 instructions with fixed
* entry points every 64 instructions.
*
* Some typos have also been corrected and the Power l (lowercase L)
* instructions replaced by lwz without comment.
*
* I have attempted to describe the reasons of the order and of the choice
* of the instructions but the comments may be hard to understand without
* the processor manual.
*
* Note that the fact that the TLB are reloaded by software in theory
* allows tremendous flexibility, for example we could avoid setting the
* reference bit of the PTE which will could actually not be accessed because
* of protection violation by changing a few lines of code. However,
* this would significantly slow down most TLB reload operations, and
* this is the reason for which we try never to make checks which would be
* redundant with hardware and usually indicate a bug in a program.
*
* There are some inconsistencies in the documentation concerning the
* settings of SRR1 bit 15. All recent documentations say now that it is set
* for stores and cleared for loads. Anyway this handler never uses this bit.
*
* A final remark, the rfi instruction seems to implicitly clear the
* MSR<14> (tgpr)bit. The documentation claims that this bit is restored
* from SRR1 by rfi, but the corresponding bit in SRR1 is the LRU way bit.
* Anyway, the only exception which can occur while TGPR is set is a machine
* check which would indicate an unrecoverable problem. Recent documentation
* now says in some place that rfi clears MSR<14>.
*
* TLB software load for 602/603/603e/603ev:
* Specific Instructions:
* tlbld - write the dtlb with the pte in rpa reg
* tlbli - write the itlb with the pte in rpa reg
* Specific SPRs:
* dmiss - address of dstream miss
* imiss - address of istream miss
* hash1 - address primary hash PTEG address
* hash2 - returns secondary hash PTEG address
* iCmp - returns the primary istream compare value
* dCmp - returns the primary dstream compare value
* rpa - the second word of pte used by tlblx
* Other specific resources:
* cr0 saved in 4 high order bits of SRR1,
* SRR1 bit 14 [WAY] selects TLB set to load from LRU algorithm
* gprs r0..r3 shadowed by the setting of MSR bit 14 [TGPR]
* other bits in SRR1 (unused by this handler but see earlier comments)
*
* There are three basic flows corresponding to three vectors:
* 0x1000: Instruction TLB miss,
* 0x1100: Data TLB miss on load,
* 0x1200: Data TLB miss on store or not dirty page
*/
/* define the following if code does not have to run on basic 603 */
/* #define USE_KEY_BIT */
/* define the following for safe multiprocessing */
/* #define MULTIPROCESSING */
/* define the following for mixed endian */
/* #define CHECK_MIXED_ENDIAN */
/* define the following if entries always have the reference bit set */
#define ASSUME_REF_SET
/* Some OS kernels may want to keep a single copy of the dirty bit in a per
* page table. In this case writable pages are always write-protected as long
* as they are clean, and the dirty bit set actually means that the page
* is writable.
*/
#define DIRTY_MEANS_WRITABLE
#include <libcpu/cpu.h>
#include "asm.h"
#include "bootldr.h"
/*
* Instruction TLB miss flow
* Entry at 0x1000 with the following:
* srr0 -> address of instruction that missed
* srr1 -> 0:3=cr0, 13=1 (instruction), 14=lru way, 16:31=saved MSR
* msr<tgpr> -> 1
* iMiss -> ea that missed
* iCmp -> the compare value for the va that missed
* hash1 -> pointer to first hash pteg
* hash2 -> pointer to second hash pteg
*
* Register usage:
* r0 is limit address during search / scratch after
* r1 is pte data / error code for ISI exception when search fails
* r2 is pointer to pte
* r3 is compare value during search / scratch after
*/
/* Binutils or assembler bug ? Declaring the section executable and writable
* generates an error message on the @fixup entries.
*/
.section .exception,"aw"
# .org 0x1000 # instruction TLB miss entry point
.globl tlb_handlers
tlb_handlers:
.type tlb_handlers,@function
#define ISIVec tlb_handlers-0x1000+0x400
#define DSIVec tlb_handlers-0x1000+0x300
mfspr r2,HASH1
lwz r1,0(r2) # Start memory access as soon as possible
mfspr r3,ICMP # to load the cache.
0: la r0,48(r2) # Use explicit loop to avoid using ctr
1: cmpw r1,r3 # In theory the loop is somewhat slower
beq- 2f # than documentation example
cmpw r0,r2 # but we gain from starting cache load
lwzu r1,8(r2) # earlier and using slots between load
bne+ 1b # and comparison for other purposes.
cmpw r1,r3
bne- 4f # Secondary hash check
2: lwz r1,4(r2) # Found: load second word of PTE
mfspr r0,IMISS # get miss address during load delay
#ifdef ASSUME_REF_SET
andi. r3,r1,8 # check for guarded memory
bne- 5f
mtspr RPA,r1
mfsrr1 r3
tlbli r0
#else
/* This is basically the original code from the manual. */
# andi. r3,r1,8 # check for guarded memory
# bne- 5f
# andi. r3,r1,0x100 # check R bit ahead to help folding
/* However there is a better solution: these last three instructions can be
replaced by the following which should cause less pipeline stalls because
both tests are combined and there is a single CR rename buffer */
extlwi r3,r1,6,23 # Keep only RCWIMG in 6 most significant bits.
rlwinm. r3,r3,5,0,27 # Keep only G (in sign) and R and test.
blt- 5f # Negative means guarded, zero R not set.
mfsrr1 r3 # get saved cr0 bits now to dual issue
ori r1,r1,0x100
mtspr RPA,r1
tlbli r0
/* Do not update PTE if R bit already set, this will save one cache line
writeback at a later time, and avoid even more bus traffic in
multiprocessing systems, when several processors access the same PTEGs.
We also hope that the reference bit will be already set. */
bne+ 3f
#ifdef MULTIPROCESSING
srwi r1,r1,8 # get byte 7 of pte
stb r1,+6(r2) # update page table
#else
sth r1,+6(r2) # update page table
#endif
#endif
3: mtcrf 0x80,r3 # restore CR0
rfi # return to executing program
/* The preceding code is 20 to 25 instructions long, which occupies
3 or 4 cache lines. */
4: andi. r0,r3,0x0040 # see if we have done second hash
lis r1,0x4000 # set up error code in case next branch taken
bne- 6f # speculatively issue the following
mfspr r2,HASH2 # get the second pointer
ori r3,r3,0x0040 # change the compare value
lwz r1,0(r2) # load first entry
b 0b # and go back to main loop
/* We are now at 27 to 32 instructions, using 3 or 4 cache lines for all
cases in which the TLB is successfully loaded. */
/* Guarded memory protection violation: synthesize an ISI exception. */
5: lis r1,0x1000 # set srr1<3>=1 to flag guard violation
/* Entry Not Found branches here with r1 correctly set. */
6: mfsrr1 r3
mfmsr r0
insrwi r1,r3,16,16 # build srr1 for ISI exception
mtsrr1 r1 # set srr1
/* It seems few people have realized rlwinm can be used to clear a bit or
a field of contiguous bits in a register by setting mask_begin>mask_end. */
rlwinm r0,r0,0,15,13 # clear the msr<tgpr> bit
mtcrf 0x80, r3 # restore CR0
mtmsr r0 # flip back to the native gprs
isync # Required from 602 doc!
b ISIVec # go to instruction access exception
/* Up to now there are 37 to 42 instructions so at least 20 could be
inserted for complex cases or for statistics recording. */
/*
Data TLB miss on load flow
Entry at 0x1100 with the following:
srr0 -> address of instruction that caused the miss
srr1 -> 0:3=cr0, 13=0 (data), 14=lru way, 15=0, 16:31=saved MSR
msr<tgpr> -> 1
dMiss -> ea that missed
dCmp -> the compare value for the va that missed
hash1 -> pointer to first hash pteg
hash2 -> pointer to second hash pteg
Register usage:
r0 is limit address during search / scratch after
r1 is pte data / error code for DSI exception when search fails
r2 is pointer to pte
r3 is compare value during search / scratch after
*/
.org tlb_handlers+0x100
mfspr r2,HASH1
lwz r1,0(r2) # Start memory access as soon as possible
mfspr r3,DCMP # to load the cache.
0: la r0,48(r2) # Use explicit loop to avoid using ctr
1: cmpw r1,r3 # In theory the loop is somewhat slower
beq- 2f # than documentation example
cmpw r0,r2 # but we gain from starting cache load
lwzu r1,8(r2) # earlier and using slots between load
bne+ 1b # and comparison for other purposes.
cmpw r1,r3
bne- 4f # Secondary hash check
2: lwz r1,4(r2) # Found: load second word of PTE
mfspr r0,DMISS # get miss address during load delay
#ifdef ASSUME_REF_SET
mtspr RPA,r1
mfsrr1 r3
tlbld r0
#else
andi. r3,r1,0x100 # check R bit ahead to help folding
mfsrr1 r3 # get saved cr0 bits now to dual issue
ori r1,r1,0x100
mtspr RPA,r1
tlbld r0
/* Do not update PTE if R bit already set, this will save one cache line
writeback at a later time, and avoid even more bus traffic in
multiprocessing systems, when several processors access the same PTEGs.
We also hope that the reference bit will be already set. */
bne+ 3f
#ifdef MULTIPROCESSING
srwi r1,r1,8 # get byte 7 of pte
stb r1,+6(r2) # update page table
#else
sth r1,+6(r2) # update page table
#endif
#endif
3: mtcrf 0x80,r3 # restore CR0
rfi # return to executing program
/* The preceding code is 18 to 23 instructions long, which occupies
3 cache lines. */
4: andi. r0,r3,0x0040 # see if we have done second hash
lis r1,0x4000 # set up error code in case next branch taken
bne- 9f # speculatively issue the following
mfspr r2,HASH2 # get the second pointer
ori r3,r3,0x0040 # change the compare value
lwz r1,0(r2) # load first entry asap
b 0b # and go back to main loop
/* We are now at 25 to 30 instructions, using 3 or 4 cache lines for all
cases in which the TLB is successfully loaded. */
/*
Data TLB miss on store or not dirty page flow
Entry at 0x1200 with the following:
srr0 -> address of instruction that caused the miss
srr1 -> 0:3=cr0, 13=0 (data), 14=lru way, 15=1, 16:31=saved MSR
msr<tgpr> -> 1
dMiss -> ea that missed
dCmp -> the compare value for the va that missed
hash1 -> pointer to first hash pteg
hash2 -> pointer to second hash pteg
Register usage:
r0 is limit address during search / scratch after
r1 is pte data / error code for DSI exception when search fails
r2 is pointer to pte
r3 is compare value during search / scratch after
*/
.org tlb_handlers+0x200
mfspr r2,HASH1
lwz r1,0(r2) # Start memory access as soon as possible
mfspr r3,DCMP # to load the cache.
0: la r0,48(r2) # Use explicit loop to avoid using ctr
1: cmpw r1,r3 # In theory the loop is somewhat slower
beq- 2f # than documentation example
cmpw r0,r2 # but we gain from starting cache load
lwzu r1,8(r2) # earlier and using slots between load
bne+ 1b # and comparison for other purposes.
cmpw r1,r3
bne- 4f # Secondary hash check
2: lwz r1,4(r2) # Found: load second word of PTE
mfspr r0,DMISS # get miss address during load delay
/* We could simply set the C bit and then rely on hardware to flag protection
violations. This raises the problem that a page which actually has not been
modified may be marked as dirty and violates the OEA model for guaranteed
bit settings (table 5-8 of 603eUM.pdf). This can have harmful consequences
on operating system memory management routines, and play havoc with copy on
write schemes. So the protection check is ABSOLUTELY necessary. */
andi. r3,r1,0x80 # check C bit
beq- 5f # if (C==0) go to check protection
3: mfsrr1 r3 # get the saved cr0 bits
mtspr RPA,r1 # set the pte
tlbld r0 # load the dtlb
mtcrf 0x80,r3 # restore CR0
rfi # return to executing program
/* The preceding code is 20 instructions long, which occupy
3 cache lines. */
4: andi. r0,r3,0x0040 # see if we have done second hash
lis r1,0x4200 # set up error code in case next branch taken
bne- 9f # speculatively issue the following
mfspr r2,HASH2 # get the second pointer
ori r3,r3,0x0040 # change the compare value
lwz r1,0(r2) # load first entry asap
b 0b # and go back to main loop
/* We are now at 27 instructions, using 3 or 4 cache lines for all
cases in which the TLB C bit is already set. */
#ifdef DIRTY_MEANS_WRITABLE
5: lis r1,0x0A00 # protection violation on store
#else
/*
Entry found and C==0: check protection before setting C:
Register usage:
r0 is dMiss register
r1 is PTE entry (to be copied to RPA if success)
r2 is pointer to pte
r3 is trashed
For the 603e, the key bit in SRR1 helps to decide whether there is a
protection violation. However the way the check is done in the manual is
not very efficient. The code shown here works as well for 603 and 603e and
is much more efficient for the 603 and comparable to the manual example
for 603e. This code however has quite a bad structure due to the fact it
has been reordered to speed up the most common cases.
*/
/* The first of the following two instructions could be replaced by
andi. r3,r1,3 but it would compete with cmplwi for cr0 resource. */
5: clrlwi r3,r1,30 # Extract two low order bits
cmplwi r3,2 # Test for PP=10
bne- 7f # assume fallthrough is more frequent
6: ori r1,r1,0x180 # set referenced and changed bit
sth r1,6(r2) # update page table
b 3b # and finish loading TLB
/* We are now at 33 instructions, using 5 cache lines. */
7: bgt- 8f # if PP=11 then DSI protection exception
/* This code only works if key bit is present (602/603e/603ev) */
#ifdef USE_KEY_BIT
mfsrr1 r3 # get the KEY bit and test it
andis. r3,r3,0x0008
beq 6b # default prediction taken, truly better ?
#else
/* This code is for all 602 and 603 family models: */
mfsrr1 r3 # Here the trick is to use the MSR PR bit as a
mfsrin r0,r0 # shift count for an rlwnm. instruction which
extrwi r3,r3,1,17 # extracts and tests the correct key bit from
rlwnm. r3,r0,r3,1,1 # the segment register. RISC they said...
mfspr r0,DMISS # Restore fault address to r0
beq 6b # if 0 load tlb else protection fault
#endif
/* We are now at 40 instructions, (37 if using key bit), using 5 cache
lines in all cases in which the C bit is successfully set */
8: lis r1,0x0A00 # protection violation on store
#endif /* DIRTY_IS_WRITABLE */
/* PTE entry not found branch here with DSISR code in r1 */
9: mfsrr1 r3
mtdsisr r1
clrlwi r2,r3,16 # set up srr1 for DSI exception
mfmsr r0
/* I have some doubts about the usefulness of the xori instruction in
mixed or pure little-endian environment. The address is in the same
doubleword, hence in the same protection domain and performing an exclusive
or with 7 is only valid for byte accesses. */
#ifdef CHECK_MIXED_ENDIAN
andi. r1,r2,1 # test LE bit ahead to help folding
#endif
mtsrr1 r2
rlwinm r0,r0,0,15,13 # clear the msr<tgpr> bit
mfspr r1,DMISS # get miss address
#ifdef CHECK_MIXED_ENDIAN
beq 1f # if little endian then:
xori r1,r1,0x07 # de-mung the data address
1:
#endif
mtdar r1 # put in dar
mtcrf 0x80,r3 # restore CR0
mtmsr r0 # flip back to the native gprs
isync # required from 602 manual
b DSIVec # branch to DSI exception
/* We are now between 50 and 56 instructions. Close to the limit
but should be sufficient in case bugs are found. */
/* Altogether the three handlers occupy 128 instructions in the worst
case, 64 instructions could still be added (non contiguously). */
.org tlb_handlers+0x300
.globl _handler_glue
_handler_glue:
/* Entry code for exceptions: DSI (0x300), ISI(0x400), alignment(0x600) and
* traps(0x700). In theory it is not necessary to save and restore r13 and all
* higher numbered registers, but it is done because it allowed to call the
* firmware (PPCBug) for debugging in the very first stages when writing the
* bootloader.
*/
stwu r1,-160(r1)
stw r0,save_r(0)
mflr r0
stmw r2,save_r(2)
bl 0f
0: mfctr r4
stw r0,save_lr
mflr r9 /* Interrupt vector + few instructions */
la r10,160(r1)
stw r4,save_ctr
mfcr r5
lwz r8,2f-0b(r9)
mfxer r6
stw r5,save_cr
mtctr r8
stw r6,save_xer
mfsrr0 r7
stw r10,save_r(1)
mfsrr1 r8
stw r7,save_nip
la r4,8(r1)
lwz r13,1f-0b(r9)
rlwinm r3,r9,24,0x3f /* Interrupt vector >> 8 */
stw r8,save_msr
bctrl
lwz r7,save_msr
lwz r6,save_nip
mtsrr1 r7
lwz r5,save_xer
mtsrr0 r6
lwz r4,save_ctr
mtxer r5
lwz r3,save_lr
mtctr r4
lwz r0,save_cr
mtlr r3
lmw r2,save_r(2)
mtcr r0
lwz r0,save_r(0)
la r1,160(r1)
rfi
1: .long (__bd)@fixup
2: .long (_handler)@fixup
.section .fixup,"aw"
.align 2
.long 1b, 2b
.previous

View File

@@ -0,0 +1,381 @@
/*
* head.S -- Bootloader Entry point
*
* Copyright (C) 1998, 1999 Gabriel Paubert, paubert@iram.es
*
* Modified to compile in RTEMS development environment
* by Eric Valette
*
* Copyright (C) 1999 Eric Valette. valette@crf.canon.fr
*
* The license and distribution terms for this file may be
* found in found in the file LICENSE in this distribution or at
* http://www.OARcorp.com/rtems/license.html.
*
* $Id$
*/
#include "bootldr.h"
#include <libcpu/cpu.h>
#include <rtems/score/targopts.h>
#include "asm.h"
#undef TEST_PPCBUG_CALLS
#define FRAME_SIZE 32
#define LOCK_CACHES (HID0_DLOCK|HID0_ILOCK)
#define INVL_CACHES (HID0_DCI|HID0_ICFI)
#define ENBL_CACHES (HID0_DCE|HID0_ICE)
#define USE_PPCBUG
#undef USE_PPCBUG
#define MONITOR_ENTER \
mfmsr r10 ; \
ori r10,r10,MSR_IP ; \
mtmsr r10 ; \
li r10,0x63 ; \
sc
START_GOT
GOT_ENTRY(_GOT2_TABLE_)
GOT_ENTRY(_FIXUP_TABLE_)
GOT_ENTRY(.bss)
GOT_ENTRY(codemove)
GOT_ENTRY(0)
GOT_ENTRY(__bd)
GOT_ENTRY(moved)
GOT_ENTRY(_binary_rtems_gz_start)
GOT_ENTRY(_binary_initrd_gz_start)
GOT_ENTRY(_binary_initrd_gz_end)
#ifdef TEST_PPCBUG_CALLS
GOT_ENTRY(banner_start)
GOT_ENTRY(banner_end)
#endif
END_GOT
.globl start
.type start,@function
/* Point the stack into the PreP partition header in the x86 reserved
* code area, so that simple C routines can be called.
*/
start:
#ifdef USE_PPCBUG
MONITOR_ENTER
#endif
bl 1f
1: mflr r1
li r0,0
stwu r0,start-1b-0x400+0x1b0-FRAME_SIZE(r1)
stmw r26,FRAME_SIZE-24(r1)
GET_GOT
mfmsr r28 /* Turn off interrupts */
ori r0,r28,MSR_EE
xori r0,r0,MSR_EE
mtmsr r0
/* Enable the caches, from now on cr2.eq set means processor is 601 */
mfpvr r0
mfspr r29,HID0
srwi r0,r0,16
cmplwi cr2,r0,1
beq 2,2f
#ifndef USE_PPCBUG
ori r0,r29,ENBL_CACHES|INVL_CACHES|LOCK_CACHES
xori r0,r0,INVL_CACHES|LOCK_CACHES
sync
isync
mtspr HID0,r0
#endif
2: bl reloc
/* save all the parameters and the orginal msr/hid0/r31 */
lwz bd,GOT(__bd)
stw r3,0(bd)
stw r4,4(bd)
stw r5,8(bd)
stw r6,12(bd)
lis r3,__size@sectoff@ha
stw r7,16(bd)
stw r8,20(bd)
addi r3,r3,__size@sectoff@l
stw r9,24(bd)
stw r10,28(bd)
stw r28,o_msr(bd)
stw r29,o_hid0(bd)
stw r31,o_r31(bd)
/* Call the routine to fill boot_data structure from residual data.
* And to find where the code has to be moved.
*/
bl early_setup
/* Now we need to relocate ourselves, where we are told to. First put a
* copy of the codemove routine to some place in memory.
* (which may be where the 0x41 partition was loaded, so size is critical).
*/
lwz r4,GOT(codemove)
li r5,_size_codemove
lwz r3,mover(bd)
lwz r6,cache_lsize(bd)
bl codemove
mtctr r3 # Where the temporary codemove is.
lwz r3,image(bd)
lis r5,_edata@sectoff@ha
lwz r4,GOT(0) # Our own address
addi r5,r5,_edata@sectoff@l
lwz r6,cache_lsize(bd)
lwz r8,GOT(moved)
sub r7,r3,r4 # Difference to adjust pointers.
add r8,r8,r7
add r30,r30,r7
add bd,bd,r7
/* Call the copy routine but return to the new area. */
mtlr r8 # for the return address
bctr # returns to the moved instruction
/* Establish the new top stack frame. */
moved: lwz r1,stack(bd)
li r0,0
stwu r0,-16(r1)
/* relocate again */
bl reloc
/* Clear all of BSS */
lwz r10,GOT(.bss)
li r0,__bss_words@sectoff@l
subi r10,r10,4
cmpwi r0,0
mtctr r0
li r0,0
beq 4f
3: stwu r0,4(r10)
bdnz 3b
/* Final memory initialization. First switch to unmapped mode
* in case the FW had set the MMU on, and flush the TLB to avoid
* stale entries from interfering. No I/O access is allowed
* during this time!
*/
#ifndef USE_PPCBUG
4: bl MMUoff
#endif
bl flush_tlb
/* Some firmware versions leave stale values in the BATs, it's time
* to invalidate them to avoid interferences with our own mappings.
* But the 601 valid bit is in the BATL (IBAT only) and others are in
* the [ID]BATU. Bloat, bloat.. fortunately thrown away later.
*/
li r3,0
beq cr2,5f
mtdbatu 0,r3
mtdbatu 1,r3
mtdbatu 2,r3
mtdbatu 3,r3
5: mtibatu 0,r3
mtibatl 0,r3
mtibatu 1,r3
mtibatl 1,r3
mtibatu 2,r3
mtibatl 2,r3
mtibatu 3,r3
mtibatl 3,r3
lis r3,__size@sectoff@ha
addi r3,r3,__size@sectoff@l
sync # We are going to touch SDR1 !
bl mm_init
bl MMUon
/* Now we are mapped and can perform I/O if we want */
#ifdef TEST_PPCBUG_CALLS
/* Experience seems to show that PPCBug can only be called with the
* data cache disabled and with MMU disabled. Bummer.
*/
li r10,0x22 # .OUTLN
lwz r3,GOT(banner_start)
lwz r4,GOT(banner_end)
sc
#endif
bl setup_hw
lwz r4,GOT(_binary_rtems_gz_start)
lis r5,_rtems_gz_size@sectoff@ha
lwz r6,GOT(_binary_initrd_gz_start)
lis r3,_rtems_size@sectoff@ha
lwz r7,GOT(_binary_initrd_gz_end)
addi r5,r5,_rtems_gz_size@sectoff@l
addi r3,r3,_rtems_size@sectoff@l
sub r7,r7,r6
bl decompress_kernel
/* Back here we are unmapped and we start the kernel, passing up to eight
* parameters just in case, only r3 to r7 used for now. Flush the tlb so
* that the loaded image starts in a clean state.
*/
bl flush_tlb
lwz r3,0(bd)
lwz r4,4(bd)
lwz r5,8(bd)
lwz r6,12(bd)
lwz r7,16(bd)
lwz r8,20(bd)
lwz r9,24(bd)
lwz r10,28(bd)
lwz r30,0(0)
mtctr r30
/*
* Linux code again
lis r30,0xdeadc0de@ha
addi r30,r30,0xdeadc0de@l
stw r30,0(0)
li r30,0
*/
dcbst 0,r30 /* Make sure it's in memory ! */
/* We just flash invalidate and disable the dcache, unless it's a 601,
* critical areas have been flushed and we don't care about the stack
* and other scratch areas.
*/
beq cr2,1f
mfspr r0,HID0
ori r0,r0,HID0_DCI|HID0_DCE
sync
mtspr HID0,r0
xori r0,r0,HID0_DCI|HID0_DCE
mtspr HID0,r0
/* Provisional return to FW, works for PPCBug */
#if 0
MONITOR_ENTER
#else
1: bctr
#endif
/* relocation function, r30 must point to got2+0x8000 */
reloc:
/* Adjust got2 pointers, no need to check for 0, this code already puts
* a few entries in the table.
*/
li r0,__got2_entries@sectoff@l
la r12,GOT(_GOT2_TABLE_)
lwz r11,GOT(_GOT2_TABLE_)
mtctr r0
sub r11,r12,r11
addi r12,r12,-4
1: lwzu r0,4(r12)
add r0,r0,r11
stw r0,0(r12)
bdnz 1b
/* Now adjust the fixups and the pointers to the fixups in case we need
* to move ourselves again.
*/
2: li r0,__fixup_entries@sectoff@l
lwz r12,GOT(_FIXUP_TABLE_)
cmpwi r0,0
mtctr r0
addi r12,r12,-4
beqlr
3: lwzu r10,4(r12)
lwzux r0,r10,r11
add r0,r0,r11
stw r10,0(r12)
stw r0,0(r10)
bdnz 3b
blr
/* Set the MMU on and off: code is always mapped 1:1 and does not need MMU,
* but it does not cost so much to map it also and it catches calls through
* NULL function pointers.
*/
.globl MMUon
.type MMUon,@function
MMUon: mfmsr r0
ori r0,r0,MSR_IR|MSR_DR|MSR_IP
mflr r11
xori r0,r0,MSR_IP
mtsrr0 r11
mtsrr1 r0
rfi
.globl MMUoff
.type MMUoff,@function
MMUoff: mfmsr r0
ori r0,r0,MSR_IR|MSR_DR|MSR_IP
mflr r11
xori r0,r0,MSR_IR|MSR_DR
mtsrr0 r11
mtsrr1 r0
rfi
/* Due to the PPC architecture (and according to the specifications), a
* series of tlbie which goes through a whole 256 MB segment always flushes
* the whole TLB. This is obviously overkill and slow, but who cares ?
* It takes about 1 ms on a 200 MHz 603e and works even if residual data
* get the number of TLB entries wrong.
*/
flush_tlb:
lis r11,0x1000
1: addic. r11,r11,-0x1000
tlbie r11
bnl 1b
/* tlbsync is not implemented on 601, so use sync which seems to be a superset
* of tlbsync in all cases and do not bother with CPU dependant code
*/
sync
blr
.globl codemove
codemove:
.type codemove,@function
/* r3 dest, r4 src, r5 length in bytes, r6 cachelinesize */
cmplw cr1,r3,r4
addi r0,r5,3
srwi. r0,r0,2
beq cr1,4f /* In place copy is not necessary */
beq 7f /* Protect against 0 count */
mtctr r0
bge cr1,2f
la r8,-4(r4)
la r7,-4(r3)
1: lwzu r0,4(r8)
stwu r0,4(r7)
bdnz 1b
b 4f
2: slwi r0,r0,2
add r8,r4,r0
add r7,r3,r0
3: lwzu r0,-4(r8)
stwu r0,-4(r7)
bdnz 3b
/* Now flush the cache: note that we must start from a cache aligned
* address. Otherwise we might miss one cache line.
*/
4: cmpwi r6,0
add r5,r3,r5
beq 7f /* Always flush prefetch queue in any case */
subi r0,r6,1
andc r3,r3,r0
mr r4,r3
5: cmplw r4,r5
dcbst 0,r4
add r4,r4,r6
blt 5b
sync /* Wait for all dcbst to complete on bus */
mr r4,r3
6: cmplw r4,r5
icbi 0,r4
add r4,r4,r6
blt 6b
7: sync /* Wait for all icbi to complete on bus */
isync
blr
.size codemove,.-codemove
_size_codemove=.-codemove
.section ".data" # .rodata
.align 2
#ifdef TEST_PPCBUG_CALLS
banner_start:
.ascii "This message was printed by PPCBug with MMU enabled"
banner_end:
#endif

View File

@@ -0,0 +1,53 @@
/* lib.c
*
* This file contains the implementation of functions that are unresolved
* in the bootloader. Unfortunately it shall not use any object code
* from newlib or rtems because they are not compiled with the right option!!!
*
* You've been warned!!!.
*
* CopyRight (C) 1998, 1999 valette@crf.canon.fr
*
* The license and distribution terms for this file may be
* found in found in the file LICENSE in this distribution or at
* http://www.OARcorp.com/rtems/license.html.
*
* $Id$
*/
void* memset(void *p, int c, unsigned int n)
{
char *q =p;
for(; n>0; --n) *q++=c;
return p;
}
void* memcpy(void *dst, const void * src, unsigned int n)
{
unsigned char *d=dst;
const unsigned char *s=src;
while(n-- > 0) *d++=*s++;
return dst;
}
char* strcat(char * dest, const char * src)
{
char *tmp = dest;
while (*dest)
dest++;
while ((*dest++ = *src++) != '\0')
;
return tmp;
}
int strlen(const char* string)
{
register int i = 0;
while (string[i] != '\0')
++i;
return i;
}

View File

@@ -0,0 +1,528 @@
/*
* head.S -- Bootloader Entry point
*
* Copyright (C) 1998, 1999 Gabriel Paubert, paubert@iram.es
*
* Modified to compile in RTEMS development environment
* by Eric Valette
*
* Copyright (C) 1999 Eric Valette. valette@crf.canon.fr
*
* The license and distribution terms for this file may be
* found in found in the file LICENSE in this distribution or at
* http://www.OARcorp.com/rtems/license.html.
*
* $Id$
*/
#include <sys/types.h>
#include <string.h>
#include <libcpu/cpu.h>
#include "bootldr.h"
#include <libcpu/spr.h>
#include "zlib.h"
#include <libcpu/page.h>
#include <libcpu/byteorder.h>
SPR_RW(DEC)
SPR_RO(PVR)
struct inode;
struct wait_queue;
struct buffer_head;
typedef struct { int counter; } atomic_t;
typedef struct page {
/* these must be first (free area handling) */
struct page *next;
struct page *prev;
struct inode *inode;
unsigned long offset;
struct page *next_hash;
atomic_t count;
unsigned long flags; /* atomic flags, some possibly updated asynchronously */
struct wait_queue *wait;
struct page **pprev_hash;
struct buffer_head * buffers;
} mem_map_t;
extern opaque mm_private, pci_private, v86_private, console_private;
#define CONSOLE_ON_SERIAL "console=ttyS0"
extern struct console_io vacuum_console_functions;
extern opaque log_console_setup, serial_console_setup, vga_console_setup;
boot_data __bd = {0, 0, 0, 0, 0, 0, 0, 0,
32, 0, 0, 0, 0, 0, 0,
&mm_private,
NULL,
&pci_private,
NULL,
&v86_private,
"root=/dev/hdc1"
};
static void exit(void) __attribute__((noreturn));
static void exit(void) {
printk("\nOnly way out is to press the reset button!\n");
asm volatile("": : :"memory");
while(1);
}
void hang(const char *s, u_long x, ctxt *p) {
u_long *r1;
#ifdef DEBUG
print_all_maps("\nMemory mappings at exception time:\n");
#endif
printk("%s %lx NIP: %p LR: %p\n"
"Callback trace (stack:return address)\n",
s, x, (void *) p->nip, (void *) p->lr);
asm volatile("lwz %0,0(1); lwz %0,0(%0); lwz %0,0(%0)": "=b" (r1));
while(r1) {
printk(" %p:%p\n", r1, (void *) r1[1]);
r1 = (u_long *) *r1;
}
exit();
};
void *zalloc(void *x, unsigned items, unsigned size)
{
void *p = salloc(items*size);
if (!p) {
printk("oops... not enough memory for gunzip\n");
}
return p;
}
void zfree(void *x, void *addr, unsigned nb)
{
sfree(addr);
}
#define HEAD_CRC 2
#define EXTRA_FIELD 4
#define ORIG_NAME 8
#define COMMENT 0x10
#define RESERVED 0xe0
#define DEFLATED 8
void gunzip(void *dst, int dstlen, unsigned char *src, int *lenp)
{
z_stream s;
int r, i, flags;
/* skip header */
i = 10;
flags = src[3];
if (src[2] != DEFLATED || (flags & RESERVED) != 0) {
printk("bad gzipped data\n");
exit();
}
if ((flags & EXTRA_FIELD) != 0)
i = 12 + src[10] + (src[11] << 8);
if ((flags & ORIG_NAME) != 0)
while (src[i++] != 0)
;
if ((flags & COMMENT) != 0)
while (src[i++] != 0)
;
if ((flags & HEAD_CRC) != 0)
i += 2;
if (i >= *lenp) {
printk("gunzip: ran out of data in header\n");
exit();
}
s.zalloc = zalloc;
s.zfree = zfree;
r = inflateInit2(&s, -MAX_WBITS);
if (r != Z_OK) {
printk("inflateInit2 returned %d\n", r);
exit();
}
s.next_in = src + i;
s.avail_in = *lenp - i;
s.next_out = dst;
s.avail_out = dstlen;
r = inflate(&s, Z_FINISH);
if (r != Z_OK && r != Z_STREAM_END) {
printk("inflate returned %d\n", r);
exit();
}
*lenp = s.next_out - (unsigned char *) dst;
inflateEnd(&s);
}
void decompress_kernel(int kernel_size, void * zimage_start, int len,
void * initrd_start, int initrd_len ) {
u_char *parea;
RESIDUAL* rescopy;
int zimage_size= len;
/* That's a mess, we have to copy the residual data twice just in
* case it happens to be in the low memory area where the kernel
* is going to be unpacked. Later we have to copy it back to
* lower addresses because only the lowest part of memory is mapped
* during boot.
*/
parea=__palloc(kernel_size, PA_LOW);
if(!parea) {
printk("Not enough memory to uncompress the kernel.");
exit();
}
/* Note that this clears the bss as a side effect, so some code
* with ugly special case for SMP could be removed from the kernel!
*/
memset(parea, 0, kernel_size);
printk("\nUncompressing the kernel...\n");
rescopy=salloc(sizeof(RESIDUAL));
/* Let us hope that residual data is aligned on word boundary */
*rescopy = *bd->residual;
bd->residual = (void *)PAGE_ALIGN(kernel_size);
gunzip(parea, kernel_size, zimage_start, &zimage_size);
bd->of_entry = 0;
bd->load_address = 0;
bd->r6 = (char *)bd->residual+PAGE_ALIGN(sizeof(RESIDUAL));
bd->r7 = bd->r6+strlen(bd->cmd_line);
if ( initrd_len ) {
/* We have to leave some room for the hash table and for the
* whole array of struct page. The hash table would be better
* located at the end of memory if possible. With some bridges
* DMA from the last pages of memory is slower because
* prefetching from PCI has to be disabled to avoid accessing
* non existing memory. So it is the ideal place to put the
* hash table.
*/
unsigned tmp = rescopy->TotalMemory;
/* It's equivalent to tmp & (-tmp), but using the negation
* operator on unsigned variables looks so ugly.
*/
if ((tmp & (~tmp+1)) != tmp) tmp <<= 1; /* Next power of 2 */
tmp /= 256; /* Size of hash table */
if (tmp> (2<<20)) tmp=2<<20;
tmp = tmp*2 + 0x40000; /* Alignment can double size + 256 kB */
tmp += (rescopy->TotalMemory / PAGE_SIZE)
* sizeof(struct page);
bd->load_address = (void *)PAGE_ALIGN((int)bd->r7 + tmp);
bd->of_entry = (char *)bd->load_address+initrd_len;
}
#ifdef DEBUG
printk("Kernel at 0x%p, size=0x%x\n", NULL, kernel_size);
printk("Initrd at 0x%p, size=0x%x\n",bd->load_address, initrd_len);
printk("Residual data at 0x%p\n", bd->residual);
printk("Command line at 0x%p\n",bd->r6);
#endif
printk("done\nNow booting...\n");
MMUoff(); /* We need to access address 0 ! */
codemove(0, parea, kernel_size, bd->cache_lsize);
codemove(bd->residual, rescopy, sizeof(RESIDUAL), bd->cache_lsize);
codemove(bd->r6, bd->cmd_line, sizeof(bd->cmd_line), bd->cache_lsize);
/* codemove checks for 0 length */
codemove(bd->load_address, initrd_start, initrd_len, bd->cache_lsize);
}
void
setup_hw(void)
{
char *cp, ch;
register RESIDUAL * res;
/* PPC_DEVICE * nvram; */
struct pci_dev *p, *default_vga;
int timer, err;
u_short default_vga_cmd;
static unsigned int indic;
indic = 0;
res=bd->residual;
default_vga=NULL;
default_vga_cmd = 0;
#define vpd res->VitalProductData
if (_read_PVR()>>16 != 1) {
if ( res && vpd.ProcessorBusHz ) {
ticks_per_ms = vpd.ProcessorBusHz/
(vpd.TimeBaseDivisor ? vpd.TimeBaseDivisor : 4000);
} else {
ticks_per_ms = 16500; /* assume 66 MHz on bus */
}
}
select_console(CONSOLE_LOG);
/* We check that the keyboard is present and immediately
* select the serial console if not.
*/
err = kbdreset();
if (err) select_console(CONSOLE_SERIAL);
printk("\nModel: %s\nSerial: %s\n"
"Processor/Bus frequencies (Hz): %ld/%ld\n"
"Time Base Divisor: %ld\n"
"Memory Size: %x\n",
vpd.PrintableModel,
vpd.Serial,
vpd.ProcessorHz,
vpd.ProcessorBusHz,
(vpd.TimeBaseDivisor ? vpd.TimeBaseDivisor : 4000),
res->TotalMemory);
printk("Original MSR: %lx\nOriginal HID0: %lx\nOriginal R31: %lx\n",
bd->o_msr, bd->o_hid0, bd->o_r31);
/* This reconfigures all the PCI subsystem */
pci_init();
/* The Motorola NT firmware does not set the correct mem size */
if ( vpd.FirmwareSupplier == 0x10000 ) {
int memsize;
memsize = find_max_mem(bd->pci_devices);
if ( memsize != res->TotalMemory ) {
printk("Changed Memory size from %lx to %x\n",
res->TotalMemory, memsize);
res->TotalMemory = memsize;
res->GoodMemory = memsize;
}
}
#define ENABLE_VGA_USAGE
#undef ENABLE_VGA_USAGE
#ifdef ENABLE_VGA_USAGE
/* Find the primary VGA device, chosing the first one found
* if none is enabled. The basic loop structure has been copied
* from linux/drivers/char/bttv.c by Alan Cox.
*/
for (p = bd->pci_devices; p; p = p->next) {
u_short cmd;
if (p->class != PCI_CLASS_NOT_DEFINED_VGA &&
((p->class) >> 16 != PCI_BASE_CLASS_DISPLAY))
continue;
if (p->bus->number != 0) {
printk("VGA device not on bus 0 not initialized!\n");
continue;
}
/* Only one can be active in text mode, which for now will
* be assumed as equivalent to having I/O response enabled.
*/
pci_read_config_word(p, PCI_COMMAND, &cmd);
if(cmd & PCI_COMMAND_IO || !default_vga) {
default_vga=p;
default_vga_cmd=cmd;
}
}
/* Disable the enabled VGA device, if any. */
if (default_vga)
pci_write_config_word(default_vga, PCI_COMMAND,
default_vga_cmd&
~(PCI_COMMAND_IO|PCI_COMMAND_MEMORY));
init_v86();
/* Same loop copied from bttv.c, this time doing the serious work */
for (p = bd->pci_devices; p; p = p->next) {
u_short cmd;
if (p->class != PCI_CLASS_NOT_DEFINED_VGA &&
((p->class) >> 16 != PCI_BASE_CLASS_DISPLAY))
continue;
if (p->bus->number != 0) continue;
pci_read_config_word(p, PCI_COMMAND, &cmd);
pci_write_config_word(p, PCI_COMMAND,
cmd|PCI_COMMAND_IO|PCI_COMMAND_MEMORY);
printk("Calling the emulator.\n");
em86_main(p);
pci_write_config_word(p, PCI_COMMAND, cmd);
}
cleanup_v86_mess();
#endif
/* Reenable the primary VGA device */
if (default_vga) {
pci_write_config_word(default_vga, PCI_COMMAND,
default_vga_cmd|
(PCI_COMMAND_IO|PCI_COMMAND_MEMORY));
if (err) {
printk("Keyboard error %d, using serial console!\n",
err);
} else {
select_console(CONSOLE_VGA);
}
} else if (!err) {
select_console(CONSOLE_SERIAL);
if (bd->cmd_line[0] == '\0') {
strcat(&bd->cmd_line[0], CONSOLE_ON_SERIAL);
}
else {
int s = strlen (bd->cmd_line);
bd->cmd_line[s + 1] = ' ';
bd->cmd_line[s + 2] = '\0';
strcat(&bd->cmd_line[0], CONSOLE_ON_SERIAL);
}
}
#if 0
/* In the future we may use the NVRAM to store default
* kernel parameters.
*/
nvram=residual_find_device(~0UL, NULL, SystemPeripheral, NVRAM,
~0UL, 0);
if (nvram) {
PnP_TAG_PACKET * pkt;
switch (nvram->DevId.Interface) {
case IndirectNVRAM:
pkt=PnP_find_packet(res->DevicePnpHeap
+nvram->AllocatedOffset,
)
}
}
#endif
printk("\nRTEMS 4.x/PPC load: ");
timer = 0;
cp = bd->cmd_line+strlen(bd->cmd_line);
while (timer++ < 5*1000) {
if (debug_tstc()) {
while ((ch = debug_getc()) != '\n' && ch != '\r') {
if (ch == '\b' || ch == 0177) {
if (cp != bd->cmd_line) {
cp--;
printk("\b \b");
}
} else {
*cp++ = ch;
debug_putc(ch);
}
}
break; /* Exit 'timer' loop */
}
udelay(1000); /* 1 msec */
}
*cp = 0;
}
/* Functions to deal with the residual data */
static int same_DevID(unsigned short vendor,
unsigned short Number,
char * str)
{
static unsigned const char hexdigit[]="0123456789ABCDEF";
if (strlen(str)!=7) return 0;
if ( ( ((vendor>>10)&0x1f)+'A'-1 == str[0]) &&
( ((vendor>>5)&0x1f)+'A'-1 == str[1]) &&
( (vendor&0x1f)+'A'-1 == str[2]) &&
(hexdigit[(Number>>12)&0x0f] == str[3]) &&
(hexdigit[(Number>>8)&0x0f] == str[4]) &&
(hexdigit[(Number>>4)&0x0f] == str[5]) &&
(hexdigit[Number&0x0f] == str[6]) ) return 1;
return 0;
}
PPC_DEVICE *residual_find_device(unsigned long BusMask,
unsigned char * DevID,
int BaseType,
int SubType,
int Interface,
int n)
{
int i;
RESIDUAL *res = bd->residual;
if ( !res || !res->ResidualLength ) return NULL;
for (i=0; i<res->ActualNumDevices; i++) {
#define Dev res->Devices[i].DeviceId
if ( (Dev.BusId&BusMask) &&
(BaseType==-1 || Dev.BaseType==BaseType) &&
(SubType==-1 || Dev.SubType==SubType) &&
(Interface==-1 || Dev.Interface==Interface) &&
(DevID==NULL || same_DevID((Dev.DevId>>16)&0xffff,
Dev.DevId&0xffff, DevID)) &&
!(n--) ) return res->Devices+i;
#undef Dev
}
return 0;
}
PnP_TAG_PACKET *PnP_find_packet(unsigned char *p,
unsigned packet_tag,
int n)
{
unsigned mask, masked_tag, size;
if(!p) return 0;
if (tag_type(packet_tag)) mask=0xff; else mask=0xF8;
masked_tag = packet_tag&mask;
for(; *p != END_TAG; p+=size) {
if ((*p & mask) == masked_tag && !(n--))
return (PnP_TAG_PACKET *) p;
if (tag_type(*p))
size=ld_le16((unsigned short *)(p+1))+3;
else
size=tag_small_count(*p)+1;
}
return 0; /* not found */
}
PnP_TAG_PACKET *PnP_find_small_vendor_packet(unsigned char *p,
unsigned packet_type,
int n)
{
int next=0;
while (p) {
p = (unsigned char *) PnP_find_packet(p, 0x70, next);
if (p && p[1]==packet_type && !(n--))
return (PnP_TAG_PACKET *) p;
next = 1;
};
return 0; /* not found */
}
PnP_TAG_PACKET *PnP_find_large_vendor_packet(unsigned char *p,
unsigned packet_type,
int n)
{
int next=0;
while (p) {
p = (unsigned char *) PnP_find_packet(p, 0x84, next);
if (p && p[3]==packet_type && !(n--))
return (PnP_TAG_PACKET *) p;
next = 1;
};
return 0; /* not found */
}
/* Find out the amount of installed memory. For MPC105 and IBM 660 this
* can be done by finding the bank with the highest memory ending address
*/
int
find_max_mem( struct pci_dev *dev )
{
u_char banks,tmp;
int i, top, max;
max = 0;
for ( ; dev; dev = dev->next) {
if ( ((dev->vendor == PCI_VENDOR_ID_MOTOROLA) &&
(dev->device == PCI_DEVICE_ID_MOTOROLA_MPC105)) ||
((dev->vendor == PCI_VENDOR_ID_IBM) &&
(dev->device == 0x0037/*IBM 660 Bridge*/)) ) {
pci_read_config_byte(dev, 0xa0, &banks);
for (i = 0; i < 8; i++) {
if ( banks & (1<<i) ) {
pci_read_config_byte(dev, 0x90+i, &tmp);
top = tmp;
pci_read_config_byte(dev, 0x98+i, &tmp);
top |= (tmp&3)<<8;
if ( top > max ) max = top;
}
}
if ( max ) return ((max+1)<<20);
else return(0);
}
}
return(0);
}

View File

@@ -0,0 +1,982 @@
/*
* mm.c -- Crude memory management for early boot.
*
* Copyright (C) 1998, 1999 Gabriel Paubert, paubert@iram.es
*
* Modified to compile in RTEMS development environment
* by Eric Valette
*
* Copyright (C) 1999 Eric Valette. valette@crf.canon.fr
*
* The license and distribution terms for this file may be
* found in found in the file LICENSE in this distribution or at
* http://www.OARcorp.com/rtems/license.html.
*
* $Id$
*/
/* This code is a crude memory manager for early boot for LinuxPPC.
* As such, it does not try to perform many optimiztions depending
* on the processor, it only uses features which are common to
* all processors (no BATs...).
*
* On PreP platorms (the only ones on which it works for now),
* it maps 1:1 all RAM/ROM and I/O space as claimed by the
* residual data. The holes between these areas can be virtually
* remapped to any of these, since for some functions it is very handy
* to have virtually contiguous but physically discontiguous memory.
*
* Physical memory allocation is also very crude, since it's only
* designed to manage a small number of large chunks. For valloc/vfree
* and palloc/pfree, the unit of allocation is the 4kB page.
*
* The salloc/sfree has been added after tracing gunzip and seeing
* how it performed a very large number of small allocations.
* For these the unit of allocation is 8 bytes (the s stands for
* small or subpage). This memory is cleared when allocated.
*
*/
#include <sys/types.h>
#include <libcpu/spr.h>
#include "bootldr.h"
#include <libcpu/mmu.h>
#include <libcpu/page.h>
#include <limits.h>
/* We use our own kind of simple memory areas for the loader, but
* we want to avoid potential clashes with kernel includes.
* Here a map maps contiguous areas from base to end,
* the firstpte entry corresponds to physical address and has the low
* order bits set for caching and permission.
*/
typedef struct _map {
struct _map *next;
u_long base;
u_long end;
u_long firstpte;
} map;
/* The LSB of the firstpte entries on map lists other than mappings
* are constants which can be checked for debugging. All these constants
* have bit of weight 4 set, this bit is zero in the mappings list entries.
* Actually firstpte&7 value is:
* - 0 or 1 should not happen
* - 2 for RW actual virtual->physical mappings
* - 3 for RO actual virtual->physical mappings
* - 6 for free areas to be suballocated by salloc
* - 7 for salloc'ated areas
* - 4 or 5 for all others, in this case firtpte & 63 is
* - 4 for unused maps (on the free list)
* - 12 for free physical memory
* - 13 for physical memory in use
* - 20 for free virtual address space
* - 21 for allocated virtual address space
* - 28 for physical memory space suballocated by salloc
* - 29 for physical memory that can't be freed
*/
#define MAP_FREE_SUBS 6
#define MAP_USED_SUBS 7
#define MAP_FREE 4
#define MAP_FREE_PHYS 12
#define MAP_USED_PHYS 13
#define MAP_FREE_VIRT 20
#define MAP_USED_VIRT 21
#define MAP_SUBS_PHYS 28
#define MAP_PERM_PHYS 29
SPR_RW(SDR1);
SPR_RO(DSISR);
SPR_RO(DAR);
/* We need a few statically allocated free maps to bootstrap the
* memory managment */
static map free_maps[4] = {{free_maps+1, 0, 0, MAP_FREE},
{free_maps+2, 0, 0, MAP_FREE},
{free_maps+3, 0, 0, MAP_FREE},
{NULL, 0, 0, MAP_FREE}};
struct _mm_private {
void *sdr1;
u_long hashmask;
map *freemaps; /* Pool of unused map structs */
map *mappings; /* Sorted list of virtual->physical mappings */
map *physavail; /* Unallocated physical address space */
map *physused; /* Allocated physical address space */
map *physperm; /* Permanently allocated physical space */
map *virtavail; /* Unallocated virtual address space */
map *virtused; /* Allocated virtual address space */
map *sallocfree; /* Free maps for salloc */
map *sallocused; /* Used maps for salloc */
map *sallocphys; /* Physical areas used by salloc */
u_int hashcnt; /* Used to cycle in PTEG when they overflow */
} mm_private = {hashmask: 0xffc0,
freemaps: free_maps+0};
/* A simplified hash table entry declaration */
typedef struct _hash_entry {
int key;
u_long rpn;
} hash_entry;
void print_maps(map *, const char *);
/* The handler used for all exceptions although for now it is only
* designed to properly handle MMU interrupts to fill the hash table.
*/
void _handler(int vec, ctxt *p) {
map *area;
struct _mm_private *mm = (struct _mm_private *) bd->mm_private;
u_long vaddr, cause;
if (vec==4 || vec==7) { /* ISI exceptions are different */
vaddr = p->nip;
cause = p->msr;
} else { /* Valid for DSI and alignment exceptions */
vaddr = _read_DAR();
cause = _read_DSISR();
}
if (vec==3 || vec==4) {
/* Panic if the fault is not PTE not found. */
if (!(cause & 0x40000000)) {
MMUon();
printk("\nPanic: vector=%x, cause=%lx\n", vec, cause);
hang("Memory protection violation at ", vaddr, p);
}
for(area=mm->mappings; area; area=area->next) {
if(area->base<=vaddr && vaddr<=area->end) break;
}
if (area) {
u_long hash, vsid, rpn;
hash_entry volatile *hte, *_hte1;
u_int i, alt=0, flushva;
vsid = _read_SR((void *)vaddr);
rpn = (vaddr&PAGE_MASK)-area->base+area->firstpte;
hash = vsid<<6;
hash ^= (vaddr>>(PAGE_SHIFT-6))&0x3fffc0;
hash &= mm->hashmask;
/* Find an empty entry in the PTEG, else
* replace a random one.
*/
hte = (hash_entry *) ((u_long)(mm->sdr1)+hash);
for (i=0; i<8; i++) {
if (hte[i].key>=0) goto found;
}
hash ^= mm->hashmask;
alt = 0x40; _hte1 = hte;
hte = (hash_entry *) ((u_long)(mm->sdr1)+hash);
for (i=0; i<8; i++) {
if (hte[i].key>=0) goto found;
}
alt = 0;
hte = _hte1;
/* Chose a victim entry and replace it. There might be
* better policies to choose the victim, but in a boot
* loader we want simplicity as long as it works.
*
* We would not need to invalidate the TLB entry since
* the mapping is still valid. But this would be a mess
* when unmapping so we make sure that the TLB is a
* subset of the hash table under all circumstances.
*/
i = mm->hashcnt;
mm->hashcnt = (mm->hashcnt+1)%8;
/* Note that the hash is already complemented here ! */
flushva = (~(hash<<9)^((hte[i].key)<<5)) &0x3ff000;
if (hte[i].key&0x40) flushva^=0x3ff000;
flushva |= ((hte[i].key<<21)&0xf0000000)
| ((hte[i].key<<22)&0x0fc00000);
hte[i].key=0;
asm volatile("sync; tlbie %0; sync" : : "r" (flushva));
found:
hte[i].rpn = rpn;
asm volatile("eieio": : );
hte[i].key = 0x80000000|(vsid<<7)|alt|
((vaddr>>22)&0x3f);
return;
} else {
MMUon();
printk("\nPanic: vector=%x, cause=%lx\n", vec, cause);
hang("\nInvalid memory access attempt at ", vaddr, p);
}
} else {
MMUon();
printk("\nPanic: vector=%x, dsisr=%lx, faultaddr =%lx, msr=%lx opcode=%lx\n", vec,
cause, p->nip, p->msr, * ((unsigned int*) p->nip) );
if (vec == 7) {
unsigned int* ptr = ((unsigned int*) p->nip) - 4 * 10;
for (; ptr <= (((unsigned int*) p->nip) + 4 * 10); ptr ++)
printk("Hexdecimal code at address %x = %x\n", ptr, *ptr);
}
hang("Program or alignment exception at ", vaddr, p);
}
}
/* Generic routines for map handling.
*/
static inline
void free_map(map *p) {
struct _mm_private *mm = (struct _mm_private *) bd->mm_private;
if (!p) return;
p->next=mm->freemaps;
mm->freemaps=p;
p->firstpte=MAP_FREE;
}
/* Sorted insertion in linked list */
static
int insert_map(map **head, map *p) {
map *q = *head;
if (!p) return 0;
if (q && (q->base < p->base)) {
for(;q->next && q->next->base<p->base; q = q->next);
if ((q->end >= p->base) ||
(q->next && p->end>=q->next->base)) {
free_map(p);
printk("Overlapping areas!\n");
return 1;
}
p->next = q->next;
q->next = p;
} else { /* Insert at head */
if (q && (p->end >= q->base)) {
free_map(p);
printk("Overlapping areas!\n");
return 1;
}
p->next = q;
*head = p;
}
return 0;
}
/* Removal from linked list */
static
map *remove_map(map **head, map *p) {
map *q = *head;
if (!p || !q) return NULL;
if (q==p) {
*head = q->next;
return p;
}
for(;q && q->next!=p; q=q->next);
if (q) {
q->next=p->next;
return p;
} else {
return NULL;
}
}
static
map *remove_map_at(map **head, void * vaddr) {
map *p, *q = *head;
if (!vaddr || !q) return NULL;
if (q->base==(u_long)vaddr) {
*head = q->next;
return q;
}
while (q->next && q->next->base != (u_long)vaddr) q=q->next;
p=q->next;
if (p) q->next=p->next;
return p;
}
static inline
map * alloc_map_page(void) {
map *from, *p;
struct _mm_private *mm = (struct _mm_private *) bd->mm_private;
/* printk("Allocating new map page !"); */
/* Get the highest page */
for (from=mm->physavail; from && from->next; from=from->next);
if (!from) return NULL;
from->end -= PAGE_SIZE;
mm->freemaps = (map *) (from->end+1);
for(p=mm->freemaps; p<mm->freemaps+PAGE_SIZE/sizeof(map)-1; p++) {
p->next = p+1;
p->firstpte = MAP_FREE;
}
(p-1)->next=0;
/* Take the last one as pointer to self and insert
* the map into the permanent map list.
*/
p->firstpte = MAP_PERM_PHYS;
p->base=(u_long) mm->freemaps;
p->end = p->base+PAGE_SIZE-1;
insert_map(&mm->physperm, p);
if (from->end+1 == from->base)
free_map(remove_map(&mm->physavail, from));
return mm->freemaps;
}
static
map * alloc_map(void) {
map *p;
struct _mm_private * mm = (struct _mm_private *) bd->mm_private;
p = mm->freemaps;
if (!p) {
p=alloc_map_page();
}
if(p) mm->freemaps=p->next;
return p;
}
static
void coalesce_maps(map *p) {
while(p) {
if (p->next && (p->end+1 == p->next->base)) {
map *q=p->next;
p->end=q->end;
p->next=q->next;
free_map(q);
} else {
p = p->next;
}
}
}
/* These routines are used to find the free memory zones to avoid
* overlapping destructive copies when initializing.
* They work from the top because of the way we want to boot.
* In the following the term zone refers to the memory described
* by one or several contiguous so called segments in the
* residual data.
*/
#define STACK_PAGES 2
static inline u_long
find_next_zone(RESIDUAL *res, u_long lowpage, u_long flags) {
u_long i, newmin=0, size=0;
for(i=0; i<res->ActualNumMemSegs; i++) {
if (res->Segs[i].Usage & flags
&& res->Segs[i].BasePage<lowpage
&& res->Segs[i].BasePage>newmin) {
newmin=res->Segs[i].BasePage;
size=res->Segs[i].PageCount;
}
}
return newmin+size;
}
static inline u_long
find_zone_start(RESIDUAL *res, u_long highpage, u_long flags) {
u_long i;
int progress;
do {
progress=0;
for (i=0; i<res->ActualNumMemSegs; i++) {
if ( (res->Segs[i].BasePage+res->Segs[i].PageCount
== highpage)
&& res->Segs[i].Usage & flags) {
highpage=res->Segs[i].BasePage;
progress=1;
}
}
} while(progress);
return highpage;
}
/* The Motorola NT firmware does not provide any setting in the residual
* data about memory segment usage. The following table provides enough
* info so that this bootloader can work.
*/
MEM_MAP seg_fix[] = {
{ 0x2000, 0xFFF00, 0x00100 },
{ 0x0020, 0x02000, 0x7E000 },
{ 0x0008, 0x00800, 0x00168 },
{ 0x0004, 0x00000, 0x00005 },
{ 0x0001, 0x006F1, 0x0010F },
{ 0x0002, 0x006AD, 0x00044 },
{ 0x0010, 0x00005, 0x006A8 },
{ 0x0010, 0x00968, 0x00698 },
{ 0x0800, 0xC0000, 0x3F000 },
{ 0x0600, 0xBF800, 0x00800 },
{ 0x0500, 0x81000, 0x3E800 },
{ 0x0480, 0x80800, 0x00800 },
{ 0x0440, 0x80000, 0x00800 } };
/* The Motorola NT firmware does not set up all required info in the residual
* data. This routine changes some things in a way that the bootloader and
* linux are happy.
*/
void
fix_residual( RESIDUAL *res )
{
#if 0
PPC_DEVICE *hostbridge;
#endif
int i;
/* Missing memory segment information */
res->ActualNumMemSegs = sizeof(seg_fix)/sizeof(MEM_MAP);
for (i=0; i<res->ActualNumMemSegs; i++) {
res->Segs[i].Usage = seg_fix[i].Usage;
res->Segs[i].BasePage = seg_fix[i].BasePage;
res->Segs[i].PageCount = seg_fix[i].PageCount;
}
/* The following should be fixed in the current version of the
* kernel and of the bootloader.
*/
#if 0
/* PPCBug has this zero */
res->VitalProductData.CacheLineSize = 0;
/* Motorola NT firmware sets TimeBaseDivisor to 0 */
if ( res->VitalProductData.TimeBaseDivisor == 0 ) {
res->VitalProductData.TimeBaseDivisor = 4000;
}
/* Motorola NT firmware records the PCIBridge as a "PCIDEVICE" and
* sets "PCIBridgeDirect". This bootloader and linux works better if
* BusId = "PROCESSORDEVICE" and Interface = "PCIBridgeIndirect".
*/
hostbridge=residual_find_device(PCIDEVICE, NULL,
BridgeController,
PCIBridge, -1, 0);
if (hostbridge) {
hostbridge->DeviceId.BusId = PROCESSORDEVICE;
hostbridge->DeviceId.Interface = PCIBridgeIndirect;
}
#endif
}
/* This routine is the first C code called with very little stack space!
* Its goal is to find where the boot image can be moved. This will
* be the highest address with enough room.
*/
int early_setup(u_long image_size) {
register RESIDUAL *res = bd->residual;
u_long minpages = PAGE_ALIGN(image_size)>>PAGE_SHIFT;
/* Fix residual if we are loaded by Motorola NT firmware */
if ( res && res->VitalProductData.FirmwareSupplier == 0x10000 )
fix_residual( res );
/* FIXME: if OF we should do something different */
if( !bd->of_entry && res &&
res->ResidualLength <= sizeof(RESIDUAL) && res->Version == 0 ) {
u_long lowpage=ULONG_MAX, highpage;
u_long imghigh=0, stkhigh=0;
/* Find the highest and large enough contiguous zone
consisting of free and BootImage sections. */
/* Find 3 free areas of memory, one for the main image, one
* for the stack (STACK_PAGES), and page one to put the map
* structures. They are allocated from the top of memory.
* In most cases the stack will be put just below the image.
*/
while((highpage =
find_next_zone(res, lowpage, BootImage|Free))) {
lowpage=find_zone_start(res, highpage, BootImage|Free);
if ((highpage-lowpage)>minpages &&
highpage>imghigh) {
imghigh=highpage;
highpage -=minpages;
}
if ((highpage-lowpage)>STACK_PAGES &&
highpage>stkhigh) {
stkhigh=highpage;
highpage-=STACK_PAGES;
}
}
bd->image = (void *)((imghigh-minpages)<<PAGE_SHIFT);
bd->stack=(void *) (stkhigh<<PAGE_SHIFT);
/* The code mover is put at the lowest possible place
* of free memory. If this corresponds to the loaded boot
* partition image it does not matter because it overrides
* the unused part of it (x86 code).
*/
bd->mover=(void *) (lowpage<<PAGE_SHIFT);
/* Let us flush the caches in all cases. After all it should
* not harm even on 601 and we don't care about performance.
* Right now it's easy since all processors have a line size
* of 32 bytes. Once again residual data has proved unreliable.
*/
bd->cache_lsize = 32;
}
/* For now we always assume that it's succesful, we should
* handle better the case of insufficient memory.
*/
return 0;
}
void * valloc(u_long size) {
map *p, *q;
struct _mm_private * mm = (struct _mm_private *) bd->mm_private;
if (size==0) return NULL;
size=PAGE_ALIGN(size)-1;
for (p=mm->virtavail; p; p=p->next) {
if (p->base+size <= p->end) break;
}
if(!p) return NULL;
q=alloc_map();
q->base=p->base;
q->end=q->base+size;
q->firstpte=MAP_USED_VIRT;
insert_map(&mm->virtused, q);
if (q->end==p->end) free_map(remove_map(&mm->virtavail, p));
else p->base += size+1;
return (void *)q->base;
}
static
void vflush(map *virtmap) {
struct _mm_private * mm = (struct _mm_private *) bd->mm_private;
u_long i, limit=(mm->hashmask>>3)+8;
hash_entry volatile *p=(hash_entry *) mm->sdr1;
/* PTE handling is simple since the processor never update
* the entries. Writable pages always have the C bit set and
* all valid entries have the R bit set. From the processor
* point of view the hash table is read only.
*/
for (i=0; i<limit; i++) {
if (p[i].key<0) {
u_long va;
va = ((i<<9)^((p[i].key)<<5)) &0x3ff000;
if (p[i].key&0x40) va^=0x3ff000;
va |= ((p[i].key<<21)&0xf0000000)
| ((p[i].key<<22)&0x0fc00000);
if (va>=virtmap->base && va<=virtmap->end) {
p[i].key=0;
asm volatile("sync; tlbie %0; sync" : :
"r" (va));
}
}
}
}
void vfree(void *vaddr) {
map *physmap, *virtmap; /* Actual mappings pertaining to this vm */
struct _mm_private * mm = (struct _mm_private *) bd->mm_private;
/* Flush memory queues */
asm volatile("sync": : : "memory");
virtmap = remove_map_at(&mm->virtused, vaddr);
if (!virtmap) return;
/* Remove mappings corresponding to virtmap */
for (physmap=mm->mappings; physmap; ) {
map *nextmap=physmap->next;
if (physmap->base>=virtmap->base
&& physmap->base<virtmap->end) {
free_map(remove_map(&mm->mappings, physmap));
}
physmap=nextmap;
}
vflush(virtmap);
virtmap->firstpte= MAP_FREE_VIRT;
insert_map(&mm->virtavail, virtmap);
coalesce_maps(mm->virtavail);
}
void vunmap(void *vaddr) {
map *physmap, *virtmap; /* Actual mappings pertaining to this vm */
struct _mm_private *mm = (struct _mm_private *) bd->mm_private;
/* Flush memory queues */
asm volatile("sync": : : "memory");
/* vaddr must be within one of the vm areas in use and
* then must correspond to one of the physical areas
*/
for (virtmap=mm->virtused; virtmap; virtmap=virtmap->next) {
if (virtmap->base<=(u_long)vaddr &&
virtmap->end>=(u_long)vaddr) break;
}
if (!virtmap) return;
physmap = remove_map_at(&mm->mappings, vaddr);
if(!physmap) return;
vflush(physmap);
free_map(physmap);
}
int vmap(void *vaddr, u_long p, u_long size) {
map *q;
struct _mm_private *mm = (struct _mm_private *) bd->mm_private;
size=PAGE_ALIGN(size);
if(!size) return 1;
/* Check that the requested area fits in one vm image */
for (q=mm->virtused; q; q=q->next) {
if ((q->base <= (u_long)vaddr) &&
(q->end>=(u_long)vaddr+size -1)) break;
}
if (!q) return 1;
q= alloc_map();
if (!q) return 1;
q->base = (u_long)vaddr;
q->end = (u_long)vaddr+size-1;
q->firstpte = p;
return insert_map(&mm->mappings, q);
}
static
void create_identity_mappings(int type, int attr) {
u_long lowpage=ULONG_MAX, highpage;
struct _mm_private *mm = (struct _mm_private *) bd->mm_private;
RESIDUAL * res=bd->residual;
while((highpage = find_next_zone(res, lowpage, type))) {
map *p;
lowpage=find_zone_start(res, highpage, type);
p=alloc_map();
/* Do not map page 0 to catch null pointers */
lowpage = lowpage ? lowpage : 1;
p->base=lowpage<<PAGE_SHIFT;
p->end=(highpage<<PAGE_SHIFT)-1;
p->firstpte = (lowpage<<PAGE_SHIFT)|attr;
insert_map(&mm->mappings, p);
}
}
static inline
void add_free_map(u_long base, u_long end) {
map *q=NULL;
struct _mm_private *mm = (struct _mm_private *) bd->mm_private;
if (base<end) q=alloc_map();
if (!q) return;
q->base=base;
q->end=end-1;
q->firstpte=MAP_FREE_VIRT;
insert_map(&mm->virtavail, q);
}
static inline
void create_free_vm(void) {
map *p;
struct _mm_private *mm = (struct _mm_private *) bd->mm_private;
u_long vaddr=PAGE_SIZE; /* Never map vaddr 0 */
for(p=mm->mappings; p; p=p->next) {
add_free_map(vaddr, p->base);
vaddr=p->end+1;
}
/* Special end of memory case */
if (vaddr) add_free_map(vaddr,0);
}
/* Memory management initialization.
* Set up the mapping lists.
*/
static inline
void add_perm_map(u_long start, u_long size) {
struct _mm_private *mm = (struct _mm_private *) bd->mm_private;
map *p=alloc_map();
p->base = start;
p->end = start + size - 1;
p->firstpte = MAP_PERM_PHYS;
insert_map(& mm->physperm , p);
}
void mm_init(u_long image_size)
{
u_long lowpage=ULONG_MAX, highpage;
struct _mm_private *mm = (struct _mm_private *) bd->mm_private;
RESIDUAL * res=bd->residual;
extern void (tlb_handlers)(void);
extern void (_handler_glue)(void);
int i;
map *p;
/* The checks are simplified by the fact that the image
* and stack area are always allocated at the upper end
* of a free block.
*/
while((highpage = find_next_zone(res, lowpage, BootImage|Free))) {
lowpage=find_zone_start(res, highpage, BootImage|Free);
if ( ( ((u_long)bd->image+PAGE_ALIGN(image_size))>>PAGE_SHIFT)
== highpage) {
highpage=(u_long)(bd->image)>>PAGE_SHIFT;
add_perm_map((u_long)bd->image, image_size);
}
if ( (( u_long)bd->stack>>PAGE_SHIFT) == highpage) {
highpage -= STACK_PAGES;
add_perm_map(highpage<<PAGE_SHIFT,
STACK_PAGES*PAGE_SIZE);
}
/* Protect the interrupt handlers that we need ! */
if (lowpage<2) lowpage=2;
/* Check for the special case of full area! */
if (highpage>lowpage) {
p = alloc_map();
p->base = lowpage<<PAGE_SHIFT;
p->end = (highpage<<PAGE_SHIFT)-1;
p->firstpte=MAP_FREE_PHYS;
insert_map(&mm->physavail, p);
}
}
/* Allocate the hash table */
mm->sdr1=__palloc(0x10000, PA_PERM|16);
_write_SDR1((u_long)mm->sdr1);
memset(mm->sdr1, 0, 0x10000);
mm->hashmask = 0xffc0;
/* Setup the segment registers as we want them */
for (i=0; i<16; i++) _write_SR(i, (void *)(i<<28));
/* Create the maps for the physical memory, firwmarecode does not
* seem to be necessary. ROM is mapped read-only to reduce the risk
* of reprogramming it because it's often Flash and some are
* amazingly easy to overwrite.
*/
create_identity_mappings(BootImage|Free|FirmwareCode|FirmwareHeap|
FirmwareStack, PTE_RAM);
create_identity_mappings(SystemROM, PTE_ROM);
create_identity_mappings(IOMemory|SystemIO|SystemRegs|
PCIAddr|PCIConfig|ISAAddr, PTE_IO);
create_free_vm();
/* Install our own MMU and trap handlers. */
codemove((void *) 0x300, _handler_glue, 0x100, bd->cache_lsize);
codemove((void *) 0x400, _handler_glue, 0x100, bd->cache_lsize);
codemove((void *) 0x600, _handler_glue, 0x100, bd->cache_lsize);
codemove((void *) 0x700, _handler_glue, 0x100, bd->cache_lsize);
}
void * salloc(u_long size) {
map *p, *q;
struct _mm_private *mm = (struct _mm_private *) bd->mm_private;
if (size==0) return NULL;
size = (size+7)&~7;
for (p=mm->sallocfree; p; p=p->next) {
if (p->base+size <= p->end) break;
}
if(!p) {
void *m;
m = __palloc(size, PA_SUBALLOC);
p = alloc_map();
if (!m && !p) return NULL;
p->base = (u_long) m;
p->firstpte = MAP_FREE_SUBS;
p->end = (u_long)m+PAGE_ALIGN(size)-1;
insert_map(&mm->sallocfree, p);
coalesce_maps(mm->sallocfree);
coalesce_maps(mm->sallocphys);
};
q=alloc_map();
q->base=p->base;
q->end=q->base+size-1;
q->firstpte=MAP_USED_SUBS;
insert_map(&mm->sallocused, q);
if (q->end==p->end) free_map(remove_map(&mm->sallocfree, p));
else p->base += size;
memset((void *)q->base, 0, size);
return (void *)q->base;
}
void sfree(void *p) {
map *q;
struct _mm_private *mm = (struct _mm_private *) bd->mm_private;
q=remove_map_at(&mm->sallocused, p);
if (!q) return;
q->firstpte=MAP_FREE_SUBS;
insert_map(&mm->sallocfree, q);
coalesce_maps(mm->sallocfree);
}
/* first/last area fit, flags is a power of 2 indicating the required
* alignment. The algorithms are stupid because we expect very little
* fragmentation of the areas, if any. The unit of allocation is the page.
* The allocation is by default performed from higher addresses down,
* unless flags&PA_LOW is true.
*/
void * __palloc(u_long size, int flags)
{
u_long mask = ((1<<(flags&PA_ALIGN_MASK))-1);
map *newmap, *frommap, *p, *splitmap=0;
map **queue;
u_long qflags;
struct _mm_private *mm = (struct _mm_private *) bd->mm_private;
/* Asking for a size which is not a multiple of the alignment
is likely to be an error. */
if (size & mask) return NULL;
size = PAGE_ALIGN(size);
if(!size) return NULL;
if (flags&PA_SUBALLOC) {
queue = &mm->sallocphys;
qflags = MAP_SUBS_PHYS;
} else if (flags&PA_PERM) {
queue = &mm->physperm;
qflags = MAP_PERM_PHYS;
} else {
queue = &mm->physused;
qflags = MAP_USED_PHYS;
}
/* We need to allocate that one now so no two allocations may attempt
* to take the same memory simultaneously. Alloc_map_page does
* not call back here to avoid infinite recursion in alloc_map.
*/
if (mask&PAGE_MASK) {
splitmap=alloc_map();
if (!splitmap) return NULL;
}
for (p=mm->physavail, frommap=NULL; p; p=p->next) {
u_long high = p->end;
u_long limit = ((p->base+mask)&~mask) + size-1;
if (high>=limit && ((p->base+mask)&~mask)+size>p->base) {
frommap = p;
if (flags&PA_LOW) break;
}
}
if (!frommap) {
if (splitmap) free_map(splitmap);
return NULL;
}
newmap=alloc_map();
if (flags&PA_LOW) {
newmap->base = (frommap->base+mask)&~mask;
} else {
newmap->base = (frommap->end +1 - size) & ~mask;
}
newmap->end = newmap->base+size-1;
newmap->firstpte = qflags;
/* Add a fragment if we don't allocate until the end. */
if (splitmap) {
splitmap->base=newmap->base+size;
splitmap->end=frommap->end;
splitmap->firstpte= MAP_FREE_PHYS;
frommap->end=newmap->base-1;
} else if (flags & PA_LOW) {
frommap->base=newmap->base+size;
} else {
frommap->end=newmap->base-1;
}
/* Remove a fragment if it becomes empty. */
if (frommap->base == frommap->end+1) {
free_map(remove_map(&mm->physavail, frommap));
}
if (splitmap) {
if (splitmap->base == splitmap->end+1) {
free_map(remove_map(&mm->physavail, splitmap));
} else {
insert_map(&mm->physavail, splitmap);
}
}
insert_map(queue, newmap);
return (void *) newmap->base;
}
void pfree(void * p) {
map *q;
struct _mm_private *mm = (struct _mm_private *) bd->mm_private;
q=remove_map_at(&mm->physused, p);
if (!q) return;
q->firstpte=MAP_FREE_PHYS;
insert_map(&mm->physavail, q);
coalesce_maps(mm->physavail);
}
#ifdef DEBUG
/* Debugging functions */
void print_maps(map *chain, const char *s) {
map *p;
printk("%s",s);
for(p=chain; p; p=p->next) {
printk(" %08lx-%08lx: %08lx\n",
p->base, p->end, p->firstpte);
}
}
void print_all_maps(const char * s) {
u_long freemaps;
struct _mm_private *mm = (struct _mm_private *) bd->mm_private;
map *free;
printk("%s",s);
print_maps(mm->mappings, " Currently defined mappings:\n");
print_maps(mm->physavail, " Currently available physical areas:\n");
print_maps(mm->physused, " Currently used physical areas:\n");
print_maps(mm->virtavail, " Currently available virtual areas:\n");
print_maps(mm->virtused, " Currently used virtual areas:\n");
print_maps(mm->physperm, " Permanently used physical areas:\n");
print_maps(mm->sallocphys, " Physical memory used for salloc:\n");
print_maps(mm->sallocfree, " Memory available for salloc:\n");
print_maps(mm->sallocused, " Memory allocated through salloc:\n");
for (freemaps=0, free=mm->freemaps; free; freemaps++, free=free->next);
printk(" %ld free maps.\n", freemaps);
}
void print_hash_table(void) {
struct _mm_private *mm = (struct _mm_private *) bd->mm_private;
hash_entry *p=(hash_entry *) mm->sdr1;
u_int i, valid=0;
for (i=0; i<((mm->hashmask)>>3)+8; i++) {
if (p[i].key<0) valid++;
}
printk("%u valid hash entries on pass 1.\n", valid);
valid = 0;
for (i=0; i<((mm->hashmask)>>3)+8; i++) {
if (p[i].key<0) valid++;
}
printk("%u valid hash entries on pass 2.\n"
" vpn:rpn_attr, p/s, pteg.i\n", valid);
for (i=0; i<((mm->hashmask)>>3)+8; i++) {
if (p[i].key<0) {
u_int pteg=(i>>3);
u_long vpn;
vpn = (pteg^((p[i].key)>>7)) &0x3ff;
if (p[i].key&0x40) vpn^=0x3ff;
vpn |= ((p[i].key<<9)&0xffff0000)
| ((p[i].key<<10)&0xfc00);
printk("%08lx:%08lx, %s, %5d.%d\n",
vpn, p[i].rpn, p[i].key&0x40 ? "sec" : "pri",
pteg, i%8);
}
}
}
#endif

View File

@@ -0,0 +1,931 @@
/*
* pci.c -- Crude pci handling for early boot.
*
* Copyright (C) 1998, 1999 Gabriel Paubert, paubert@iram.es
*
* Modified to compile in RTEMS development environment
* by Eric Valette
*
* Copyright (C) 1999 Eric Valette. valette@crf.canon.fr
*
* The license and distribution terms for this file may be
* found in found in the file LICENSE in this distribution or at
* http://www.OARcorp.com/rtems/license.html.
*
* $Id$
*/
#include <sys/types.h>
#include <libcpu/spr.h>
#include "bootldr.h"
#include "pci.h"
#include <libcpu/io.h>
#include <bsp/consoleIo.h>
typedef unsigned int u32;
/*#define DEBUG*/
/* Used to reorganize PCI space on stupid machines which spread resources
* across a wide address space. This is bad when P2P bridges are present
* or when it limits the mappings that a resource hog like a PCI<->VME
* bridge can use.
*/
typedef struct _pci_resource {
struct _pci_resource *next;
struct pci_dev *dev;
u_long base; /* will be 64 bits on 64 bits machines */
u_long size;
u_char type; /* 1 is I/O else low order 4 bits of the memory type */
u_char reg; /* Register # in conf space header */
u_short cmd; /* Original cmd byte */
} pci_resource;
typedef struct _pci_area {
struct _pci_area *next;
u_long start;
u_long end;
struct pci_bus *bus;
u_int flags;
} pci_area;
typedef struct _pci_area_head {
pci_area *head;
u_long mask;
int high; /* To allocate from top */
} pci_area_head;
#define PCI_AREA_PREFETCHABLE 0
#define PCI_AREA_MEMORY 1
#define PCI_AREA_IO 2
struct _pci_private {
volatile u_int * config_addr;
volatile u_char * config_data;
struct pci_dev **last_dev_p;
struct pci_bus pci_root;
pci_resource *resources;
pci_area_head io, mem;
} pci_private = {
config_addr: NULL,
config_data: (volatile u_char *) 0x80800000,
last_dev_p: NULL,
resources: NULL,
io: {NULL, 0xfff, 0},
mem: {NULL, 0xfffff, 0}
};
#define pci ((struct _pci_private *)(bd->pci_private))
#define pci_root pci->pci_root
#if !defined(DEBUG)
#undef PCI_DEBUG
/*
#else
#define PCI_DEBUG
*/
#endif
#if defined(PCI_DEBUG)
static void
print_pci_resources(const char *s) {
pci_resource *p;
printk("%s", s);
for (p=pci->resources; p; p=p->next) {
printk(" %p:%p %06x %08lx %08lx %d\n",
p, p->next,
(p->dev->devfn<<8)+(p->dev->bus->number<<16)
+0x10+p->reg*4,
p->base,
p->size,
p->type);
}
}
static void
print_pci_area(pci_area *p) {
for (; p; p=p->next) {
printk(" %p:%p %p %08lx %08lx\n",
p, p->next, p->bus, p->start, p->end);
}
}
static void
print_pci_areas(const char *s) {
printk("%s PCI I/O areas:\n",s);
print_pci_area(pci->io.head);
printk(" PCI memory areas:\n");
print_pci_area(pci->mem.head);
}
#else
#define print_pci_areas(x)
#define print_pci_resources(x)
#endif
/* Maybe there are some devices who use a size different
* from the alignment. For now we assume both are the same.
* The blacklist might be used for other weird things in the future too,
* since weird non PCI complying devices seem to proliferate these days.
*/
struct blacklist_entry {
u_short vendor, device;
u_char reg;
u_long actual_size;
};
#define BLACKLIST(vid, did, breg, actual_size) \
{PCI_VENDOR_ID_##vid, PCI_DEVICE_ID_##vid##_##did, breg, actual_size}
static struct blacklist_entry blacklist[] = {
BLACKLIST(S3, TRIO, 0, 0x04000000),
{0xffff, 0, 0, 0}
};
/* This function filters resources and then inserts them into a list of
* configurable pci resources.
*/
#define AREA(r) \
(((r->type&PCI_BASE_ADDRESS_SPACE)==PCI_BASE_ADDRESS_SPACE_IO) ? PCI_AREA_IO :\
((r->type&PCI_BASE_ADDRESS_MEM_PREFETCH) ? PCI_AREA_PREFETCHABLE :\
PCI_AREA_MEMORY))
static int insert_before(pci_resource *e, pci_resource *t) {
if (e->dev->bus->number != t->dev->bus->number)
return e->dev->bus->number > t->dev->bus->number;
if (AREA(e) != AREA(t)) return AREA(e)<AREA(t);
return (e->size > t->size);
}
static void insert_resource(pci_resource *r) {
struct blacklist_entry *b;
pci_resource *p;
if (!r) return;
/* First fixup in case we have a blacklist entry. Note that this
* may temporarily leave a resource in an inconsistent state: with
* (base & (size-1)) !=0. This is harmless.
*/
for (b=blacklist; b->vendor!=0xffff; b++) {
if ((r->dev->vendor==b->vendor) &&
(r->dev->device==b->device) &&
(r->reg==b->reg)) {
r->size=b->actual_size;
break;
}
}
/* Motorola NT firmware does not configure pci devices which are not
* required for booting, others do. For now:
* - allocated devices in the ISA range (64kB I/O, 16Mb memory)
* but non zero base registers are left as is.
* - all other registers, whether already allocated or not, are
* reallocated unless they require an inordinate amount of
* resources (>256 Mb for memory >64kB for I/O). These
* devices with too large mapping requirements are simply ignored
* and their bases are set to 0. This should disable the
* corresponding decoders according to the PCI specification.
* Many devices are buggy in this respect, however, but the
* limits have hopefully been set high enough to avoid problems.
*/
if ((r->type==PCI_BASE_ADDRESS_SPACE_IO)
? (r->base && r->base <0x10000)
: (r->base && r->base <0x1000000)) {
sfree(r);
return;
}
if ((r->type==PCI_BASE_ADDRESS_SPACE_IO)
? (r->size >= 0x10000)
: (r->size >= 0x10000000)) {
r->size = 0;
r->base = 0;
}
/* Now insert into the list sorting by
* 1) decreasing bus number
* 2) space: prefetchable memory, non-prefetchable and finally I/O
* 3) decreasing size
*/
if (!pci->resources || insert_before(r, pci->resources)) {
r->next = pci->resources;
pci->resources=r;
} else {
for (p=pci->resources; p->next; p=p->next) {
if (insert_before(r, p->next)) break;
}
r->next=p->next;
p->next=r;
}
}
/* This version only works for bus 0. I don't have any P2P bridges to test
* a more sophisticated version which has therefore not been implemented.
* Prefetchable memory is not yet handled correctly either.
* And several levels of PCI bridges much less even since there must be
* allocated together to be able to setup correctly the top bridge.
*/
static u_long find_range(u_char bus, u_char type,
pci_resource **first,
pci_resource **past, u_int *flags) {
pci_resource *p;
u_long total=0;
u_int fl=0;
for (p=pci->resources; p; p=p->next) {
if ((p->dev->bus->number == bus) &&
AREA(p)==type) break;
}
*first = p;
for (; p; p=p->next) {
if ((p->dev->bus->number != bus) ||
AREA(p)!=type || p->size == 0) break;
total = total+p->size;
fl |= 1<<p->type;
}
*past = p;
/* This will be used later to tell whether there are any 32 bit
* devices in an area which could be mapped higher than 4Gb
* on 64 bits architectures
*/
*flags = fl;
return total;
}
static inline void init_free_area(pci_area_head *h, u_long start,
u_long end, u_int mask, int high) {
pci_area *p;
p = salloc(sizeof(pci_area));
if (!p) return;
h->head = p;
p->next = NULL;
p->start = (start+mask)&~mask;
p->end = (end-mask)|mask;
p->bus = NULL;
h->mask = mask;
h->high = high;
}
static void insert_area(pci_area_head *h, pci_area *p) {
pci_area *q = h->head;
if (!p) return;
if (q && (q->start< p->start)) {
for(;q->next && q->next->start<p->start; q = q->next);
if ((q->end >= p->start) ||
(q->next && p->end>=q->next->start)) {
sfree(p);
printk("Overlapping pci areas!\n");
return;
}
p->next = q->next;
q->next = p;
} else { /* Insert at head */
if (q && (p->end >= q->start)) {
sfree(p);
printk("Overlapping pci areas!\n");
return;
}
p->next = q;
h->head = p;
}
}
static
void remove_area(pci_area_head *h, pci_area *p) {
pci_area *q = h->head;
if (!p || !q) return;
if (q==p) {
h->head = q->next;
return;
}
for(;q && q->next!=p; q=q->next);
if (q) q->next=p->next;
}
static pci_area * alloc_area(pci_area_head *h, struct pci_bus *bus,
u_long required, u_long mask, u_int flags) {
pci_area *p;
pci_area *from, *split, *new;
required = (required+h->mask) & ~h->mask;
for (p=h->head, from=NULL; p; p=p->next) {
u_long l1 = ((p->start+required+mask)&~mask)-1;
u_long l2 = ((p->start+mask)&~mask)+required-1;
/* Allocated areas point to the bus to which they pertain */
if (p->bus) continue;
if ((p->end)>=l1 || (p->end)>=l2) from=p;
if (from && !h->high) break;
}
if (!from) return NULL;
split = salloc(sizeof(pci_area));
new = salloc(sizeof(pci_area));
/* If allocation of new succeeds then allocation of split has
* also been successful (given the current mm algorithms) !
*/
if (!new) {
sfree(split);
return NULL;
}
new->bus = bus;
new->flags = flags;
/* Now allocate pci_space taking alignment into account ! */
if (h->high) {
u_long l1 = ((from->end+1)&~mask)-required;
u_long l2 = (from->end+1-required)&~mask;
new->start = (l1>l2) ? l1 : l2;
split->end = from->end;
from->end = new->start-1;
split->start = new->start+required;
new->end = new->start+required-1;
} else {
u_long l1 = ((from->start+mask)&~mask)+required-1;
u_long l2 = ((from->start+required+mask)&~mask)-1;
new->end = (l1<l2) ? l1 : l2;
split->start = from->start;
from->start = new->end+1;
new->start = new->end+1-required;
split->end = new->start-1;
}
if (from->end+1 == from->start) remove_area(h, from);
if (split->end+1 != split->start) {
split->bus = NULL;
insert_area(h, split);
} else {
sfree(split);
}
insert_area(h, new);
print_pci_areas("alloc_area called:\n");
return new;
}
static inline
void alloc_space(pci_area *p, pci_resource *r) {
if (p->start & (r->size-1)) {
r->base = p->end+1-r->size;
p->end -= r->size;
} else {
r->base = p->start;
p->start += r->size;
}
}
static void reconfigure_bus_space(u_char bus, u_char type, pci_area_head *h) {
pci_resource *first, *past, *r;
pci_area *area, tmp;
u_int flags;
u_int required = find_range(bus, type, &first, &past, &flags);
if (required==0) return;
area = alloc_area(h, first->dev->bus, required, first->size-1, flags);
if (!area) return;
tmp = *area;
for (r=first; r!=past; r=r->next) {
alloc_space(&tmp, r);
}
}
static void reconfigure_pci(void) {
pci_resource *r;
struct pci_dev *dev;
/* FIXME: for now memory is relocated from low, it's better
* to start from higher addresses.
*/
init_free_area(&pci->io, 0x10000, 0x7fffff, 0xfff, 0);
init_free_area(&pci->mem, 0x1000000, 0x3cffffff, 0xfffff, 0);
/* First reconfigure the I/O space, this will be more
* complex when there is more than 1 bus. And 64 bits
* devices are another kind of problems.
*/
reconfigure_bus_space(0, PCI_AREA_IO, &pci->io);
reconfigure_bus_space(0, PCI_AREA_MEMORY, &pci->mem);
reconfigure_bus_space(0, PCI_AREA_PREFETCHABLE, &pci->mem);
/* Now we have to touch the configuration space of all
* the devices to remap them better than they are right now.
* This is done in 3 steps:
* 1) first disable I/O and memory response of all devices
* 2) modify the base registers
* 3) restore the original PCI_COMMAND register.
*/
for (r=pci->resources; r; r= r->next) {
if (!r->dev->sysdata) {
r->dev->sysdata=r;
pci_read_config_word(r->dev, PCI_COMMAND, &r->cmd);
pci_write_config_word(r->dev, PCI_COMMAND,
r->cmd & ~(PCI_COMMAND_IO|
PCI_COMMAND_MEMORY));
}
}
for (r=pci->resources; r; r= r->next) {
pci_write_config_dword(r->dev,
PCI_BASE_ADDRESS_0+(r->reg<<2),
r->base);
if ((r->type&
(PCI_BASE_ADDRESS_SPACE|
PCI_BASE_ADDRESS_MEM_TYPE_MASK)) ==
(PCI_BASE_ADDRESS_SPACE_MEMORY|
PCI_BASE_ADDRESS_MEM_TYPE_64)) {
pci_write_config_dword(r->dev,
PCI_BASE_ADDRESS_1+
(r->reg<<2),
0);
}
}
for (dev=bd->pci_devices; dev; dev= dev->next) {
if (dev->sysdata) {
pci_write_config_word(dev, PCI_COMMAND,
((pci_resource *)dev->sysdata)
->cmd);
dev->sysdata=NULL;
}
}
}
static int
indirect_pci_read_config_byte(unsigned char bus, unsigned char dev_fn,
unsigned char offset, unsigned char *val) {
out_be32(pci->config_addr,
0x80|(bus<<8)|(dev_fn<<16)|((offset&~3)<<24));
*val=in_8(pci->config_data + (offset&3));
return PCIBIOS_SUCCESSFUL;
}
static int
indirect_pci_read_config_word(unsigned char bus, unsigned char dev_fn,
unsigned char offset, unsigned short *val) {
*val = 0xffff;
if (offset&1) return PCIBIOS_BAD_REGISTER_NUMBER;
out_be32(pci->config_addr,
0x80|(bus<<8)|(dev_fn<<16)|((offset&~3)<<24));
*val=in_le16((volatile u_short *)(pci->config_data + (offset&3)));
return PCIBIOS_SUCCESSFUL;
}
static int
indirect_pci_read_config_dword(unsigned char bus, unsigned char dev_fn,
unsigned char offset, unsigned int *val) {
*val = 0xffffffff;
if (offset&3) return PCIBIOS_BAD_REGISTER_NUMBER;
out_be32(pci->config_addr,
0x80|(bus<<8)|(dev_fn<<16)|(offset<<24));
*val=in_le32((volatile u_int *)pci->config_data);
return PCIBIOS_SUCCESSFUL;
}
static int
indirect_pci_write_config_byte(unsigned char bus, unsigned char dev_fn,
unsigned char offset, unsigned char val) {
out_be32(pci->config_addr,
0x80|(bus<<8)|(dev_fn<<16)|((offset&~3)<<24));
out_8(pci->config_data + (offset&3), val);
return PCIBIOS_SUCCESSFUL;
}
static int
indirect_pci_write_config_word(unsigned char bus, unsigned char dev_fn,
unsigned char offset, unsigned short val) {
if (offset&1) return PCIBIOS_BAD_REGISTER_NUMBER;
out_be32(pci->config_addr,
0x80|(bus<<8)|(dev_fn<<16)|((offset&~3)<<24));
out_le16((volatile u_short *)(pci->config_data + (offset&3)), val);
return PCIBIOS_SUCCESSFUL;
}
static int
indirect_pci_write_config_dword(unsigned char bus, unsigned char dev_fn,
unsigned char offset, unsigned int val) {
if (offset&3) return PCIBIOS_BAD_REGISTER_NUMBER;
out_be32(pci->config_addr,
0x80|(bus<<8)|(dev_fn<<16)|(offset<<24));
out_le32((volatile u_int *)pci->config_data, val);
return PCIBIOS_SUCCESSFUL;
}
static const struct pci_config_access_functions indirect_functions = {
indirect_pci_read_config_byte,
indirect_pci_read_config_word,
indirect_pci_read_config_dword,
indirect_pci_write_config_byte,
indirect_pci_write_config_word,
indirect_pci_write_config_dword
};
static int
direct_pci_read_config_byte(unsigned char bus, unsigned char dev_fn,
unsigned char offset, unsigned char *val) {
if (bus != 0 || (1<<PCI_SLOT(dev_fn) & 0xff8007fe)) {
*val=0xff;
return PCIBIOS_DEVICE_NOT_FOUND;
}
*val=in_8(pci->config_data + ((1<<PCI_SLOT(dev_fn))&~1)
+ (PCI_FUNC(dev_fn)<<8) + offset);
return PCIBIOS_SUCCESSFUL;
}
static int
direct_pci_read_config_word(unsigned char bus, unsigned char dev_fn,
unsigned char offset, unsigned short *val) {
*val = 0xffff;
if (offset&1) return PCIBIOS_BAD_REGISTER_NUMBER;
if (bus != 0 || (1<<PCI_SLOT(dev_fn) & 0xff8007fe)) {
return PCIBIOS_DEVICE_NOT_FOUND;
}
*val=in_le16((volatile u_short *)
(pci->config_data + ((1<<PCI_SLOT(dev_fn))&~1)
+ (PCI_FUNC(dev_fn)<<8) + offset));
return PCIBIOS_SUCCESSFUL;
}
static int
direct_pci_read_config_dword(unsigned char bus, unsigned char dev_fn,
unsigned char offset, unsigned int *val) {
*val = 0xffffffff;
if (offset&3) return PCIBIOS_BAD_REGISTER_NUMBER;
if (bus != 0 || (1<<PCI_SLOT(dev_fn) & 0xff8007fe)) {
return PCIBIOS_DEVICE_NOT_FOUND;
}
*val=in_le32((volatile u_int *)
(pci->config_data + ((1<<PCI_SLOT(dev_fn))&~1)
+ (PCI_FUNC(dev_fn)<<8) + offset));
return PCIBIOS_SUCCESSFUL;
}
static int
direct_pci_write_config_byte(unsigned char bus, unsigned char dev_fn,
unsigned char offset, unsigned char val) {
if (bus != 0 || (1<<PCI_SLOT(dev_fn) & 0xff8007fe)) {
return PCIBIOS_DEVICE_NOT_FOUND;
}
out_8(pci->config_data + ((1<<PCI_SLOT(dev_fn))&~1)
+ (PCI_FUNC(dev_fn)<<8) + offset,
val);
return PCIBIOS_SUCCESSFUL;
}
static int
direct_pci_write_config_word(unsigned char bus, unsigned char dev_fn,
unsigned char offset, unsigned short val) {
if (offset&1) return PCIBIOS_BAD_REGISTER_NUMBER;
if (bus != 0 || (1<<PCI_SLOT(dev_fn) & 0xff8007fe)) {
return PCIBIOS_DEVICE_NOT_FOUND;
}
out_le16((volatile u_short *)
(pci->config_data + ((1<<PCI_SLOT(dev_fn))&~1)
+ (PCI_FUNC(dev_fn)<<8) + offset),
val);
return PCIBIOS_SUCCESSFUL;
}
static int
direct_pci_write_config_dword(unsigned char bus, unsigned char dev_fn,
unsigned char offset, unsigned int val) {
if (offset&3) return PCIBIOS_BAD_REGISTER_NUMBER;
if (bus != 0 || (1<<PCI_SLOT(dev_fn) & 0xff8007fe)) {
return PCIBIOS_DEVICE_NOT_FOUND;
}
out_le32((volatile u_int *)
(pci->config_data + ((1<<PCI_SLOT(dev_fn))&~1)
+ (PCI_FUNC(dev_fn)<<8) + offset),
val);
return PCIBIOS_SUCCESSFUL;
}
static const struct pci_config_access_functions direct_functions = {
direct_pci_read_config_byte,
direct_pci_read_config_word,
direct_pci_read_config_dword,
direct_pci_write_config_byte,
direct_pci_write_config_word,
direct_pci_write_config_dword
};
void pci_read_bases(struct pci_dev *dev, unsigned int howmany)
{
unsigned int reg, nextreg;
#define REG (PCI_BASE_ADDRESS_0 + (reg<<2))
u_short cmd;
u32 l, ml;
pci_read_config_word(dev, PCI_COMMAND, &cmd);
for(reg=0; reg<howmany; reg=nextreg) {
pci_resource *r;
nextreg=reg+1;
pci_read_config_dword(dev, REG, &l);
#if 0
if (l == 0xffffffff /*AJF || !l*/) continue;
#endif
/* Note that disabling the memory response of a host bridge
* would lose data if a DMA transfer were in progress. In a
* bootloader we don't care however. Also we can't print any
* message for a while since we might just disable the console.
*/
pci_write_config_word(dev, PCI_COMMAND, cmd &
~(PCI_COMMAND_IO|PCI_COMMAND_MEMORY));
pci_write_config_dword(dev, REG, ~0);
pci_read_config_dword(dev, REG, &ml);
pci_write_config_dword(dev, REG, l);
/* Reenable the device now that we've played with
* base registers.
*/
pci_write_config_word(dev, PCI_COMMAND, cmd);
/* seems to be an unused entry skip it */
if ( ml == 0 || ml == 0xffffffff ) continue;
if ((l &
(PCI_BASE_ADDRESS_SPACE|PCI_BASE_ADDRESS_MEM_TYPE_MASK))
== (PCI_BASE_ADDRESS_MEM_TYPE_64
|PCI_BASE_ADDRESS_SPACE_MEMORY)) {
nextreg=reg+2;
}
dev->base_address[reg] = l;
r = salloc(sizeof(pci_resource));
if (!r) {
printk("Error allocating pci_resource struct.\n");
continue;
}
r->dev = dev;
r->reg = reg;
if ((l&PCI_BASE_ADDRESS_SPACE) == PCI_BASE_ADDRESS_SPACE_IO) {
r->type = l&~PCI_BASE_ADDRESS_IO_MASK;
r->base = l&PCI_BASE_ADDRESS_IO_MASK;
r->size = ~(ml&PCI_BASE_ADDRESS_IO_MASK)+1;
} else {
r->type = l&~PCI_BASE_ADDRESS_MEM_MASK;
r->base = l&PCI_BASE_ADDRESS_MEM_MASK;
r->size = ~(ml&PCI_BASE_ADDRESS_MEM_MASK)+1;
}
/* Check for the blacklisted entries */
insert_resource(r);
}
}
u_int pci_scan_bus(struct pci_bus *bus)
{
unsigned int devfn, l, max, class;
unsigned char irq, hdr_type, is_multi = 0;
struct pci_dev *dev, **bus_last;
struct pci_bus *child;
bus_last = &bus->devices;
max = bus->secondary;
for (devfn = 0; devfn < 0xff; ++devfn) {
if (PCI_FUNC(devfn) && !is_multi) {
/* not a multi-function device */
continue;
}
if (pcibios_read_config_byte(bus->number, devfn, PCI_HEADER_TYPE, &hdr_type))
continue;
if (!PCI_FUNC(devfn))
is_multi = hdr_type & 0x80;
if (pcibios_read_config_dword(bus->number, devfn, PCI_VENDOR_ID, &l) ||
/* some broken boards return 0 if a slot is empty: */
l == 0xffffffff || l == 0x00000000 || l == 0x0000ffff || l == 0xffff0000) {
is_multi = 0;
continue;
}
dev = salloc(sizeof(*dev));
dev->bus = bus;
dev->devfn = devfn;
dev->vendor = l & 0xffff;
dev->device = (l >> 16) & 0xffff;
pcibios_read_config_dword(bus->number, devfn,
PCI_CLASS_REVISION, &class);
class >>= 8; /* upper 3 bytes */
dev->class = class;
class >>= 8;
dev->hdr_type = hdr_type;
switch (hdr_type & 0x7f) { /* header type */
case PCI_HEADER_TYPE_NORMAL: /* standard header */
if (class == PCI_CLASS_BRIDGE_PCI)
goto bad;
/*
* If the card generates interrupts, read IRQ number
* (some architectures change it during pcibios_fixup())
*/
pcibios_read_config_byte(bus->number, dev->devfn, PCI_INTERRUPT_PIN, &irq);
if (irq)
pcibios_read_config_byte(bus->number, dev->devfn, PCI_INTERRUPT_LINE, &irq);
dev->irq = irq;
/*
* read base address registers, again pcibios_fixup() can
* tweak these
*/
pci_read_bases(dev, 6);
pcibios_read_config_dword(bus->number, devfn, PCI_ROM_ADDRESS, &l);
dev->rom_address = (l == 0xffffffff) ? 0 : l;
break;
case PCI_HEADER_TYPE_BRIDGE: /* bridge header */
if (class != PCI_CLASS_BRIDGE_PCI)
goto bad;
pci_read_bases(dev, 2);
pcibios_read_config_dword(bus->number, devfn, PCI_ROM_ADDRESS1, &l);
dev->rom_address = (l == 0xffffffff) ? 0 : l;
break;
case PCI_HEADER_TYPE_CARDBUS: /* CardBus bridge header */
if (class != PCI_CLASS_BRIDGE_CARDBUS)
goto bad;
pci_read_bases(dev, 1);
break;
default: /* unknown header */
bad:
printk("PCI device with unknown "
"header type %d ignored.\n",
hdr_type&0x7f);
continue;
}
/*
* Put it into the global PCI device chain. It's used to
* find devices once everything is set up.
*/
*pci->last_dev_p = dev;
pci->last_dev_p = &dev->next;
/*
* Now insert it into the list of devices held
* by the parent bus.
*/
*bus_last = dev;
bus_last = &dev->sibling;
}
/*
* After performing arch-dependent fixup of the bus, look behind
* all PCI-to-PCI bridges on this bus.
*/
for(dev=bus->devices; dev; dev=dev->sibling)
/*
* If it's a bridge, scan the bus behind it.
*/
if ((dev->class >> 8) == PCI_CLASS_BRIDGE_PCI) {
unsigned int buses;
unsigned int devfn = dev->devfn;
unsigned short cr;
/*
* Insert it into the tree of buses.
*/
child = salloc(sizeof(*child));
child->next = bus->children;
bus->children = child;
child->self = dev;
child->parent = bus;
/*
* Set up the primary, secondary and subordinate
* bus numbers.
*/
child->number = child->secondary = ++max;
child->primary = bus->secondary;
child->subordinate = 0xff;
/*
* Clear all status bits and turn off memory,
* I/O and master enables.
*/
pcibios_read_config_word(bus->number, devfn, PCI_COMMAND, &cr);
pcibios_write_config_word(bus->number, devfn, PCI_COMMAND, 0x0000);
pcibios_write_config_word(bus->number, devfn, PCI_STATUS, 0xffff);
/*
* Read the existing primary/secondary/subordinate bus
* number configuration to determine if the PCI bridge
* has already been configured by the system. If so,
* do not modify the configuration, merely note it.
*/
pcibios_read_config_dword(bus->number, devfn, PCI_PRIMARY_BUS, &buses);
if ((buses & 0xFFFFFF) != 0)
{
unsigned int cmax;
child->primary = buses & 0xFF;
child->secondary = (buses >> 8) & 0xFF;
child->subordinate = (buses >> 16) & 0xFF;
child->number = child->secondary;
cmax = pci_scan_bus(child);
if (cmax > max) max = cmax;
}
else
{
/*
* Configure the bus numbers for this bridge:
*/
buses &= 0xff000000;
buses |=
(((unsigned int)(child->primary) << 0) |
((unsigned int)(child->secondary) << 8) |
((unsigned int)(child->subordinate) << 16));
pcibios_write_config_dword(bus->number, devfn, PCI_PRIMARY_BUS, buses);
/*
* Now we can scan all subordinate buses:
*/
max = pci_scan_bus(child);
/*
* Set the subordinate bus number to its real
* value:
*/
child->subordinate = max;
buses = (buses & 0xff00ffff)
| ((unsigned int)(child->subordinate) << 16);
pcibios_write_config_dword(bus->number, devfn, PCI_PRIMARY_BUS, buses);
}
pcibios_write_config_word(bus->number, devfn, PCI_COMMAND, cr);
}
/*
* We've scanned the bus and so we know all about what's on
* the other side of any bridges that may be on this bus plus
* any devices.
*
* Return how far we've got finding sub-buses.
*/
return max;
}
void
pci_fixup(void) {
struct pci_dev *p;
struct pci_bus *bus;
for (bus = &pci_root; bus; bus=bus->next) {
for (p=bus->devices; p; p=p->sibling) {
}
}
}
void pci_init(void) {
PPC_DEVICE *hostbridge;
if (pci->last_dev_p) {
printk("Two or more calls to pci_init!\n");
return;
}
pci->last_dev_p = &(bd->pci_devices);
hostbridge=residual_find_device(PROCESSORDEVICE, NULL,
BridgeController,
PCIBridge, -1, 0);
if (hostbridge) {
if (hostbridge->DeviceId.Interface==PCIBridgeIndirect) {
bd->pci_functions=&indirect_functions;
/* Should be extracted from residual data,
* indeed MPC106 in CHRP mode is different,
* but we should not use residual data in
* this case anyway.
*/
pci->config_addr = ((volatile u_int *)
(ptr_mem_map->io_base+0xcf8));
pci->config_data = ptr_mem_map->io_base+0xcfc;
} else if(hostbridge->DeviceId.Interface==PCIBridgeDirect) {
bd->pci_functions=&direct_functions;
pci->config_data=(u_char *) 0x80800000;
} else {
}
} else {
/* Let us try by experimentation at our own risk! */
u_int id0;
bd->pci_functions = &direct_functions;
/* On all direct bridges I know the host bridge itself
* appears as device 0 function 0.
*/
pcibios_read_config_dword(0, 0, PCI_VENDOR_ID, &id0);
if (id0==~0U) {
bd->pci_functions = &indirect_functions;
pci->config_addr = ((volatile u_int *)
(ptr_mem_map->io_base+0xcf8));
pci->config_data = ptr_mem_map->io_base+0xcfc;
}
/* Here we should check that the host bridge is actually
* present, but if it not, we are in such a desperate
* situation, that we probably can't even tell it.
*/
}
/* Now build a small database of all found PCI devices */
printk("\nPCI: Probing PCI hardware\n");
pci_root.subordinate=pci_scan_bus(&pci_root);
print_pci_resources("Configurable PCI resources:\n");
reconfigure_pci();
print_pci_resources("Allocated PCI resources:\n");
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,94 @@
OUTPUT_ARCH(powerpc)
OUTPUT_FORMAT(ppcboot)
/* Do we need any of these for elf?
__DYNAMIC = 0; */
SECTIONS
{
.text :
{
/* We have to build the header by hand, painful since ppcboot
format support is very poor in binutils.
objdump -b ppcboot zImage --all-headers can be used to check. */
/* The following line can be added as a branch to use the same image
* for netboot as for prepboots, the only problem is that objdump
* did not in this case recognize the format since it insisted
* in checking the x86 code area held only zeroes.
*/
LONG(0x48000000+start);
. = 0x1be; BYTE(0x80); BYTE(0)
BYTE(2); BYTE(0); BYTE(0x41); BYTE(1);
BYTE(0x12); BYTE(0x4f); LONG(0);
BYTE(((_edata + 0x1ff)>>9)&0xff);
BYTE(((_edata + 0x1ff)>>17)&0xff);
BYTE(((_edata + 0x1ff)>>25)&0xff);
. = 0x1fe;
BYTE(0x55);
BYTE(0xaa);
BYTE(start&0xff);
BYTE((start>>8)&0xff);
BYTE((start>>16)&0xff);
BYTE((start>>24)&0xff);
BYTE(_edata&0xff);
BYTE((_edata>>8)&0xff);
BYTE((_edata>>16)&0xff);
BYTE((_edata>>24)&0xff);
BYTE(0); /* flags */
BYTE(0); /* os_id */
BYTE(0x4C); BYTE(0x69); BYTE(0x6e);
BYTE(0x75); BYTE(0x78); /* Partition name */
. = 0x400;
*(.text)
*(.sdata2)
*(.rodata)
}
/* . = ALIGN(16); */
.image :
{
rtems.gz(*)
. = ALIGN(4);
*.gz(*)
}
/* Read-write section, merged into data segment: */
/* . = ALIGN(4096); */
.reloc :
{
*(.got)
_GOT2_TABLE_ = .;
*(.got2)
_FIXUP_TABLE_ = .;
*(.fixup)
}
__got2_entries = (_FIXUP_TABLE_ - _GOT2_TABLE_) >>2;
__fixup_entries = (. - _FIXUP_TABLE_)>>2;
.handlers :
{
*(.exception)
}
.data :
{
*(.data)
*(.sdata)
. = ALIGN(4);
_edata = .;
}
PROVIDE(_binary_initrd_gz_start = 0);
PROVIDE(_binary_initrd_gz_end = 0);
_rtems_gz_size = _binary_rtems_gz_end - _binary_rtems_gz_start;
_rtems_size = __rtems_end - __rtems_start;
.bss :
{
*(.sbss)
*(.bss)
. = ALIGN(4);
}
__bss_words = SIZEOF(.bss)>>2;
__size = . ;
/DISCARD/ :
{
*(.comment)
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,438 @@
/* $Id$ */
/*
* This file is derived from zlib.h and zconf.h from the zlib-0.95
* distribution by Jean-loup Gailly and Mark Adler, with some additions
* by Paul Mackerras to aid in implementing Deflate compression and
* decompression for PPP packets.
*/
/*
* ==FILEVERSION 960122==
*
* This marker is used by the Linux installation script to determine
* whether an up-to-date version of this file is already installed.
*/
/* zlib.h -- interface of the 'zlib' general purpose compression library
version 0.95, Aug 16th, 1995.
Copyright (C) 1995 Jean-loup Gailly and Mark Adler
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
Jean-loup Gailly Mark Adler
gzip@prep.ai.mit.edu madler@alumni.caltech.edu
*/
#ifndef _ZLIB_H
#define _ZLIB_H
#define local
#ifdef DEBUG_ZLIB
#include <bsp/consoleIo.h>
#define fprintf printk
#endif
/* #include "zconf.h" */ /* included directly here */
/* zconf.h -- configuration of the zlib compression library
* Copyright (C) 1995 Jean-loup Gailly.
* For conditions of distribution and use, see copyright notice in zlib.h
*/
/* From: zconf.h,v 1.12 1995/05/03 17:27:12 jloup Exp */
/*
The library does not install any signal handler. It is recommended to
add at least a handler for SIGSEGV when decompressing; the library checks
the consistency of the input data whenever possible but may go nuts
for some forms of corrupted input.
*/
/*
* Compile with -DMAXSEG_64K if the alloc function cannot allocate more
* than 64k bytes at a time (needed on systems with 16-bit int).
* Compile with -DUNALIGNED_OK if it is OK to access shorts or ints
* at addresses which are not a multiple of their size.
* Under DOS, -DFAR=far or -DFAR=__far may be needed.
*/
#ifndef STDC
# if defined(MSDOS) || defined(__STDC__) || defined(__cplusplus)
# define STDC
# endif
#endif
#ifdef __MWERKS__ /* Metrowerks CodeWarrior declares fileno() in unix.h */
# include <unix.h>
#endif
/* Maximum value for memLevel in deflateInit2 */
#ifndef MAX_MEM_LEVEL
# ifdef MAXSEG_64K
# define MAX_MEM_LEVEL 8
# else
# define MAX_MEM_LEVEL 9
# endif
#endif
#ifndef FAR
# define FAR
#endif
/* Maximum value for windowBits in deflateInit2 and inflateInit2 */
#ifndef MAX_WBITS
# define MAX_WBITS 15 /* 32K LZ77 window */
#endif
/* The memory requirements for deflate are (in bytes):
1 << (windowBits+2) + 1 << (memLevel+9)
that is: 128K for windowBits=15 + 128K for memLevel = 8 (default values)
plus a few kilobytes for small objects. For example, if you want to reduce
the default memory requirements from 256K to 128K, compile with
make CFLAGS="-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7"
Of course this will generally degrade compression (there's no free lunch).
The memory requirements for inflate are (in bytes) 1 << windowBits
that is, 32K for windowBits=15 (default value) plus a few kilobytes
for small objects.
*/
/* Type declarations */
#ifndef OF /* function prototypes */
# ifdef STDC
# define OF(args) args
# else
# define OF(args) ()
# endif
#endif
typedef unsigned char Byte; /* 8 bits */
typedef unsigned int uInt; /* 16 bits or more */
typedef unsigned long uLong; /* 32 bits or more */
typedef Byte FAR Bytef;
typedef char FAR charf;
typedef int FAR intf;
typedef uInt FAR uIntf;
typedef uLong FAR uLongf;
#ifdef STDC
typedef void FAR *voidpf;
typedef void *voidp;
#else
typedef Byte FAR *voidpf;
typedef Byte *voidp;
#endif
/* end of original zconf.h */
#define ZLIB_VERSION "0.95P"
/*
The 'zlib' compression library provides in-memory compression and
decompression functions, including integrity checks of the uncompressed
data. This version of the library supports only one compression method
(deflation) but other algorithms may be added later and will have the same
stream interface.
For compression the application must provide the output buffer and
may optionally provide the input buffer for optimization. For decompression,
the application must provide the input buffer and may optionally provide
the output buffer for optimization.
Compression can be done in a single step if the buffers are large
enough (for example if an input file is mmap'ed), or can be done by
repeated calls of the compression function. In the latter case, the
application must provide more input and/or consume the output
(providing more output space) before each call.
*/
typedef voidpf (*alloc_func) OF((voidpf opaque, uInt items, uInt size));
typedef void (*free_func) OF((voidpf opaque, voidpf address, uInt nbytes));
struct internal_state;
typedef struct z_stream_s {
Bytef *next_in; /* next input byte */
uInt avail_in; /* number of bytes available at next_in */
uLong total_in; /* total nb of input bytes read so far */
Bytef *next_out; /* next output byte should be put there */
uInt avail_out; /* remaining free space at next_out */
uLong total_out; /* total nb of bytes output so far */
char *msg; /* last error message, NULL if no error */
struct internal_state FAR *state; /* not visible by applications */
alloc_func zalloc; /* used to allocate the internal state */
free_func zfree; /* used to free the internal state */
voidp opaque; /* private data object passed to zalloc and zfree */
Byte data_type; /* best guess about the data type: ascii or binary */
} z_stream;
/*
The application must update next_in and avail_in when avail_in has
dropped to zero. It must update next_out and avail_out when avail_out
has dropped to zero. The application must initialize zalloc, zfree and
opaque before calling the init function. All other fields are set by the
compression library and must not be updated by the application.
The opaque value provided by the application will be passed as the first
parameter for calls of zalloc and zfree. This can be useful for custom
memory management. The compression library attaches no meaning to the
opaque value.
zalloc must return Z_NULL if there is not enough memory for the object.
On 16-bit systems, the functions zalloc and zfree must be able to allocate
exactly 65536 bytes, but will not be required to allocate more than this
if the symbol MAXSEG_64K is defined (see zconf.h). WARNING: On MSDOS,
pointers returned by zalloc for objects of exactly 65536 bytes *must*
have their offset normalized to zero. The default allocation function
provided by this library ensures this (see zutil.c). To reduce memory
requirements and avoid any allocation of 64K objects, at the expense of
compression ratio, compile the library with -DMAX_WBITS=14 (see zconf.h).
The fields total_in and total_out can be used for statistics or
progress reports. After compression, total_in holds the total size of
the uncompressed data and may be saved for use in the decompressor
(particularly if the decompressor wants to decompress everything in
a single step).
*/
/* constants */
#define Z_NO_FLUSH 0
#define Z_PARTIAL_FLUSH 1
#define Z_FULL_FLUSH 2
#define Z_SYNC_FLUSH 3 /* experimental: partial_flush + byte align */
#define Z_FINISH 4
#define Z_PACKET_FLUSH 5
/* See deflate() below for the usage of these constants */
#define Z_OK 0
#define Z_STREAM_END 1
#define Z_ERRNO (-1)
#define Z_STREAM_ERROR (-2)
#define Z_DATA_ERROR (-3)
#define Z_MEM_ERROR (-4)
#define Z_BUF_ERROR (-5)
/* error codes for the compression/decompression functions */
#define Z_BEST_SPEED 1
#define Z_BEST_COMPRESSION 9
#define Z_DEFAULT_COMPRESSION (-1)
/* compression levels */
#define Z_FILTERED 1
#define Z_HUFFMAN_ONLY 2
#define Z_DEFAULT_STRATEGY 0
#define Z_BINARY 0
#define Z_ASCII 1
#define Z_UNKNOWN 2
/* Used to set the data_type field */
#define Z_NULL 0 /* for initializing zalloc, zfree, opaque */
extern char *zlib_version;
/* The application can compare zlib_version and ZLIB_VERSION for consistency.
If the first character differs, the library code actually used is
not compatible with the zlib.h header file used by the application.
*/
/* basic functions */
extern int inflateInit OF((z_stream *strm));
/*
Initializes the internal stream state for decompression. The fields
zalloc and zfree must be initialized before by the caller. If zalloc and
zfree are set to Z_NULL, inflateInit updates them to use default allocation
functions.
inflateInit returns Z_OK if success, Z_MEM_ERROR if there was not
enough memory. msg is set to null if there is no error message.
inflateInit does not perform any decompression: this will be done by
inflate().
*/
extern int inflate OF((z_stream *strm, int flush));
/*
Performs one or both of the following actions:
- Decompress more input starting at next_in and update next_in and avail_in
accordingly. If not all input can be processed (because there is not
enough room in the output buffer), next_in is updated and processing
will resume at this point for the next call of inflate().
- Provide more output starting at next_out and update next_out and avail_out
accordingly. inflate() always provides as much output as possible
(until there is no more input data or no more space in the output buffer).
Before the call of inflate(), the application should ensure that at least
one of the actions is possible, by providing more input and/or consuming
more output, and updating the next_* and avail_* values accordingly.
The application can consume the uncompressed output when it wants, for
example when the output buffer is full (avail_out == 0), or after each
call of inflate().
If the parameter flush is set to Z_PARTIAL_FLUSH or Z_PACKET_FLUSH,
inflate flushes as much output as possible to the output buffer. The
flushing behavior of inflate is not specified for values of the flush
parameter other than Z_PARTIAL_FLUSH, Z_PACKET_FLUSH or Z_FINISH, but the
current implementation actually flushes as much output as possible
anyway. For Z_PACKET_FLUSH, inflate checks that once all the input data
has been consumed, it is expecting to see the length field of a stored
block; if not, it returns Z_DATA_ERROR.
inflate() should normally be called until it returns Z_STREAM_END or an
error. However if all decompression is to be performed in a single step
(a single call of inflate), the parameter flush should be set to
Z_FINISH. In this case all pending input is processed and all pending
output is flushed; avail_out must be large enough to hold all the
uncompressed data. (The size of the uncompressed data may have been saved
by the compressor for this purpose.) The next operation on this stream must
be inflateEnd to deallocate the decompression state. The use of Z_FINISH
is never required, but can be used to inform inflate that a faster routine
may be used for the single inflate() call.
inflate() returns Z_OK if some progress has been made (more input
processed or more output produced), Z_STREAM_END if the end of the
compressed data has been reached and all uncompressed output has been
produced, Z_DATA_ERROR if the input data was corrupted, Z_STREAM_ERROR if
the stream structure was inconsistent (for example if next_in or next_out
was NULL), Z_MEM_ERROR if there was not enough memory, Z_BUF_ERROR if no
progress is possible or if there was not enough room in the output buffer
when Z_FINISH is used. In the Z_DATA_ERROR case, the application may then
call inflateSync to look for a good compression block. */
extern int inflateEnd OF((z_stream *strm));
/*
All dynamically allocated data structures for this stream are freed.
This function discards any unprocessed input and does not flush any
pending output.
inflateEnd returns Z_OK if success, Z_STREAM_ERROR if the stream state
was inconsistent. In the error case, msg may be set but then points to a
static string (which must not be deallocated).
*/
/* advanced functions */
extern int inflateInit2 OF((z_stream *strm,
int windowBits));
/*
This is another version of inflateInit with more compression options. The
fields next_out, zalloc and zfree must be initialized before by the caller.
The windowBits parameter is the base two logarithm of the maximum window
size (the size of the history buffer). It should be in the range 8..15 for
this version of the library (the value 16 will be allowed soon). The
default value is 15 if inflateInit is used instead. If a compressed stream
with a larger window size is given as input, inflate() will return with
the error code Z_DATA_ERROR instead of trying to allocate a larger window.
If next_out is not null, the library will use this buffer for the history
buffer; the buffer must either be large enough to hold the entire output
data, or have at least 1<<windowBits bytes. If next_out is null, the
library will allocate its own buffer (and leave next_out null). next_in
need not be provided here but must be provided by the application for the
next call of inflate().
If the history buffer is provided by the application, next_out must
never be changed by the application since the decompressor maintains
history information inside this buffer from call to call; the application
can only reset next_out to the beginning of the history buffer when
avail_out is zero and all output has been consumed.
inflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was
not enough memory, Z_STREAM_ERROR if a parameter is invalid (such as
windowBits < 8). msg is set to null if there is no error message.
inflateInit2 does not perform any decompression: this will be done by
inflate().
*/
extern int inflateSync OF((z_stream *strm));
/*
Skips invalid compressed data until the special marker (see deflate()
above) can be found, or until all available input is skipped. No output
is provided.
inflateSync returns Z_OK if the special marker has been found, Z_BUF_ERROR
if no more input was provided, Z_DATA_ERROR if no marker has been found,
or Z_STREAM_ERROR if the stream structure was inconsistent. In the success
case, the application may save the current current value of total_in which
indicates where valid compressed data was found. In the error case, the
application may repeatedly call inflateSync, providing more input each time,
until success or end of the input data.
*/
extern int inflateReset OF((z_stream *strm));
/*
This function is equivalent to inflateEnd followed by inflateInit,
but does not free and reallocate all the internal decompression state.
The stream will keep attributes that may have been set by inflateInit2.
inflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source
stream state was inconsistent (such as zalloc or state being NULL).
*/
extern int inflateIncomp OF((z_stream *strm));
/*
This function adds the data at next_in (avail_in bytes) to the output
history without performing any output. There must be no pending output,
and the decompressor must be expecting to see the start of a block.
Calling this function is equivalent to decompressing a stored block
containing the data at next_in (except that the data is not output).
*/
/* checksum functions */
/*
This function is not related to compression but is exported
anyway because it might be useful in applications using the
compression library.
*/
extern uLong adler32 OF((uLong adler, Bytef *buf, uInt len));
/*
Update a running Adler-32 checksum with the bytes buf[0..len-1] and
return the updated checksum. If buf is NULL, this function returns
the required initial value for the checksum.
An Adler-32 checksum is almost as reliable as a CRC32 but can be computed
much faster. Usage example:
uLong adler = adler32(0L, Z_NULL, 0);
while (read_buffer(buffer, length) != EOF) {
adler = adler32(adler, buffer, length);
}
if (adler != original_adler) error();
*/
#ifndef _Z_UTIL_H
struct internal_state {int dummy;}; /* hack for buggy compilers */
#endif
#endif /* _ZLIB_H */

View File

@@ -0,0 +1,38 @@
#
# $Id$
#
@SET_MAKE@
srcdir = @srcdir@
top_srcdir = @top_srcdir@
top_builddir = ../../..
subdir = powerpc/shared/clock
RTEMS_ROOT = @RTEMS_ROOT@
PROJECT_ROOT = @PROJECT_ROOT@
VPATH = @srcdir@
H_FILES =
SRCS = $(C_FILES) $(H_FILES)
include $(RTEMS_ROOT)/make/custom/@RTEMS_BSP@.cfg
include $(RTEMS_ROOT)/make/leaf.cfg
INSTALL_CHANGE = @INSTALL_CHANGE@
mkinstalldirs = $(SHELL) $(top_srcdir)/@RTEMS_TOPdir@/mkinstalldirs
INSTALLDIRS = $(PROJECT_INCLUDE)/bsp
$(INSTALLDIRS):
@$(mkinstalldirs) $(INSTALLDIRS)
all: ${ARCH} $(SRCS)
# the .rel file built here will be put into libbsp.a by ../wrapup/Makefile
install: all
Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
cd $(top_builddir) \
&& CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status

View File

@@ -0,0 +1,37 @@
/*
* Clock Tick interrupt conexion code.
*
* COPYRIGHT (c) 1989-1997.
* On-Line Applications Research Corporation (OAR).
* Copyright assigned to U.S. Government, 1994.
*
* The license and distribution terms for this file may in
* the file LICENSE in this distribution or at
* http://www.OARcorp.com/rtems/license.html.
*
* Modified to support the MPC750.
* Modifications Copyright (c) 1999 Eric Valette valette@crf.canon.fr
*
* $Id$
*/
#include <bsp.h>
#include <bsp/irq.h>
#include <libcpu/c_clock.h>
static rtems_irq_connect_data clockIrqData = {BSP_DECREMENTER,
clockIsr,
(rtems_irq_enable)clockOn,
(rtems_irq_disable)clockOff,
(rtems_irq_is_enabled) clockIsOn};
int BSP_disconnect_clock_handler (void)
{
return BSP_remove_rtems_irq_handler (&clockIrqData);
}
int BSP_connect_clock_handler (void)
{
return BSP_install_rtems_irq_handler (&clockIrqData);
}

View File

@@ -0,0 +1,48 @@
#
# $Id:
#
@SET_MAKE@
srcdir = @srcdir@
top_srcdir = @top_srcdir@
top_builddir = ../../..
subdir = powerpc/shared/console
RTEMS_ROOT = @RTEMS_ROOT@
PROJECT_ROOT = @PROJECT_ROOT@
VPATH = @srcdir@:@srcdir@/../../../shared
# C source names, if any, go here -- minus the .c
H_FILES = $(srcdir)/consoleIo.h $(srcdir)/keyboard.h $(srcdir)/uart.h
SRCS = $(C_FILES) $(CC_FILES) $(H_FILES) $(S_FILES)
include $(RTEMS_ROOT)/make/custom/@RTEMS_BSP@.cfg
include $(RTEMS_ROOT)/make/leaf.cfg
INSTALL_CHANGE = @INSTALL_CHANGE@
mkinstalldirs = $(SHELL) $(top_srcdir)/@RTEMS_TOPdir@/mkinstalldirs
INSTALLDIRS = $(PROJECT_INCLUDE)/bsp
$(INSTALLDIRS):
@$(mkinstalldirs) $(INSTALLDIRS)
#
# Add your list of files to delete here. The config files
# already know how to delete some stuff, so you may want
# to just run 'make clean' first to see what gets missed.
# 'make clobber' already includes 'make clean'
#
preinstall:
@$(mkinstalldirs) $(PROJECT_INCLUDE)/bsp
@$(INSTALL_CHANGE) -m 644 $(H_FILES) $(PROJECT_INCLUDE)/bsp
all: ${ARCH} $(SRCS) preinstall
Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
cd $(top_builddir) \
&& CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status

View File

@@ -45,10 +45,10 @@ extern int close(int fd);
* BSP_UART_COM2 * BSP_UART_COM2
*/ */
extern int BSPConsolePort; int BSPConsolePort = BSP_UART_COM1;
/* int BSPConsolePort = BSP_UART_COM2; */ /* int BSPConsolePort = BSP_UART_COM2; */
extern int BSPBaseBaud; int BSPBaseBaud = 115200;
/*-------------------------------------------------------------------------+ /*-------------------------------------------------------------------------+
| External Prototypes | External Prototypes
@@ -84,7 +84,6 @@ isr_is_on(const rtems_irq_connect_data *irq)
return BSP_irq_enabled_at_i8259s(irq->name); return BSP_irq_enabled_at_i8259s(irq->name);
} }
/*
void console_reserve_resources(rtems_configuration_table *conf) void console_reserve_resources(rtems_configuration_table *conf)
{ {
if(BSPConsolePort != BSP_CONSOLE_PORT_CONSOLE) if(BSPConsolePort != BSP_CONSOLE_PORT_CONSOLE)
@@ -94,7 +93,6 @@ void console_reserve_resources(rtems_configuration_table *conf)
return; return;
} }
*/
void __assert (const char *file, int line, const char *msg) void __assert (const char *file, int line, const char *msg)
{ {

View File

@@ -0,0 +1,45 @@
/*
* consoleIo.h -- console I/O package interface
*
* Copyright (C) 1999 Eric Valette. valette@crf.canon.fr
*
* The license and distribution terms for this file may be
* found in found in the file LICENSE in this distribution or at
* http://www.OARcorp.com/rtems/license.html.
*
* $Id$
*/
#ifndef __CONSOLE_IO_H
#define __CONSOLE_IO_H
typedef enum {
CONSOLE_LOG = 1,
CONSOLE_SERIAL = 2,
CONSOLE_VGA = 3,
CONSOLE_VACUUM = 4
}ioType;
typedef volatile unsigned char * __io_ptr;
typedef struct {
__io_ptr io_base;
__io_ptr isa_mem_base;
__io_ptr pci_mmio_base;
__io_ptr pci_dma_offset;
} board_memory_map;
extern board_memory_map *ptr_mem_map;
extern unsigned long ticks_per_ms;
extern int select_console(ioType t);
extern int printk(const char *, ...) __attribute__((format(printf, 1, 2)));
extern void udelay(int);
extern void debug_putc(const unsigned char c);
extern int debug_getc(void);
extern int debug_tstc(void);
int kbdreset(void);
#endif

View File

@@ -0,0 +1,318 @@
/*
* inch.c -- keyboard minimal driver
*
* Copyright (C) 1999 Eric Valette. valette@crf.canon.fr
*
* This code is based on the pc386 BSP inch.c so the following
* copyright also applies :
*
* (C) Copyright 1997 -
* - NavIST Group - Real-Time Distributed Systems and Industrial Automation
*
* http://pandora.ist.utl.pt
*
* Instituto Superior Tecnico * Lisboa * PORTUGAL
* The license and distribution terms for this file may be
* found in found in the file LICENSE in this distribution or at
* http://www.OARcorp.com/rtems/license.html.
*
* $Id$
*/
#include <bsp.h>
#include <bsp/irq.h>
/*-------------------------------------------------------------------------+
| Constants
+--------------------------------------------------------------------------*/
#define KBD_CTL 0x61 /* -------------------------------- */
#define KBD_DATA 0x60 /* Ports for PC keyboard controller */
#define KBD_STATUS 0x64 /* -------------------------------- */
#define KBD_BUF_SIZE 256
/*-------------------------------------------------------------------------+
| Global Variables
+--------------------------------------------------------------------------*/
static char key_map[] =
{
0,033,'1','2','3','4','5','6','7','8','9','0','-','=','\b','\t',
'q','w','e','r','t','y','u','i','o','p','[',']',015,0x80,
'a','s','d','f','g','h','j','k','l',';',047,0140,0x80,
0134,'z','x','c','v','b','n','m',',','.','/',0x80,
'*',0x80,' ',0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,
0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,
0x80,0x80,0x80,'0',0177
}; /* Keyboard scancode -> character map with no modifiers. */
static char shift_map[] =
{
0,033,'!','@','#','$','%','^','&','*','(',')','_','+','\b','\t',
'Q','W','E','R','T','Y','U','I','O','P','{','}',015,0x80,
'A','S','D','F','G','H','J','K','L',':',042,'~',0x80,
'|','Z','X','C','V','B','N','M','<','>','?',0x80,
'*',0x80,' ',0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,
0x80,0x80,0x80,0x80,'7','8','9',0x80,'4','5','6',0x80,
'1','2','3','0',177
}; /* Keyboard scancode -> character map with SHIFT key modifier. */
static char kbd_buffer[KBD_BUF_SIZE];
static rtems_unsigned16 kbd_first = 0;
static rtems_unsigned16 kbd_last = 0;
static rtems_unsigned16 kbd_end = KBD_BUF_SIZE - 1;
/*-------------------------------------------------------------------------+
| Function: rtemsReboot
| Description: Reboot the PC.
| Global Variables: None.
| Arguments: None.
| Returns: Nothing.
+--------------------------------------------------------------------------*/
void rtemsReboot(void)
{
/* shutdown and reboot */
outport_byte(0x64, 0xFE); /* use keyboard controler to do the job... */
} /* rtemsReboot */
/*-------------------------------------------------------------------------+
| Function: _IBMPC_scankey
| Description: This function can be called during a poll for input, or by
| an ISR. Basically any time you want to process a keypress.
| Global Variables: key_map, shift_map.
| Arguments: outChar - character read in case of a valid reading,
| otherwise unchanged.
| Returns: TRUE in case a valid character has been read,
| FALSE otherwise.
+--------------------------------------------------------------------------*/
rtems_boolean
_IBMPC_scankey(char *outChar)
{
unsigned char inChar;
static int alt_pressed = 0;
static int ctrl_pressed = 0;
static int shift_pressed = 0;
static int caps_pressed = 0;
static int extended = 0;
*outChar = NULL; /* default value if we return FALSE */
/* Read keyboard controller, toggle enable */
inport_byte(KBD_CTL, inChar);
outport_byte(KBD_CTL, inChar & ~0x80);
outport_byte(KBD_CTL, inChar | 0x80);
outport_byte(KBD_CTL, inChar & ~0x80);
/* See if it has data */
inport_byte(KBD_STATUS, inChar);
if ((inChar & 0x01) == 0)
return FALSE;
/* Read the data. Handle nonsense with shift, control, etc. */
inport_byte(KBD_DATA, inChar);
if (extended)
extended--;
switch (inChar)
{
case 0xe0:
extended = 2;
return FALSE;
break;
case 0x38:
alt_pressed = 1;
return FALSE;
break;
case 0xb8:
alt_pressed = 0;
return FALSE;
break;
case 0x1d:
ctrl_pressed = 1;
return FALSE;
break;
case 0x9d:
ctrl_pressed = 0;
return FALSE;
break;
case 0x2a:
if (extended)
return FALSE;
case 0x36:
shift_pressed = 1;
return FALSE;
break;
case 0xaa:
if (extended)
return FALSE;
case 0xb6:
shift_pressed = 0;
return FALSE;
break;
case 0x3a:
caps_pressed = 1;
return FALSE;
break;
case 0xba:
caps_pressed = 0;
return FALSE;
break;
case 0x53:
if (ctrl_pressed && alt_pressed)
rtemsReboot(); /* ctrl+alt+del -> reboot */
break;
/*
* Ignore unrecognized keys--usually arrow and such
*/
default:
if ((inChar & 0x80) || (inChar > 0x39))
/* High-bit on means key is being released, not pressed */
return FALSE;
break;
} /* switch */
/* Strip high bit, look up in our map */
inChar &= 0x7f;
if (ctrl_pressed)
{
*outChar = key_map[inChar];
*outChar &= 037;
}
else
{
*outChar = shift_pressed ? shift_map[inChar] : key_map[inChar];
if (caps_pressed)
{
if (*outChar >= 'A' && *outChar <= 'Z')
*outChar += 'a' - 'A';
else if (*outChar >= 'a' && *outChar <= 'z')
*outChar -= 'a' - 'A';
}
}
return TRUE;
} /* _IBMPC_scankey */
/*-------------------------------------------------------------------------+
| Function: _IBMPC_keyboard_isr
| Description: Interrupt Service Routine for keyboard (0x01) IRQ.
| Global Variables: kbd_buffer, kbd_first, kbd_last.
| Arguments: vector - standard RTEMS argument - see documentation.
| Returns: standard return value - see documentation.
+--------------------------------------------------------------------------*/
void _IBMPC_keyboard_isr()
{
if (_IBMPC_scankey(&kbd_buffer[kbd_last]))
{
/* Got one; save it if there is enough room in buffer. */
unsigned int next = (kbd_last == kbd_end) ? 0 : kbd_last + 1;
if (next != kbd_first)
{
kbd_last = next;
}
}
} /* _IBMPC_keyboard_isr */
/*-------------------------------------------------------------------------+
| Function: _IBMPC_chrdy
| Description: Check keyboard ISR buffer and return character if not empty.
| Global Variables: kbd_buffer, kbd_first, kbd_last.
| Arguments: c - character read if keyboard buffer not empty, otherwise
| unchanged.
| Returns: TRUE if keyboard buffer not empty, FALSE otherwise.
+--------------------------------------------------------------------------*/
rtems_boolean
_IBMPC_chrdy(char *c)
{
/* Check buffer our ISR builds */
if (kbd_first != kbd_last)
{
*c = kbd_buffer[kbd_first];
kbd_first = (kbd_first + 1) % KBD_BUF_SIZE;
return TRUE;
}
else
return FALSE;
} /* _IBMPC_chrdy */
/*-------------------------------------------------------------------------+
| Function: _IBMPC_inch
| Description: Poll keyboard until a character is ready and return it.
| Global Variables: None.
| Arguments: None.
| Returns: character read from keyboard.
+--------------------------------------------------------------------------*/
char
_IBMPC_inch(void)
{
char c;
while (!_IBMPC_chrdy(&c))
continue;
return c;
} /* _IBMPC_inch */
/*
* Routine that can be used before interrupt management is initialized.
*/
char
BSP_wait_polled_input(void)
{
char c;
while (!_IBMPC_scankey(&c))
continue;
return c;
}
/*-------------------------------------------------------------------------+
| Function: _IBMPC_inch_sleep
| Description: If charcter is ready return it, otherwise sleep until
| it is ready
| Global Variables: None.
| Arguments: None.
| Returns: character read from keyboard.
+--------------------------------------------------------------------------*/
char
_IBMPC_inch_sleep(void)
{
char c;
rtems_interval ticks_per_second;
ticks_per_second = 0;
for(;;)
{
if(_IBMPC_chrdy(&c))
{
return c;
}
if(ticks_per_second == 0)
{
rtems_clock_get(RTEMS_CLOCK_GET_TICKS_PER_SECOND,
&ticks_per_second);
}
rtems_task_wake_after((ticks_per_second+24)/25);
}
return c;
} /* _IBMPC_inch */

View File

@@ -0,0 +1,433 @@
/*
* keyboard.h -- keyboard definitions.
*
* Copyright (C) 1999 Eric Valette. valette@crf.canon.fr
*
* The license and distribution terms for this file may be
* found in found in the file LICENSE in this distribution or at
* http://www.OARcorp.com/rtems/license.html.
*
* $Id$
*/
#ifndef __LINUX_KEYBOARD_H
#define __LINUX_KEYBOARD_H
#define KG_SHIFT 0
#define KG_CTRL 2
#define KG_ALT 3
#define KG_ALTGR 1
#define KG_SHIFTL 4
#define KG_SHIFTR 5
#define KG_CTRLL 6
#define KG_CTRLR 7
#define KG_CAPSSHIFT 8
#define NR_SHIFT 9
#define NR_KEYS 128
#define MAX_NR_KEYMAPS 256
/* This means 64Kb if all keymaps are allocated. Only the superuser
may increase the number of keymaps beyond MAX_NR_OF_USER_KEYMAPS. */
#define MAX_NR_OF_USER_KEYMAPS 256 /* should be at least 7 */
#define MAX_NR_FUNC 256 /* max nr of strings assigned to keys */
#define KT_LATIN 0 /* we depend on this being zero */
#define KT_LETTER 11 /* symbol that can be acted upon by CapsLock */
#define KT_FN 1
#define KT_SPEC 2
#define KT_PAD 3
#define KT_DEAD 4
#define KT_CONS 5
#define KT_CUR 6
#define KT_SHIFT 7
#define KT_META 8
#define KT_ASCII 9
#define KT_LOCK 10
#define KT_SLOCK 12
#define K(t,v) (((t)<<8)|(v))
#define KTYP(x) ((x) >> 8)
#define KVAL(x) ((x) & 0xff)
#define K_F1 K(KT_FN,0)
#define K_F2 K(KT_FN,1)
#define K_F3 K(KT_FN,2)
#define K_F4 K(KT_FN,3)
#define K_F5 K(KT_FN,4)
#define K_F6 K(KT_FN,5)
#define K_F7 K(KT_FN,6)
#define K_F8 K(KT_FN,7)
#define K_F9 K(KT_FN,8)
#define K_F10 K(KT_FN,9)
#define K_F11 K(KT_FN,10)
#define K_F12 K(KT_FN,11)
#define K_F13 K(KT_FN,12)
#define K_F14 K(KT_FN,13)
#define K_F15 K(KT_FN,14)
#define K_F16 K(KT_FN,15)
#define K_F17 K(KT_FN,16)
#define K_F18 K(KT_FN,17)
#define K_F19 K(KT_FN,18)
#define K_F20 K(KT_FN,19)
#define K_FIND K(KT_FN,20)
#define K_INSERT K(KT_FN,21)
#define K_REMOVE K(KT_FN,22)
#define K_SELECT K(KT_FN,23)
#define K_PGUP K(KT_FN,24) /* PGUP is a synonym for PRIOR */
#define K_PGDN K(KT_FN,25) /* PGDN is a synonym for NEXT */
#define K_MACRO K(KT_FN,26)
#define K_HELP K(KT_FN,27)
#define K_DO K(KT_FN,28)
#define K_PAUSE K(KT_FN,29)
#define K_F21 K(KT_FN,30)
#define K_F22 K(KT_FN,31)
#define K_F23 K(KT_FN,32)
#define K_F24 K(KT_FN,33)
#define K_F25 K(KT_FN,34)
#define K_F26 K(KT_FN,35)
#define K_F27 K(KT_FN,36)
#define K_F28 K(KT_FN,37)
#define K_F29 K(KT_FN,38)
#define K_F30 K(KT_FN,39)
#define K_F31 K(KT_FN,40)
#define K_F32 K(KT_FN,41)
#define K_F33 K(KT_FN,42)
#define K_F34 K(KT_FN,43)
#define K_F35 K(KT_FN,44)
#define K_F36 K(KT_FN,45)
#define K_F37 K(KT_FN,46)
#define K_F38 K(KT_FN,47)
#define K_F39 K(KT_FN,48)
#define K_F40 K(KT_FN,49)
#define K_F41 K(KT_FN,50)
#define K_F42 K(KT_FN,51)
#define K_F43 K(KT_FN,52)
#define K_F44 K(KT_FN,53)
#define K_F45 K(KT_FN,54)
#define K_F46 K(KT_FN,55)
#define K_F47 K(KT_FN,56)
#define K_F48 K(KT_FN,57)
#define K_F49 K(KT_FN,58)
#define K_F50 K(KT_FN,59)
#define K_F51 K(KT_FN,60)
#define K_F52 K(KT_FN,61)
#define K_F53 K(KT_FN,62)
#define K_F54 K(KT_FN,63)
#define K_F55 K(KT_FN,64)
#define K_F56 K(KT_FN,65)
#define K_F57 K(KT_FN,66)
#define K_F58 K(KT_FN,67)
#define K_F59 K(KT_FN,68)
#define K_F60 K(KT_FN,69)
#define K_F61 K(KT_FN,70)
#define K_F62 K(KT_FN,71)
#define K_F63 K(KT_FN,72)
#define K_F64 K(KT_FN,73)
#define K_F65 K(KT_FN,74)
#define K_F66 K(KT_FN,75)
#define K_F67 K(KT_FN,76)
#define K_F68 K(KT_FN,77)
#define K_F69 K(KT_FN,78)
#define K_F70 K(KT_FN,79)
#define K_F71 K(KT_FN,80)
#define K_F72 K(KT_FN,81)
#define K_F73 K(KT_FN,82)
#define K_F74 K(KT_FN,83)
#define K_F75 K(KT_FN,84)
#define K_F76 K(KT_FN,85)
#define K_F77 K(KT_FN,86)
#define K_F78 K(KT_FN,87)
#define K_F79 K(KT_FN,88)
#define K_F80 K(KT_FN,89)
#define K_F81 K(KT_FN,90)
#define K_F82 K(KT_FN,91)
#define K_F83 K(KT_FN,92)
#define K_F84 K(KT_FN,93)
#define K_F85 K(KT_FN,94)
#define K_F86 K(KT_FN,95)
#define K_F87 K(KT_FN,96)
#define K_F88 K(KT_FN,97)
#define K_F89 K(KT_FN,98)
#define K_F90 K(KT_FN,99)
#define K_F91 K(KT_FN,100)
#define K_F92 K(KT_FN,101)
#define K_F93 K(KT_FN,102)
#define K_F94 K(KT_FN,103)
#define K_F95 K(KT_FN,104)
#define K_F96 K(KT_FN,105)
#define K_F97 K(KT_FN,106)
#define K_F98 K(KT_FN,107)
#define K_F99 K(KT_FN,108)
#define K_F100 K(KT_FN,109)
#define K_F101 K(KT_FN,110)
#define K_F102 K(KT_FN,111)
#define K_F103 K(KT_FN,112)
#define K_F104 K(KT_FN,113)
#define K_F105 K(KT_FN,114)
#define K_F106 K(KT_FN,115)
#define K_F107 K(KT_FN,116)
#define K_F108 K(KT_FN,117)
#define K_F109 K(KT_FN,118)
#define K_F110 K(KT_FN,119)
#define K_F111 K(KT_FN,120)
#define K_F112 K(KT_FN,121)
#define K_F113 K(KT_FN,122)
#define K_F114 K(KT_FN,123)
#define K_F115 K(KT_FN,124)
#define K_F116 K(KT_FN,125)
#define K_F117 K(KT_FN,126)
#define K_F118 K(KT_FN,127)
#define K_F119 K(KT_FN,128)
#define K_F120 K(KT_FN,129)
#define K_F121 K(KT_FN,130)
#define K_F122 K(KT_FN,131)
#define K_F123 K(KT_FN,132)
#define K_F124 K(KT_FN,133)
#define K_F125 K(KT_FN,134)
#define K_F126 K(KT_FN,135)
#define K_F127 K(KT_FN,136)
#define K_F128 K(KT_FN,137)
#define K_F129 K(KT_FN,138)
#define K_F130 K(KT_FN,139)
#define K_F131 K(KT_FN,140)
#define K_F132 K(KT_FN,141)
#define K_F133 K(KT_FN,142)
#define K_F134 K(KT_FN,143)
#define K_F135 K(KT_FN,144)
#define K_F136 K(KT_FN,145)
#define K_F137 K(KT_FN,146)
#define K_F138 K(KT_FN,147)
#define K_F139 K(KT_FN,148)
#define K_F140 K(KT_FN,149)
#define K_F141 K(KT_FN,150)
#define K_F142 K(KT_FN,151)
#define K_F143 K(KT_FN,152)
#define K_F144 K(KT_FN,153)
#define K_F145 K(KT_FN,154)
#define K_F146 K(KT_FN,155)
#define K_F147 K(KT_FN,156)
#define K_F148 K(KT_FN,157)
#define K_F149 K(KT_FN,158)
#define K_F150 K(KT_FN,159)
#define K_F151 K(KT_FN,160)
#define K_F152 K(KT_FN,161)
#define K_F153 K(KT_FN,162)
#define K_F154 K(KT_FN,163)
#define K_F155 K(KT_FN,164)
#define K_F156 K(KT_FN,165)
#define K_F157 K(KT_FN,166)
#define K_F158 K(KT_FN,167)
#define K_F159 K(KT_FN,168)
#define K_F160 K(KT_FN,169)
#define K_F161 K(KT_FN,170)
#define K_F162 K(KT_FN,171)
#define K_F163 K(KT_FN,172)
#define K_F164 K(KT_FN,173)
#define K_F165 K(KT_FN,174)
#define K_F166 K(KT_FN,175)
#define K_F167 K(KT_FN,176)
#define K_F168 K(KT_FN,177)
#define K_F169 K(KT_FN,178)
#define K_F170 K(KT_FN,179)
#define K_F171 K(KT_FN,180)
#define K_F172 K(KT_FN,181)
#define K_F173 K(KT_FN,182)
#define K_F174 K(KT_FN,183)
#define K_F175 K(KT_FN,184)
#define K_F176 K(KT_FN,185)
#define K_F177 K(KT_FN,186)
#define K_F178 K(KT_FN,187)
#define K_F179 K(KT_FN,188)
#define K_F180 K(KT_FN,189)
#define K_F181 K(KT_FN,190)
#define K_F182 K(KT_FN,191)
#define K_F183 K(KT_FN,192)
#define K_F184 K(KT_FN,193)
#define K_F185 K(KT_FN,194)
#define K_F186 K(KT_FN,195)
#define K_F187 K(KT_FN,196)
#define K_F188 K(KT_FN,197)
#define K_F189 K(KT_FN,198)
#define K_F190 K(KT_FN,199)
#define K_F191 K(KT_FN,200)
#define K_F192 K(KT_FN,201)
#define K_F193 K(KT_FN,202)
#define K_F194 K(KT_FN,203)
#define K_F195 K(KT_FN,204)
#define K_F196 K(KT_FN,205)
#define K_F197 K(KT_FN,206)
#define K_F198 K(KT_FN,207)
#define K_F199 K(KT_FN,208)
#define K_F200 K(KT_FN,209)
#define K_F201 K(KT_FN,210)
#define K_F202 K(KT_FN,211)
#define K_F203 K(KT_FN,212)
#define K_F204 K(KT_FN,213)
#define K_F205 K(KT_FN,214)
#define K_F206 K(KT_FN,215)
#define K_F207 K(KT_FN,216)
#define K_F208 K(KT_FN,217)
#define K_F209 K(KT_FN,218)
#define K_F210 K(KT_FN,219)
#define K_F211 K(KT_FN,220)
#define K_F212 K(KT_FN,221)
#define K_F213 K(KT_FN,222)
#define K_F214 K(KT_FN,223)
#define K_F215 K(KT_FN,224)
#define K_F216 K(KT_FN,225)
#define K_F217 K(KT_FN,226)
#define K_F218 K(KT_FN,227)
#define K_F219 K(KT_FN,228)
#define K_F220 K(KT_FN,229)
#define K_F221 K(KT_FN,230)
#define K_F222 K(KT_FN,231)
#define K_F223 K(KT_FN,232)
#define K_F224 K(KT_FN,233)
#define K_F225 K(KT_FN,234)
#define K_F226 K(KT_FN,235)
#define K_F227 K(KT_FN,236)
#define K_F228 K(KT_FN,237)
#define K_F229 K(KT_FN,238)
#define K_F230 K(KT_FN,239)
#define K_F231 K(KT_FN,240)
#define K_F232 K(KT_FN,241)
#define K_F233 K(KT_FN,242)
#define K_F234 K(KT_FN,243)
#define K_F235 K(KT_FN,244)
#define K_F236 K(KT_FN,245)
#define K_F237 K(KT_FN,246)
#define K_F238 K(KT_FN,247)
#define K_F239 K(KT_FN,248)
#define K_F240 K(KT_FN,249)
#define K_F241 K(KT_FN,250)
#define K_F242 K(KT_FN,251)
#define K_F243 K(KT_FN,252)
#define K_F244 K(KT_FN,253)
#define K_F245 K(KT_FN,254)
#define K_UNDO K(KT_FN,255)
#define K_HOLE K(KT_SPEC,0)
#define K_ENTER K(KT_SPEC,1)
#define K_SH_REGS K(KT_SPEC,2)
#define K_SH_MEM K(KT_SPEC,3)
#define K_SH_STAT K(KT_SPEC,4)
#define K_BREAK K(KT_SPEC,5)
#define K_CONS K(KT_SPEC,6)
#define K_CAPS K(KT_SPEC,7)
#define K_NUM K(KT_SPEC,8)
#define K_HOLD K(KT_SPEC,9)
#define K_SCROLLFORW K(KT_SPEC,10)
#define K_SCROLLBACK K(KT_SPEC,11)
#define K_BOOT K(KT_SPEC,12)
#define K_CAPSON K(KT_SPEC,13)
#define K_COMPOSE K(KT_SPEC,14)
#define K_SAK K(KT_SPEC,15)
#define K_DECRCONSOLE K(KT_SPEC,16)
#define K_INCRCONSOLE K(KT_SPEC,17)
#define K_SPAWNCONSOLE K(KT_SPEC,18)
#define K_BARENUMLOCK K(KT_SPEC,19)
#define K_ALLOCATED K(KT_SPEC,126) /* dynamically allocated keymap */
#define K_NOSUCHMAP K(KT_SPEC,127) /* returned by KDGKBENT */
#define K_P0 K(KT_PAD,0)
#define K_P1 K(KT_PAD,1)
#define K_P2 K(KT_PAD,2)
#define K_P3 K(KT_PAD,3)
#define K_P4 K(KT_PAD,4)
#define K_P5 K(KT_PAD,5)
#define K_P6 K(KT_PAD,6)
#define K_P7 K(KT_PAD,7)
#define K_P8 K(KT_PAD,8)
#define K_P9 K(KT_PAD,9)
#define K_PPLUS K(KT_PAD,10) /* key-pad plus */
#define K_PMINUS K(KT_PAD,11) /* key-pad minus */
#define K_PSTAR K(KT_PAD,12) /* key-pad asterisk (star) */
#define K_PSLASH K(KT_PAD,13) /* key-pad slash */
#define K_PENTER K(KT_PAD,14) /* key-pad enter */
#define K_PCOMMA K(KT_PAD,15) /* key-pad comma: kludge... */
#define K_PDOT K(KT_PAD,16) /* key-pad dot (period): kludge... */
#define K_PPLUSMINUS K(KT_PAD,17) /* key-pad plus/minus */
#define K_PPARENL K(KT_PAD,18) /* key-pad left parenthesis */
#define K_PPARENR K(KT_PAD,19) /* key-pad right parenthesis */
#define NR_PAD 20
#define K_DGRAVE K(KT_DEAD,0)
#define K_DACUTE K(KT_DEAD,1)
#define K_DCIRCM K(KT_DEAD,2)
#define K_DTILDE K(KT_DEAD,3)
#define K_DDIERE K(KT_DEAD,4)
#define K_DCEDIL K(KT_DEAD,5)
#define NR_DEAD 6
#define K_DOWN K(KT_CUR,0)
#define K_LEFT K(KT_CUR,1)
#define K_RIGHT K(KT_CUR,2)
#define K_UP K(KT_CUR,3)
#define K_SHIFT K(KT_SHIFT,KG_SHIFT)
#define K_CTRL K(KT_SHIFT,KG_CTRL)
#define K_ALT K(KT_SHIFT,KG_ALT)
#define K_ALTGR K(KT_SHIFT,KG_ALTGR)
#define K_SHIFTL K(KT_SHIFT,KG_SHIFTL)
#define K_SHIFTR K(KT_SHIFT,KG_SHIFTR)
#define K_CTRLL K(KT_SHIFT,KG_CTRLL)
#define K_CTRLR K(KT_SHIFT,KG_CTRLR)
#define K_CAPSSHIFT K(KT_SHIFT,KG_CAPSSHIFT)
#define K_ASC0 K(KT_ASCII,0)
#define K_ASC1 K(KT_ASCII,1)
#define K_ASC2 K(KT_ASCII,2)
#define K_ASC3 K(KT_ASCII,3)
#define K_ASC4 K(KT_ASCII,4)
#define K_ASC5 K(KT_ASCII,5)
#define K_ASC6 K(KT_ASCII,6)
#define K_ASC7 K(KT_ASCII,7)
#define K_ASC8 K(KT_ASCII,8)
#define K_ASC9 K(KT_ASCII,9)
#define K_HEX0 K(KT_ASCII,10)
#define K_HEX1 K(KT_ASCII,11)
#define K_HEX2 K(KT_ASCII,12)
#define K_HEX3 K(KT_ASCII,13)
#define K_HEX4 K(KT_ASCII,14)
#define K_HEX5 K(KT_ASCII,15)
#define K_HEX6 K(KT_ASCII,16)
#define K_HEX7 K(KT_ASCII,17)
#define K_HEX8 K(KT_ASCII,18)
#define K_HEX9 K(KT_ASCII,19)
#define K_HEXa K(KT_ASCII,20)
#define K_HEXb K(KT_ASCII,21)
#define K_HEXc K(KT_ASCII,22)
#define K_HEXd K(KT_ASCII,23)
#define K_HEXe K(KT_ASCII,24)
#define K_HEXf K(KT_ASCII,25)
#define NR_ASCII 26
#define K_SHIFTLOCK K(KT_LOCK,KG_SHIFT)
#define K_CTRLLOCK K(KT_LOCK,KG_CTRL)
#define K_ALTLOCK K(KT_LOCK,KG_ALT)
#define K_ALTGRLOCK K(KT_LOCK,KG_ALTGR)
#define K_SHIFTLLOCK K(KT_LOCK,KG_SHIFTL)
#define K_SHIFTRLOCK K(KT_LOCK,KG_SHIFTR)
#define K_CTRLLLOCK K(KT_LOCK,KG_CTRLL)
#define K_CTRLRLOCK K(KT_LOCK,KG_CTRLR)
#define K_SHIFT_SLOCK K(KT_SLOCK,KG_SHIFT)
#define K_CTRL_SLOCK K(KT_SLOCK,KG_CTRL)
#define K_ALT_SLOCK K(KT_SLOCK,KG_ALT)
#define K_ALTGR_SLOCK K(KT_SLOCK,KG_ALTGR)
#define K_SHIFTL_SLOCK K(KT_SLOCK,KG_SHIFTL)
#define K_SHIFTR_SLOCK K(KT_SLOCK,KG_SHIFTR)
#define K_CTRLL_SLOCK K(KT_SLOCK,KG_CTRLL)
#define K_CTRLR_SLOCK K(KT_SLOCK,KG_CTRLR)
#define NR_LOCK 8
#define MAX_DIACR 256
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,778 @@
/*
* This software is Copyright (C) 1998 by T.sqware - all rights limited
* It is provided in to the public domain "as is", can be freely modified
* as far as this copyight notice is kept unchanged, but does not imply
* an endorsement by T.sqware of the product in which it is included.
*
* $Id$
*/
#include <bsp.h>
#include <bsp/irq.h>
#include <bsp/uart.h>
#include <rtems/libio.h>
#include <assert.h>
/*
* Basic 16552 driver
*/
struct uart_data
{
int hwFlow;
int baud;
};
static struct uart_data uart_data[2];
/*
* Macros to read/wirte register of uart, if configuration is
* different just rewrite these macros
*/
static inline unsigned char
uread(int uart, unsigned int reg)
{
register unsigned char val;
if(uart == 0)
{
inport_byte(COM1_BASE_IO+reg, val);
}
else
{
inport_byte(COM2_BASE_IO+reg, val);
}
return val;
}
static inline void
uwrite(int uart, int reg, unsigned int val)
{
if(uart == 0)
{
outport_byte(COM1_BASE_IO+reg, val);
}
else
{
outport_byte(COM2_BASE_IO+reg, val);
}
}
#ifdef UARTDEBUG
static void
uartError(int uart)
{
unsigned char uartStatus, dummy;
uartStatus = uread(uart, LSR);
dummy = uread(uart, RBR);
if (uartStatus & OE)
printk("********* Over run Error **********\n");
if (uartStatus & PE)
printk("********* Parity Error **********\n");
if (uartStatus & FE)
printk("********* Framing Error **********\n");
if (uartStatus & BI)
printk("********* Parity Error **********\n");
if (uartStatus & ERFIFO)
printk("********* Error receive Fifo **********\n");
}
#else
inline void uartError(int uart)
{
unsigned char uartStatus;
uartStatus = uread(uart, LSR);
uartStatus = uread(uart, RBR);
}
#endif
/*
* Uart initialization, it is hardcoded to 8 bit, no parity,
* one stop bit, FIFO, things to be changed
* are baud rate and nad hw flow control,
* and longest rx fifo setting
*/
void
BSP_uart_init(int uart, int baud, int hwFlow)
{
unsigned char tmp;
/* Sanity check */
assert(uart == BSP_UART_COM1 || uart == BSP_UART_COM2);
switch(baud)
{
case 50:
case 75:
case 110:
case 134:
case 300:
case 600:
case 1200:
case 2400:
case 9600:
case 19200:
case 38400:
case 57600:
case 115200:
break;
default:
assert(0);
return;
}
/* Set DLAB bit to 1 */
uwrite(uart, LCR, DLAB);
/* Set baud rate */
uwrite(uart, DLL, (BSPBaseBaud/baud) & 0xff);
uwrite(uart, DLM, ((BSPBaseBaud/baud) >> 8) & 0xff);
/* 8-bit, no parity , 1 stop */
uwrite(uart, LCR, CHR_8_BITS);
/* Set DTR, RTS and OUT2 high */
uwrite(uart, MCR, DTR | RTS | OUT_2);
/* Enable FIFO */
uwrite(uart, FCR, FIFO_EN | XMIT_RESET | RCV_RESET | RECEIVE_FIFO_TRIGGER12);
/* Disable Interrupts */
uwrite(uart, IER, 0);
/* Read status to clear them */
tmp = uread(uart, LSR);
tmp = uread(uart, RBR);
tmp = uread(uart, MSR);
/* Remember state */
uart_data[uart].hwFlow = hwFlow;
uart_data[uart].baud = baud;
return;
}
/*
* Set baud
*/
void
BSP_uart_set_baud(int uart, int baud)
{
unsigned char mcr, ier;
/* Sanity check */
assert(uart == BSP_UART_COM1 || uart == BSP_UART_COM2);
/*
* This function may be called whenever TERMIOS parameters
* are changed, so we have to make sire that baud change is
* indeed required
*/
if(baud == uart_data[uart].baud)
{
return;
}
mcr = uread(uart, MCR);
ier = uread(uart, IER);
BSP_uart_init(uart, baud, uart_data[uart].hwFlow);
uwrite(uart, MCR, mcr);
uwrite(uart, IER, ier);
return;
}
/*
* Enable/disable interrupts
*/
void
BSP_uart_intr_ctrl(int uart, int cmd)
{
assert(uart == BSP_UART_COM1 || uart == BSP_UART_COM2);
switch(cmd)
{
case BSP_UART_INTR_CTRL_DISABLE:
uwrite(uart, IER, INTERRUPT_DISABLE);
break;
case BSP_UART_INTR_CTRL_ENABLE:
if(uart_data[uart].hwFlow)
{
uwrite(uart, IER,
(RECEIVE_ENABLE |
TRANSMIT_ENABLE |
RECEIVER_LINE_ST_ENABLE |
MODEM_ENABLE
)
);
}
else
{
uwrite(uart, IER,
(RECEIVE_ENABLE |
TRANSMIT_ENABLE |
RECEIVER_LINE_ST_ENABLE
)
);
}
break;
case BSP_UART_INTR_CTRL_TERMIOS:
if(uart_data[uart].hwFlow)
{
uwrite(uart, IER,
(RECEIVE_ENABLE |
RECEIVER_LINE_ST_ENABLE |
MODEM_ENABLE
)
);
}
else
{
uwrite(uart, IER,
(RECEIVE_ENABLE |
RECEIVER_LINE_ST_ENABLE
)
);
}
break;
case BSP_UART_INTR_CTRL_GDB:
uwrite(uart, IER, RECEIVE_ENABLE);
break;
default:
assert(0);
break;
}
return;
}
void
BSP_uart_throttle(int uart)
{
unsigned int mcr;
assert(uart == BSP_UART_COM1 || uart == BSP_UART_COM2);
if(!uart_data[uart].hwFlow)
{
/* Should not happen */
assert(0);
return;
}
mcr = uread (uart, MCR);
/* RTS down */
mcr &= ~RTS;
uwrite(uart, MCR, mcr);
return;
}
void
BSP_uart_unthrottle(int uart)
{
unsigned int mcr;
assert(uart == BSP_UART_COM1 || uart == BSP_UART_COM2);
if(!uart_data[uart].hwFlow)
{
/* Should not happen */
assert(0);
return;
}
mcr = uread (uart, MCR);
/* RTS up */
mcr |= RTS;
uwrite(uart, MCR, mcr);
return;
}
/*
* Status function, -1 if error
* detected, 0 if no received chars available,
* 1 if received char available, 2 if break
* is detected, it will eat break and error
* chars. It ignores overruns - we cannot do
* anything about - it execpt count statistics
* and we are not counting it.
*/
int
BSP_uart_polled_status(int uart)
{
unsigned char val;
assert(uart == BSP_UART_COM1 || uart == BSP_UART_COM2);
val = uread(uart, LSR);
if(val & BI)
{
/* BREAK found, eat character */
uread(uart, RBR);
return BSP_UART_STATUS_BREAK;
}
if((val & (DR | OE | FE)) == 1)
{
/* No error, character present */
return BSP_UART_STATUS_CHAR;
}
if((val & (DR | OE | FE)) == 0)
{
/* Nothing */
return BSP_UART_STATUS_NOCHAR;
}
/*
* Framing or parity error
* eat character
*/
uread(uart, RBR);
return BSP_UART_STATUS_ERROR;
}
/*
* Polled mode write function
*/
void
BSP_uart_polled_write(int uart, int val)
{
unsigned char val1;
/* Sanity check */
assert(uart == BSP_UART_COM1 || uart == BSP_UART_COM2);
for(;;)
{
if((val1=uread(uart, LSR)) & THRE)
{
break;
}
}
if(uart_data[uart].hwFlow)
{
for(;;)
{
if(uread(uart, MSR) & CTS)
{
break;
}
}
}
uwrite(uart, THR, val & 0xff);
return;
}
void
BSP_output_char_via_serial(int val)
{
BSP_uart_polled_write(BSPConsolePort, val);
if (val == '\n') BSP_uart_polled_write(BSPConsolePort,'\r');
}
/*
* Polled mode read function
*/
int
BSP_uart_polled_read(int uart)
{
unsigned char val;
assert(uart == BSP_UART_COM1 || uart == BSP_UART_COM2);
for(;;)
{
if(uread(uart, LSR) & DR)
{
break;
}
}
val = uread(uart, RBR);
return (int)(val & 0xff);
}
unsigned
BSP_poll_char_via_serial()
{
return BSP_uart_polled_read(BSPConsolePort);
}
/* ================ Termios support =================*/
static volatile int termios_stopped_com1 = 0;
static volatile int termios_tx_active_com1 = 0;
static void* termios_ttyp_com1 = NULL;
static char termios_tx_hold_com1 = 0;
static volatile char termios_tx_hold_valid_com1 = 0;
static volatile int termios_stopped_com2 = 0;
static volatile int termios_tx_active_com2 = 0;
static void* termios_ttyp_com2 = NULL;
static char termios_tx_hold_com2 = 0;
static volatile char termios_tx_hold_valid_com2 = 0;
/*
* Set channel parameters
*/
void
BSP_uart_termios_set(int uart, void *ttyp)
{
unsigned char val;
assert(uart == BSP_UART_COM1 || uart == BSP_UART_COM2);
if(uart == BSP_UART_COM1)
{
if(uart_data[uart].hwFlow)
{
val = uread(uart, MSR);
termios_stopped_com1 = (val & CTS) ? 0 : 1;
}
else
{
termios_stopped_com1 = 0;
}
termios_tx_active_com1 = 0;
termios_ttyp_com1 = ttyp;
termios_tx_hold_com1 = 0;
termios_tx_hold_valid_com1 = 0;
}
else
{
if(uart_data[uart].hwFlow)
{
val = uread(uart, MSR);
termios_stopped_com2 = (val & CTS) ? 0 : 1;
}
else
{
termios_stopped_com2 = 0;
}
termios_tx_active_com2 = 0;
termios_ttyp_com2 = ttyp;
termios_tx_hold_com2 = 0;
termios_tx_hold_valid_com2 = 0;
}
return;
}
int
BSP_uart_termios_write_com1(int minor, const char *buf, int len)
{
assert(buf != NULL);
if(len <= 0)
{
return 0;
}
/* If there TX buffer is busy - something is royally screwed up */
/* assert((uread(BSP_UART_COM1, LSR) & THRE) != 0); */
if(termios_stopped_com1)
{
/* CTS low */
termios_tx_hold_com1 = *buf;
termios_tx_hold_valid_com1 = 1;
return 0;
}
/* Write character */
uwrite(BSP_UART_COM1, THR, *buf & 0xff);
/* Enable interrupts if necessary */
if(!termios_tx_active_com1 && uart_data[BSP_UART_COM1].hwFlow)
{
termios_tx_active_com1 = 1;
uwrite(BSP_UART_COM1, IER,
(RECEIVE_ENABLE |
TRANSMIT_ENABLE |
RECEIVER_LINE_ST_ENABLE |
MODEM_ENABLE
)
);
}
else if(!termios_tx_active_com1)
{
termios_tx_active_com1 = 1;
uwrite(BSP_UART_COM1, IER,
(RECEIVE_ENABLE |
TRANSMIT_ENABLE |
RECEIVER_LINE_ST_ENABLE
)
);
}
return 0;
}
int
BSP_uart_termios_write_com2(int minor, const char *buf, int len)
{
assert(buf != NULL);
if(len <= 0)
{
return 0;
}
/* If there TX buffer is busy - something is royally screwed up */
assert((uread(BSP_UART_COM2, LSR) & THRE) != 0);
if(termios_stopped_com2)
{
/* CTS low */
termios_tx_hold_com2 = *buf;
termios_tx_hold_valid_com2 = 1;
return 0;
}
/* Write character */
uwrite(BSP_UART_COM2, THR, *buf & 0xff);
/* Enable interrupts if necessary */
if(!termios_tx_active_com2 && uart_data[BSP_UART_COM2].hwFlow)
{
termios_tx_active_com2 = 1;
uwrite(BSP_UART_COM2, IER,
(RECEIVE_ENABLE |
TRANSMIT_ENABLE |
RECEIVER_LINE_ST_ENABLE |
MODEM_ENABLE
)
);
}
else if(!termios_tx_active_com2)
{
termios_tx_active_com2 = 1;
uwrite(BSP_UART_COM2, IER,
(RECEIVE_ENABLE |
TRANSMIT_ENABLE |
RECEIVER_LINE_ST_ENABLE
)
);
}
return 0;
}
void
BSP_uart_termios_isr_com1(void)
{
unsigned char buf[40];
unsigned char val;
int off, ret, vect;
off = 0;
for(;;)
{
vect = uread(BSP_UART_COM1, IIR) & 0xf;
switch(vect)
{
case MODEM_STATUS :
val = uread(BSP_UART_COM1, MSR);
if(uart_data[BSP_UART_COM1].hwFlow)
{
if(val & CTS)
{
/* CTS high */
termios_stopped_com1 = 0;
if(termios_tx_hold_valid_com1)
{
termios_tx_hold_valid_com1 = 0;
BSP_uart_termios_write_com1(0, &termios_tx_hold_com1,
1);
}
}
else
{
/* CTS low */
termios_stopped_com1 = 1;
}
}
break;
case NO_MORE_INTR :
/* No more interrupts */
if(off != 0)
{
/* Update rx buffer */
rtems_termios_enqueue_raw_characters(termios_ttyp_com1,
(char *)buf,
off);
}
return;
case TRANSMITTER_HODING_REGISTER_EMPTY :
/*
* TX holding empty: we have to disable these interrupts
* if there is nothing more to send.
*/
ret = rtems_termios_dequeue_characters(termios_ttyp_com1, 1);
/* If nothing else to send disable interrupts */
if(ret == 0 && uart_data[BSP_UART_COM1].hwFlow)
{
uwrite(BSP_UART_COM1, IER,
(RECEIVE_ENABLE |
RECEIVER_LINE_ST_ENABLE |
MODEM_ENABLE
)
);
termios_tx_active_com1 = 0;
}
else if(ret == 0)
{
uwrite(BSP_UART_COM1, IER,
(RECEIVE_ENABLE |
RECEIVER_LINE_ST_ENABLE
)
);
termios_tx_active_com1 = 0;
}
break;
case RECEIVER_DATA_AVAIL :
case CHARACTER_TIMEOUT_INDICATION:
/* RX data ready */
assert(off < sizeof(buf));
buf[off++] = uread(BSP_UART_COM1, RBR);
break;
case RECEIVER_ERROR:
/* RX error: eat character */
uartError(BSP_UART_COM1);
break;
default:
/* Should not happen */
assert(0);
return;
}
}
}
void
BSP_uart_termios_isr_com2()
{
unsigned char buf[40];
unsigned char val;
int off, ret, vect;
off = 0;
for(;;)
{
vect = uread(BSP_UART_COM2, IIR) & 0xf;
switch(vect)
{
case MODEM_STATUS :
val = uread(BSP_UART_COM2, MSR);
if(uart_data[BSP_UART_COM2].hwFlow)
{
if(val & CTS)
{
/* CTS high */
termios_stopped_com2 = 0;
if(termios_tx_hold_valid_com2)
{
termios_tx_hold_valid_com2 = 0;
BSP_uart_termios_write_com2(0, &termios_tx_hold_com2,
1);
}
}
else
{
/* CTS low */
termios_stopped_com2 = 1;
}
}
break;
case NO_MORE_INTR :
/* No more interrupts */
if(off != 0)
{
/* Update rx buffer */
rtems_termios_enqueue_raw_characters(termios_ttyp_com2,
(char *)buf,
off);
}
return;
case TRANSMITTER_HODING_REGISTER_EMPTY :
/*
* TX holding empty: we have to disable these interrupts
* if there is nothing more to send.
*/
ret = rtems_termios_dequeue_characters(termios_ttyp_com2, 1);
/* If nothing else to send disable interrupts */
if(ret == 0 && uart_data[BSP_UART_COM2].hwFlow)
{
uwrite(BSP_UART_COM2, IER,
(RECEIVE_ENABLE |
RECEIVER_LINE_ST_ENABLE |
MODEM_ENABLE
)
);
termios_tx_active_com2 = 0;
}
else if(ret == 0)
{
uwrite(BSP_UART_COM2, IER,
(RECEIVE_ENABLE |
RECEIVER_LINE_ST_ENABLE
)
);
termios_tx_active_com2 = 0;
}
break;
case RECEIVER_DATA_AVAIL :
case CHARACTER_TIMEOUT_INDICATION:
/* RX data ready */
assert(off < sizeof(buf));
buf[off++] = uread(BSP_UART_COM2, RBR);
break;
case RECEIVER_ERROR:
/* RX error: eat character */
uartError(BSP_UART_COM2);
break;
default:
/* Should not happen */
assert(0);
return;
}
}
}

View File

@@ -0,0 +1,169 @@
/*
* This software is Copyright (C) 1998 by T.sqware - all rights limited
* It is provided in to the public domain "as is", can be freely modified
* as far as this copyight notice is kept unchanged, but does not imply
* an endorsement by T.sqware of the product in which it is included.
*/
#ifndef _BSPUART_H
#define _BSPUART_H
void BSP_uart_init(int uart, int baud, int hwFlow);
void BSP_uart_set_baud(int aurt, int baud);
void BSP_uart_intr_ctrl(int uart, int cmd);
void BSP_uart_throttle(int uart);
void BSP_uart_unthrottle(int uart);
int BSP_uart_polled_status(int uart);
void BSP_uart_polled_write(int uart, int val);
int BSP_uart_polled_read(int uart);
void BSP_uart_termios_set(int uart, void *ttyp);
int BSP_uart_termios_write_com1(int minor, const char *buf, int len);
int BSP_uart_termios_write_com2(int minor, const char *buf, int len);
void BSP_uart_termios_isr_com1();
void BSP_uart_termios_isr_com2();
void BSP_uart_dbgisr_com1(void);
void BSP_uart_dbgisr_com2(void);
extern unsigned BSP_poll_char_via_serial(void);
extern void BSP_output_char_via_serial(int val);
extern int BSPConsolePort;
extern int BSPBaseBaud;
/*
* Command values for BSP_uart_intr_ctrl(),
* values are strange in order to catch errors
* with assert
*/
#define BSP_UART_INTR_CTRL_DISABLE (0)
#define BSP_UART_INTR_CTRL_GDB (0xaa) /* RX only */
#define BSP_UART_INTR_CTRL_ENABLE (0xbb) /* Normal operations */
#define BSP_UART_INTR_CTRL_TERMIOS (0xcc) /* RX & line status */
/* Return values for uart_polled_status() */
#define BSP_UART_STATUS_ERROR (-1) /* No character */
#define BSP_UART_STATUS_NOCHAR (0) /* No character */
#define BSP_UART_STATUS_CHAR (1) /* Character present */
#define BSP_UART_STATUS_BREAK (2) /* Break point is detected */
/* PC UART definitions */
#define BSP_UART_COM1 (0)
#define BSP_UART_COM2 (1)
/*
* Base IO for UART
*/
#define COM1_BASE_IO 0x3F8
#define COM2_BASE_IO 0x2F8
/*
* Offsets from base
*/
/* DLAB 0 */
#define RBR (0) /* Rx Buffer Register (read) */
#define THR (0) /* Tx Buffer Register (write) */
#define IER (1) /* Interrupt Enable Register */
/* DLAB X */
#define IIR (2) /* Interrupt Ident Register (read) */
#define FCR (2) /* FIFO Control Register (write) */
#define LCR (3) /* Line Control Register */
#define MCR (4) /* Modem Control Register */
#define LSR (5) /* Line Status Register */
#define MSR (6) /* Modem Status Register */
#define SCR (7) /* Scratch register */
/* DLAB 1 */
#define DLL (0) /* Divisor Latch, LSB */
#define DLM (1) /* Divisor Latch, MSB */
#define AFR (2) /* Alternate Function register */
/*
* Interrupt source definition via IIR
*/
#define MODEM_STATUS 0
#define NO_MORE_INTR 1
#define TRANSMITTER_HODING_REGISTER_EMPTY 2
#define RECEIVER_DATA_AVAIL 4
#define RECEIVER_ERROR 6
#define CHARACTER_TIMEOUT_INDICATION 12
/*
* Bits definition of IER
*/
#define RECEIVE_ENABLE 0x1
#define TRANSMIT_ENABLE 0x2
#define RECEIVER_LINE_ST_ENABLE 0x4
#define MODEM_ENABLE 0x8
#define INTERRUPT_DISABLE 0x0
/*
* Bits definition of the Line Status Register (LSR)
*/
#define DR 0x01 /* Data Ready */
#define OE 0x02 /* Overrun Error */
#define PE 0x04 /* Parity Error */
#define FE 0x08 /* Framing Error */
#define BI 0x10 /* Break Interrupt */
#define THRE 0x20 /* Transmitter Holding Register Empty */
#define TEMT 0x40 /* Transmitter Empty */
#define ERFIFO 0x80 /* Error receive Fifo */
/*
* Bits definition of the MODEM Control Register (MCR)
*/
#define DTR 0x01 /* Data Terminal Ready */
#define RTS 0x02 /* Request To Send */
#define OUT_1 0x04 /* Output 1, (reserved on COMPAQ I/O Board) */
#define OUT_2 0x08 /* Output 2, Enable Asynchronous Port Interrupts */
#define LB 0x10 /* Enable Internal Loop Back */
/*
* Bits definition of the Line Control Register (LCR)
*/
#define CHR_5_BITS 0
#define CHR_6_BITS 1
#define CHR_7_BITS 2
#define CHR_8_BITS 3
#define WL 0x03 /* Word length mask */
#define STB 0x04 /* 1 Stop Bit, otherwise 2 Stop Bits */
#define PEN 0x08 /* Parity Enabled */
#define EPS 0x10 /* Even Parity Select, otherwise Odd */
#define SP 0x20 /* Stick Parity */
#define BCB 0x40 /* Break Control Bit */
#define DLAB 0x80 /* Enable Divisor Latch Access */
/*
* Bits definition of the MODEM Status Register (MSR)
*/
#define DCTS 0x01 /* Delta Clear To Send */
#define DDSR 0x02 /* Delta Data Set Ready */
#define TERI 0x04 /* Trailing Edge Ring Indicator */
#define DDCD 0x08 /* Delta Carrier Detect Indicator */
#define CTS 0x10 /* Clear To Send (when loop back is active) */
#define DSR 0x20 /* Data Set Ready (when loop back is active) */
#define RI 0x40 /* Ring Indicator (when loop back is active) */
#define DCD 0x80 /* Data Carrier Detect (when loop back is active) */
/*
* Bits definition of the FIFO Control Register : WD16C552 or NS16550
*/
#define FIFO_CTRL 0x01 /* Set to 1 permit access to other bits */
#define FIFO_EN 0x01 /* Enable the FIFO */
#define XMIT_RESET 0x02 /* Transmit FIFO Reset */
#define RCV_RESET 0x04 /* Receive FIFO Reset */
#define FCR3 0x08 /* do not understand manual! */
#define RECEIVE_FIFO_TRIGGER1 0x0 /* trigger recieve interrupt after 1 byte */
#define RECEIVE_FIFO_TRIGGER4 0x40 /* trigger recieve interrupt after 4 byte */
#define RECEIVE_FIFO_TRIGGER8 0x80 /* trigger recieve interrupt after 8 byte */
#define RECEIVE_FIFO_TRIGGER12 0xc0 /* trigger recieve interrupt after 12 byte */
#define TRIG_LEVEL 0xc0 /* Mask for the trigger level */
#endif /* _BSPUART_H */

View File

@@ -0,0 +1,32 @@
#
# $Id$
#
@SET_MAKE@
srcdir = @srcdir@
top_srcdir = @top_srcdir@
top_builddir = ../../..
subdir = powerpc/shared/dec21140
RTEMS_ROOT = @RTEMS_ROOT@
PROJECT_ROOT = @PROJECT_ROOT@
VPATH = @srcdir@
H_FILES =
SRCS = $(C_FILES) $(H_FILES)
include $(RTEMS_ROOT)/make/custom/@RTEMS_BSP@.cfg
include $(RTEMS_ROOT)/make/leaf.cfg
INSTALL_CHANGE = @INSTALL_CHANGE@
all: ${ARCH} $(SRCS)
# the .rel file built here will be put into libbsp.a by ../wrapup/Makefile
install: all
Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
cd $(top_builddir) \
&& CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status

View File

@@ -0,0 +1,905 @@
/*
* RTEMS driver for TULIP based Ethernet Controller
*
* Copyright (C) 1999 Emmanuel Raguet. raguet@crf.canon.fr
*
* The license and distribution terms for this file may be
* found in found in the file LICENSE in this distribution or at
* http://www.OARcorp.com/rtems/license.html.
*
* $Id$
*/
#include <bsp.h>
#include <bsp/pci.h>
#include <stdlib.h>
#include <stdio.h>
#include <stdarg.h>
#include <rtems/error.h>
#include <rtems/rtems_bsdnet.h>
#include <libcpu/cpu.h>
#include <libcpu/io.h>
#include <libcpu/byteorder.h>
#include <sys/param.h>
#include <sys/mbuf.h>
#include <sys/socket.h>
#include <sys/sockio.h>
#include <net/if.h>
#include <netinet/in.h>
#include <netinet/if_ether.h>
#include <bsp/irq.h>
#ifdef malloc
#undef malloc
#endif
#ifdef free
#undef free
#endif
#define DEC_DEBUG
#define PCI_INVALID_VENDORDEVICEID 0xffffffff
#define PCI_VENDOR_ID_DEC 0x1011
#define PCI_DEVICE_ID_DEC_TULIP_FAST 0x0009
#define IO_MASK 0x3
#define MEM_MASK 0xF
#define MASK_OFFSET 0xF
/* command and status registers, 32-bit access, only if IO-ACCESS */
#define ioCSR0 0x00 /* bus mode register */
#define ioCSR1 0x08 /* transmit poll demand */
#define ioCSR2 0x10 /* receive poll demand */
#define ioCSR3 0x18 /* receive list base address */
#define ioCSR4 0x20 /* transmit list base address */
#define ioCSR5 0x28 /* status register */
#define ioCSR6 0x30 /* operation mode register */
#define ioCSR7 0x38 /* interrupt mask register */
#define ioCSR8 0x40 /* missed frame counter */
#define ioCSR9 0x48 /* Ethernet ROM register */
#define ioCSR10 0x50 /* reserved */
#define ioCSR11 0x58 /* full-duplex register */
#define ioCSR12 0x60 /* SIA status register */
#define ioCSR13 0x68
#define ioCSR14 0x70
#define ioCSR15 0x78 /* SIA general register */
/* command and status registers, 32-bit access, only if MEMORY-ACCESS */
#define memCSR0 0x00 /* bus mode register */
#define memCSR1 0x02 /* transmit poll demand */
#define memCSR2 0x04 /* receive poll demand */
#define memCSR3 0x06 /* receive list base address */
#define memCSR4 0x08 /* transmit list base address */
#define memCSR5 0x0A /* status register */
#define memCSR6 0x0C /* operation mode register */
#define memCSR7 0x0E /* interrupt mask register */
#define memCSR8 0x10 /* missed frame counter */
#define memCSR9 0x12 /* Ethernet ROM register */
#define memCSR10 0x14 /* reserved */
#define memCSR11 0x16 /* full-duplex register */
#define memCSR12 0x18 /* SIA status register */
#define memCSR13 0x1A
#define memCSR14 0x1C
#define memCSR15 0x1E /* SIA general register */
#define DEC_REGISTER_SIZE 0x100 /* to reserve virtual memory */
#define RESET_CHIP 0x00000001
#define CSR0_MODE 0x01b08000 /* 01a08000 */
#define ROM_ADDRESS 0x00004800
#define CSR6_INIT 0x020c0000 /* 020c0000 */
#define CSR6_TX 0x00002000
#define CSR6_TXRX 0x00002002
#define IT_SETUP 0x00010040 /* 0001ebef */
#define CLEAR_IT 0xFFFFFFFF
#define NO_IT 0x00000000
#define NRXBUFS 7 /* number of receive buffers */
#define NTXBUFS 1 /* number of transmit buffers */
/* message descriptor entry */
struct MD {
volatile unsigned long status;
volatile unsigned long counts;
volatile unsigned char *buf1, *buf2;
};
/*
* Number of WDs supported by this driver
*/
#define NDECDRIVER 1
/*
* Receive buffer size -- Allow for a full ethernet packet including CRC
*/
#define RBUF_SIZE 1536
#define ET_MINLEN 60 /* minimum message length */
/*
* RTEMS event used by interrupt handler to signal driver tasks.
* This must not be any of the events used by the network task synchronization.
*/
#define INTERRUPT_EVENT RTEMS_EVENT_1
/*
* RTEMS event used to start transmit daemon.
* This must not be the same as INTERRUPT_EVENT.
*/
#define START_TRANSMIT_EVENT RTEMS_EVENT_2
#if (MCLBYTES < RBUF_SIZE)
# error "Driver must have MCLBYTES > RBUF_SIZE"
#endif
/*
* Per-device data
*/
struct dec21140_softc {
struct arpcom arpcom;
rtems_irq_connect_data irqInfo;
volatile struct MD *MDbase;
volatile unsigned char *bufferBase;
int acceptBroadcast;
int rxBdCount;
int txBdCount;
rtems_id rxDaemonTid;
rtems_id txDaemonTid;
unsigned int port;
volatile unsigned int *base;
unsigned long bpar;
/*
* Statistics
*/
unsigned long rxInterrupts;
unsigned long rxNotFirst;
unsigned long rxNotLast;
unsigned long rxGiant;
unsigned long rxNonOctet;
unsigned long rxRunt;
unsigned long rxBadCRC;
unsigned long rxOverrun;
unsigned long rxCollision;
unsigned long txInterrupts;
unsigned long txDeferred;
unsigned long txHeartbeat;
unsigned long txLateCollision;
unsigned long txRetryLimit;
unsigned long txUnderrun;
unsigned long txLostCarrier;
unsigned long txRawWait;
};
static struct dec21140_softc dec21140_softc[NDECDRIVER];
/*
* DEC21140 interrupt handler
*/
static rtems_isr
dec21140Enet_interrupt_handler (rtems_vector_number v)
{
volatile unsigned int *tbase;
unsigned long status;
unsigned int sc;
tbase = dec21140_softc[0].base ;
/*
* Read status
*/
st_le32((tbase+memCSR7), NO_IT);
status = ld_le32(tbase+memCSR5);
st_le32((tbase+memCSR5), CLEAR_IT);
/*
* Frame received?
*/
if (status & 0x00000040){
dec21140_softc[0].rxInterrupts++;
sc = rtems_event_send (dec21140_softc[0].rxDaemonTid, INTERRUPT_EVENT);
}
}
static void nopOn(const rtems_irq_connect_data* notUsed)
{
/*
* code should be moved from dec21140Enet_initialize_hardware
* to this location
*/
}
static int dec21140IsOn(const rtems_irq_connect_data* irq)
{
return BSP_irq_enabled_at_i8259s (irq->name);
}
/*
* Read and write the MII registers using software-generated serial
* MDIO protocol.
*/
#define MDIO_SHIFT_CLK 0x10000
#define MDIO_DATA_WRITE0 0x00000
#define MDIO_DATA_WRITE1 0x20000
#define MDIO_ENB 0x00000
#define MDIO_ENB_IN 0x40000
#define MDIO_DATA_READ 0x80000
static int mdio_read(volatile unsigned int *ioaddr, int phy_id, int location)
{
int i, i3;
int read_cmd = (0xf6 << 10) | (phy_id << 5) | location;
unsigned short retval = 0;
/* Establish sync by sending at least 32 logic ones. */
for (i = 32; i >= 0; i--) {
st_le32(ioaddr, MDIO_ENB | MDIO_DATA_WRITE1);
for(i3=0; i3<1000; i3++);
st_le32(ioaddr, MDIO_ENB | MDIO_DATA_WRITE1 | MDIO_SHIFT_CLK);
for(i3=0; i3<1000; i3++);
}
/* Shift the read command bits out. */
for (i = 17; i >= 0; i--) {
int dataval = (read_cmd & (1 << i)) ? MDIO_DATA_WRITE1 : 0;
st_le32(ioaddr, dataval);
for(i3=0; i3<1000; i3++);
st_le32(ioaddr, dataval | MDIO_SHIFT_CLK);
for(i3=0; i3<1000; i3++);
st_le32(ioaddr, dataval);
for(i3=0; i3<1000; i3++);
}
st_le32(ioaddr, MDIO_ENB_IN | MDIO_SHIFT_CLK);
for(i3=0; i3<1000; i3++);
st_le32(ioaddr, MDIO_ENB_IN);
for (i = 16; i > 0; i--) {
st_le32(ioaddr, MDIO_ENB_IN | MDIO_SHIFT_CLK);
for(i3=0; i3<1000; i3++);
retval = (retval << 1) | ((ld_le32(ioaddr) & MDIO_DATA_READ) ? 1 : 0);
st_le32(ioaddr, MDIO_ENB_IN);
for(i3=0; i3<1000; i3++);
}
/* Clear out extra bits. */
for (i = 16; i > 0; i--) {
st_le32(ioaddr, MDIO_ENB_IN | MDIO_SHIFT_CLK);
for(i3=0; i3<1000; i3++);
st_le32(ioaddr, MDIO_ENB_IN);
for(i3=0; i3<1000; i3++);
}
return ( ((retval<<8)&0xff00) | ((retval>>8)&0xff) );
}
static int mdio_write(volatile unsigned int *ioaddr, int phy_id, int location, int value)
{
int i, i3;
int cmd = (0x5002 << 16) | (phy_id << 23) | (location << 18) | value;
/* Establish sync by sending at least 32 logic ones. */
for (i = 32; i >= 0; i--) {
st_le32(ioaddr, MDIO_ENB | MDIO_DATA_WRITE1);
for(i3=0; i3<1000; i3++);
st_le32(ioaddr, MDIO_ENB | MDIO_DATA_WRITE1 | MDIO_SHIFT_CLK);
for(i3=0; i3<1000; i3++);
}
/* Shift the read command bits out. */
for (i = 31; i >= 0; i--) {
int dataval = (cmd & (1 << i)) ? MDIO_DATA_WRITE1 : 0;
st_le32(ioaddr, dataval);
for(i3=0; i3<1000; i3++);
st_le32(ioaddr, dataval | MDIO_SHIFT_CLK);
for(i3=0; i3<1000; i3++);
}
/* Clear out extra bits. */
for (i = 2; i > 0; i--) {
st_le32(ioaddr, MDIO_ENB_IN);
for(i3=0; i3<1000; i3++);
st_le32(ioaddr, MDIO_ENB_IN | MDIO_SHIFT_CLK);
for(i3=0; i3<1000; i3++);
}
return 0;
}
/*
* This routine reads a word (16 bits) from the serial EEPROM.
*/
/* EEPROM_Ctrl bits. */
#define EE_SHIFT_CLK 0x02 /* EEPROM shift clock. */
#define EE_CS 0x01 /* EEPROM chip select. */
#define EE_DATA_WRITE 0x04 /* EEPROM chip data in. */
#define EE_WRITE_0 0x01
#define EE_WRITE_1 0x05
#define EE_DATA_READ 0x08 /* EEPROM chip data out. */
#define EE_ENB (0x4800 | EE_CS)
/* The EEPROM commands include the alway-set leading bit. */
#define EE_WRITE_CMD (5 << 6)
#define EE_READ_CMD (6 << 6)
#define EE_ERASE_CMD (7 << 6)
static int eeget16(volatile unsigned int *ioaddr, int location)
{
int i, i3;
unsigned short retval = 0;
int read_cmd = location | EE_READ_CMD;
st_le32(ioaddr, EE_ENB & ~EE_CS);
st_le32(ioaddr, EE_ENB);
/* Shift the read command bits out. */
for (i = 10; i >= 0; i--) {
short dataval = (read_cmd & (1 << i)) ? EE_DATA_WRITE : 0;
st_le32(ioaddr, EE_ENB | dataval);
for (i3=0; i3<1000; i3++) ;
st_le32(ioaddr, EE_ENB | dataval | EE_SHIFT_CLK);
for (i3=0; i3<1000; i3++) ;
st_le32(ioaddr, EE_ENB | dataval); /* Finish EEPROM a clock tick. */
for (i3=0; i3<1000; i3++) ;
}
st_le32(ioaddr, EE_ENB);
for (i = 16; i > 0; i--) {
st_le32(ioaddr, EE_ENB | EE_SHIFT_CLK);
for (i3=0; i3<1000; i3++) ;
retval = (retval << 1) | ((ld_le32(ioaddr) & EE_DATA_READ) ? 1 : 0);
st_le32(ioaddr, EE_ENB);
for (i3=0; i3<1000; i3++) ;
}
/* Terminate the EEPROM access. */
st_le32(ioaddr, EE_ENB & ~EE_CS);
return ( ((retval<<8)&0xff00) | ((retval>>8)&0xff) );
}
/*
* Initialize the ethernet hardware
*/
static void
dec21140Enet_initialize_hardware (struct dec21140_softc *sc)
{
rtems_status_code st;
volatile unsigned int *tbase;
union {char c[64]; unsigned short s[32];} rombuf;
int i, i2, i3;
volatile unsigned char *cp, direction, *setup_frm, *eaddrs;
unsigned long csr12_val, mii_reg0;
volatile unsigned char *buffer;
volatile struct MD *rmd;
tbase = sc->base;
/*
* WARNING : First write in CSR6
* Then Reset the chip ( 1 in CSR0)
*/
st_le32( (tbase+memCSR6), CSR6_INIT);
st_le32( (tbase+memCSR0), RESET_CHIP);
for(i3=0; i3<1000; i3++);
/*
* Init CSR0
*/
st_le32( (tbase+memCSR0), CSR0_MODE);
csr12_val = ld_le32( (tbase+memCSR8) );
for (i=0; i<32; i++){
rombuf.s[i] = eeget16(tbase+memCSR9, i);
}
memcpy (sc->arpcom.ac_enaddr, rombuf.c+20, ETHER_ADDR_LEN);
mii_reg0 = mdio_read(tbase+memCSR9, 0, 0);
mdio_write(tbase+memCSR9, 0, 0, mii_reg0 | 0x1000);
#ifdef DEC_DEBUG
printk("DC21140 %x:%x:%x:%x:%x:%x IRQ %d IO %x M %x .........\n",
sc->arpcom.ac_enaddr[0], sc->arpcom.ac_enaddr[1],
sc->arpcom.ac_enaddr[2], sc->arpcom.ac_enaddr[3],
sc->arpcom.ac_enaddr[4], sc->arpcom.ac_enaddr[5],
sc->irqInfo.name, sc->port, (unsigned) sc->base);
#endif
/*
* Init RX ring
*/
sc->rxBdCount = 0;
cp = (volatile unsigned char *)malloc((NRXBUFS+NTXBUFS)*(sizeof(struct MD)+ RBUF_SIZE) + PPC_CACHE_ALIGNMENT);
sc->bufferBase = cp;
if ((unsigned int)cp & (PPC_CACHE_ALIGNMENT-1))
cp = (volatile unsigned char *) (((unsigned int)cp + PPC_CACHE_ALIGNMENT) & ~(PPC_CACHE_ALIGNMENT-1));
#ifdef PCI_BRIDGE_DOES_NOT_ENSURE_CACHE_COHERENCY_FOR_DMA
if (_CPU_is_paging_enabled())
_CPU_change_memory_mapping_attribute
(NULL, cp,
(NRXBUFS+NTXBUFS)*(sizeof(struct MD)+ RBUF_SIZE),
PTE_CACHE_DISABLE | PTE_WRITABLE);
#endif
rmd = (volatile struct MD*)cp;
sc->MDbase = rmd;
buffer = cp + ((NRXBUFS+NTXBUFS)*sizeof(struct MD));
st_le32( (tbase+memCSR3), (long)((long)(sc->MDbase) + PREP_PCI_DRAM_OFFSET));
for (i=0 ; i<NRXBUFS; i++){
rmd->buf2 = (volatile unsigned char *) 0;
rmd->buf1 = (buffer + (i*RBUF_SIZE) + PREP_PCI_DRAM_OFFSET);
rmd->counts = 0xfcc00000 | (RBUF_SIZE);
rmd->status = 0x80000000;
rmd++;
}
/*
* mark last RX buffer.
*/
sc->MDbase [NRXBUFS-1].counts = 0xfec00000 | (RBUF_SIZE);
/*
* Init TX ring
*/
sc->txBdCount = 0;
st_le32( (tbase+memCSR4), (long)(((long)(rmd)) + PREP_PCI_DRAM_OFFSET));
rmd->buf2 = (volatile unsigned char *) 0;
rmd->buf1 = buffer + (NRXBUFS*RBUF_SIZE) + PREP_PCI_DRAM_OFFSET;
rmd->counts = 0x62000000;
rmd->status = 0x0;
/*
* Set up interrupts
*/
st_le32( (tbase+memCSR5), IT_SETUP);
st_le32( (tbase+memCSR7), IT_SETUP);
sc->irqInfo.hdl = (rtems_irq_hdl)dec21140Enet_interrupt_handler;
sc->irqInfo.on = nopOn;
sc->irqInfo.off = nopOn;
sc->irqInfo.isOn = dec21140IsOn;
st = BSP_install_rtems_irq_handler (&sc->irqInfo);
if (!st)
rtems_panic ("Can't attach DEC21140 interrupt handler for irq %d\n",
sc->irqInfo.name);
/*
* Start TX for setup frame
*/
st_le32( (tbase+memCSR6), CSR6_INIT | CSR6_TX);
/*
* Build setup frame
*/
setup_frm = rmd->buf1 - PREP_PCI_DRAM_OFFSET;
eaddrs = (char *)(sc->arpcom.ac_enaddr);
/* Fill the buffer with our physical address. */
for (i = 1; i < 16; i++) {
*setup_frm++ = eaddrs[0];
*setup_frm++ = eaddrs[1];
*setup_frm++ = eaddrs[0];
*setup_frm++ = eaddrs[1];
*setup_frm++ = eaddrs[2];
*setup_frm++ = eaddrs[3];
*setup_frm++ = eaddrs[2];
*setup_frm++ = eaddrs[3];
*setup_frm++ = eaddrs[4];
*setup_frm++ = eaddrs[5];
*setup_frm++ = eaddrs[4];
*setup_frm++ = eaddrs[5];
}
/* Add the broadcast address when doing perfect filtering */
memset((void*) setup_frm, 0xff, 12);
rmd->counts = 0x0a000000 | 192 ;
rmd->status = 0x80000000;
st_le32( (tbase+memCSR1), 1);
while (rmd->status != 0x7fffffff);
/*
* Enable RX and TX
*/
st_le32( (unsigned int*)(tbase+memCSR6), CSR6_INIT | CSR6_TXRX);
/*
* Set up PHY
*/
i = rombuf.c[27];
i+=2;
direction = rombuf.c[i];
i +=4;
st_le32( (tbase+memCSR12), direction | 0x100);
for (i2 = 0; i2 < rombuf.c[(i+2) + rombuf.c[i+1]]; i2++){
st_le32( (tbase + memCSR12), rombuf.c[(i+3) + rombuf.c[i+1] + i2]);
}
for (i2 = 0; i2 < rombuf.c[i+1]; i2++){
st_le32( (tbase + memCSR12), rombuf.c[(i+2) + i2]);
}
}
static void
dec21140_rxDaemon (void *arg)
{
volatile unsigned int *tbase;
struct ether_header *eh;
struct dec21140_softc *dp = (struct dec21140_softc *)&dec21140_softc[0];
struct ifnet *ifp = &dp->arpcom.ac_if;
struct mbuf *m;
volatile struct MD *rmd;
unsigned int len;
char *temp;
rtems_event_set events;
int nbMD;
tbase = dec21140_softc[0].base ;
for (;;){
rtems_bsdnet_event_receive (INTERRUPT_EVENT,
RTEMS_WAIT|RTEMS_EVENT_ANY,
RTEMS_NO_TIMEOUT,
&events);
rmd = dec21140_softc[0].MDbase;
nbMD = 0;
while (nbMD < NRXBUFS){
if ( (rmd->status & 0x80000000) == 0){
len = (rmd->status >> 16) & 0x7ff;
MGETHDR (m, M_WAIT, MT_DATA);
MCLGET (m, M_WAIT);
m->m_pkthdr.rcvif = ifp;
temp = m->m_data;
m->m_len = m->m_pkthdr.len = len - sizeof(struct ether_header);
memcpy(temp, (void*) (rmd->buf1-PREP_PCI_DRAM_OFFSET), len);
rmd->status = 0x80000000;
eh = mtod (m, struct ether_header *);
m->m_data += sizeof(struct ether_header);
ether_input (ifp, eh, m);
}
rmd++;
nbMD++;
}
st_le32( (tbase+memCSR7), IT_SETUP);
}
}
static void
sendpacket (struct ifnet *ifp, struct mbuf *m)
{
struct dec21140_softc *dp = ifp->if_softc;
volatile struct MD *tmd;
volatile unsigned char *temp;
struct mbuf *n;
unsigned int len;
volatile unsigned int *tbase;
tbase = dp->base;
/*
* Waiting for Transmitter ready
*/
tmd = dec21140_softc[0].MDbase + NRXBUFS;
while ( (tmd->status & 0x80000000) != 0 );
len = 0;
n = m;
temp = tmd->buf1-PREP_PCI_DRAM_OFFSET;
for (;;){
len += m->m_len;
memcpy((void*) temp, (char *)m->m_data, m->m_len);
temp += m->m_len ;
if ((m = m->m_next) == NULL)
break;
}
if (len < ET_MINLEN) len = ET_MINLEN;
tmd->counts = 0xe2000000 | len;
tmd->status = 0x80000000;
st_le32( (tbase+memCSR1), 0x1);
m_freem(n);
}
/*
* Driver transmit daemon
*/
void
dec21140_txDaemon (void *arg)
{
struct dec21140_softc *sc = (struct dec21140_softc *)arg;
struct ifnet *ifp = &sc->arpcom.ac_if;
struct mbuf *m;
rtems_event_set events;
for (;;) {
/*
* Wait for packet
*/
rtems_bsdnet_event_receive (START_TRANSMIT_EVENT, RTEMS_EVENT_ANY | RTEMS_WAIT, RTEMS_NO_TIMEOUT, &events);
/*
* Send packets till queue is empty
*/
for (;;) {
/*
* Get the next mbuf chain to transmit.
*/
IF_DEQUEUE(&ifp->if_snd, m);
if (!m)
break;
sendpacket (ifp, m);
}
ifp->if_flags &= ~IFF_OACTIVE;
}
}
static void
dec21140_start (struct ifnet *ifp)
{
struct dec21140_softc *sc = ifp->if_softc;
rtems_event_send (sc->txDaemonTid, START_TRANSMIT_EVENT);
ifp->if_flags |= IFF_OACTIVE;
}
/*
* Initialize and start the device
*/
static void
dec21140_init (void *arg)
{
struct dec21140_softc *sc = arg;
struct ifnet *ifp = &sc->arpcom.ac_if;
if (sc->txDaemonTid == 0) {
/*
* Set up DEC21140 hardware
*/
dec21140Enet_initialize_hardware (sc);
/*
* Start driver tasks
*/
sc->rxDaemonTid = rtems_bsdnet_newproc ("DCrx", 4096,
dec21140_rxDaemon, sc);
sc->txDaemonTid = rtems_bsdnet_newproc ("DCtx", 4096,
dec21140_txDaemon, sc);
}
/*
* Tell the world that we're running.
*/
ifp->if_flags |= IFF_RUNNING;
}
/*
* Stop the device
*/
static void
dec21140_stop (struct dec21140_softc *sc)
{
volatile unsigned int *tbase;
struct ifnet *ifp = &sc->arpcom.ac_if;
ifp->if_flags &= ~IFF_RUNNING;
/*
* Stop the transmitter
*/
tbase=dec21140_softc[0].base ;
st_le32( (tbase+memCSR7), NO_IT);
st_le32( (tbase+memCSR6), CSR6_INIT);
free((void*)sc->bufferBase);
}
/*
* Show interface statistics
*/
static void
dec21140_stats (struct dec21140_softc *sc)
{
printf (" Rx Interrupts:%-8lu", sc->rxInterrupts);
printf (" Not First:%-8lu", sc->rxNotFirst);
printf (" Not Last:%-8lu\n", sc->rxNotLast);
printf (" Giant:%-8lu", sc->rxGiant);
printf (" Runt:%-8lu", sc->rxRunt);
printf (" Non-octet:%-8lu\n", sc->rxNonOctet);
printf (" Bad CRC:%-8lu", sc->rxBadCRC);
printf (" Overrun:%-8lu", sc->rxOverrun);
printf (" Collision:%-8lu\n", sc->rxCollision);
printf (" Tx Interrupts:%-8lu", sc->txInterrupts);
printf (" Deferred:%-8lu", sc->txDeferred);
printf (" Missed Hearbeat:%-8lu\n", sc->txHeartbeat);
printf (" No Carrier:%-8lu", sc->txLostCarrier);
printf ("Retransmit Limit:%-8lu", sc->txRetryLimit);
printf (" Late Collision:%-8lu\n", sc->txLateCollision);
printf (" Underrun:%-8lu", sc->txUnderrun);
printf (" Raw output wait:%-8lu\n", sc->txRawWait);
}
/*
* Driver ioctl handler
*/
static int
dec21140_ioctl (struct ifnet *ifp, int command, caddr_t data)
{
struct dec21140_softc *sc = ifp->if_softc;
int error = 0;
switch (command) {
case SIOCGIFADDR:
case SIOCSIFADDR:
ether_ioctl (ifp, command, data);
break;
case SIOCSIFFLAGS:
switch (ifp->if_flags & (IFF_UP | IFF_RUNNING)) {
case IFF_RUNNING:
dec21140_stop (sc);
break;
case IFF_UP:
dec21140_init (sc);
break;
case IFF_UP | IFF_RUNNING:
dec21140_stop (sc);
dec21140_init (sc);
break;
default:
break;
}
break;
case SIO_RTEMS_SHOW_STATS:
dec21140_stats (sc);
break;
/*
* FIXME: All sorts of multicast commands need to be added here!
*/
default:
error = EINVAL;
break;
}
return error;
}
/*
* Attach an DEC21140 driver to the system
*/
int
rtems_dec21140_driver_attach (struct rtems_bsdnet_ifconfig *config)
{
struct dec21140_softc *sc;
struct ifnet *ifp;
int mtu;
int i;
unsigned char ucSlotNumber, ucFnNumber;
unsigned int ulDeviceID, lvalue, tmp;
unsigned char cvalue;
/*
* First, find a DEC board
*/
for(ucSlotNumber=0;ucSlotNumber<PCI_MAX_DEVICES;ucSlotNumber++) {
for(ucFnNumber=0;ucFnNumber<PCI_MAX_FUNCTIONS;ucFnNumber++) {
(void)pci_read_config_dword(0,
ucSlotNumber,
ucFnNumber,
PCI_VENDOR_ID,
&ulDeviceID);
if(ulDeviceID==PCI_INVALID_VENDORDEVICEID) {
/*
* This slot is empty
*/
continue;
}
if (ulDeviceID == ((PCI_DEVICE_ID_DEC_TULIP_FAST<<16) + PCI_VENDOR_ID_DEC))
break;
}
if (ulDeviceID == ((PCI_DEVICE_ID_DEC_TULIP_FAST<<16) + PCI_VENDOR_ID_DEC)){
printk("DEC Adapter found !!\n");
break;
}
}
if(ulDeviceID==PCI_INVALID_VENDORDEVICEID)
rtems_panic("DEC PCI board not found !!\n");
/*
* Find a free driver
*/
for (i = 0 ; i < NDECDRIVER ; i++) {
sc = &dec21140_softc[i];
ifp = &sc->arpcom.ac_if;
if (ifp->if_softc == NULL)
break;
}
if (i >= NDECDRIVER) {
printk ("Too many DEC drivers.\n");
return 0;
}
/*
* Process options
*/
(void)pci_read_config_dword(0,
ucSlotNumber,
ucFnNumber,
PCI_BASE_ADDRESS_0,
&lvalue);
sc->port = lvalue & (unsigned int)(~IO_MASK);
(void)pci_read_config_dword(0,
ucSlotNumber,
ucFnNumber,
PCI_BASE_ADDRESS_1 ,
&lvalue);
tmp = (unsigned int)(lvalue & (unsigned int)(~MEM_MASK))
+ (unsigned int)PREP_ISA_MEM_BASE;
sc->base = (unsigned int *)(tmp);
(void)pci_read_config_byte(0,
ucSlotNumber,
ucFnNumber,
PCI_INTERRUPT_LINE,
&cvalue);
sc->irqInfo.name = (rtems_irq_symbolic_name)cvalue;
if (config->hardware_address) {
memcpy (sc->arpcom.ac_enaddr, config->hardware_address,
ETHER_ADDR_LEN);
}
else {
memset (sc->arpcom.ac_enaddr, 0x08,ETHER_ADDR_LEN);
}
if (config->mtu)
mtu = config->mtu;
else
mtu = ETHERMTU;
sc->acceptBroadcast = !config->ignore_broadcast;
/*
* Set up network interface values
*/
ifp->if_softc = sc;
ifp->if_unit = i + 1;
ifp->if_name = "dc";
ifp->if_mtu = mtu;
ifp->if_init = dec21140_init;
ifp->if_ioctl = dec21140_ioctl;
ifp->if_start = dec21140_start;
ifp->if_output = ether_output;
ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX;
if (ifp->if_snd.ifq_maxlen == 0)
ifp->if_snd.ifq_maxlen = ifqmaxlen;
/*
* Attach the interface
*/
if_attach (ifp);
ether_ifattach (ifp);
return 1;
};

View File

@@ -0,0 +1,48 @@
#
# $Id$
#
@SET_MAKE@
srcdir = @srcdir@
top_srcdir = @top_srcdir@
top_builddir = ../../..
subdir = powerpc/shared/include
RTEMS_ROOT = @RTEMS_ROOT@
PROJECT_ROOT = @PROJECT_ROOT@
VPATH = @srcdir@
H_FILES = $(srcdir)/nvram.h $(srcdir)/bsp.h
#
# Equate files are for including from assembly preprocessed by
# gm4 or gasp. No examples are provided except for those for
# other CPUs. The best way to generate them would be to
# provide a program which generates the constants used based
# on the C equivalents.
#
EQ_FILES =
SRCS = $(H_FILES) $(EQ_FILES)
include $(RTEMS_ROOT)/make/custom/@RTEMS_BSP@.cfg
include $(RTEMS_ROOT)/make/leaf.cfg
INSTALL_CHANGE = @INSTALL_CHANGE@
mkinstalldirs = $(SHELL) $(top_srcdir)/@RTEMS_TOPdir@/mkinstalldirs
INSTALLDIRS = $(PROJECT_INCLUDE)
$(INSTALLDIRS):
@$(mkinstalldirs) $(INSTALLDIRS)
CLEAN_ADDITIONS +=
CLOBBER_ADDITIONS +=
all: $(SRCS)
Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
cd $(top_builddir) \
&& CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status

View File

@@ -0,0 +1,57 @@
/*
* bsp.h -- contain BSP API definition.
*
* Copyright (C) 1999 Eric Valette. valette@crf.canon.fr
*
* The license and distribution terms for this file may be
* found in found in the file LICENSE in this distribution or at
* http://www.OARcorp.com/rtems/license.html.
*
* $Id$
*/
#ifndef LIBBSP_POWERPC_MCP750_BSP_H
#define LIBBSP_POWERPC_MCP750_BSP_H
#include <rtems.h>
#include <console.h>
#include <libcpu/io.h>
#include <clockdrv.h>
#include <bsp/vectors.h>
#ifndef ASM
#define outport_byte(port,value) outb(value,port)
#define outport_word(port,value) outw(value,port)
#define outport_long(port,value) outl(value,port)
#define inport_byte(port,value) (value = inb(port))
#define inport_word(port,value) (value = inw(port))
#define inport_long(port,value) (value = inl(port))
/*
* Vital Board data Start using DATA RESIDUAL
*/
/*
* Total memory using RESIDUAL DATA
*/
unsigned int BSP_mem_size;
/*
* PCI Bus Frequency
*/
unsigned int BSP_bus_frequency;
/*
* processor clock frequency
*/
unsigned int BSP_processor_frequency;
/*
* Time base divisior (how many tick for 1 second).
*/
unsigned int BSP_time_base_divisor;
extern rtems_configuration_table BSP_Configuration;
extern void BSP_panic(char *s);
extern void rtemsReboot(void);
extern int printk(const char *, ...) __attribute__((format(printf, 1, 2)));
extern int BSP_disconnect_clock_handler (void);
extern int BSP_connect_clock_handler (void);
#endif
#endif

View File

@@ -0,0 +1,170 @@
/*
* PreP compliant NVRAM access
*
* This file can be found in motorla or IBP PPC site.
*
* $Id$
*/
#ifndef _PPC_NVRAM_H
#define _PPC_NVRAM_H
#define NVRAM_AS0 0x74
#define NVRAM_AS1 0x75
#define NVRAM_DATA 0x77
/* RTC Offsets */
#define MOTO_RTC_SECONDS 0x1FF9
#define MOTO_RTC_MINUTES 0x1FFA
#define MOTO_RTC_HOURS 0x1FFB
#define MOTO_RTC_DAY_OF_WEEK 0x1FFC
#define MOTO_RTC_DAY_OF_MONTH 0x1FFD
#define MOTO_RTC_MONTH 0x1FFE
#define MOTO_RTC_YEAR 0x1FFF
#define MOTO_RTC_CONTROLA 0x1FF8
#define MOTO_RTC_CONTROLB 0x1FF9
#ifndef BCD_TO_BIN
#define BCD_TO_BIN(val) ((val)=((val)&15) + ((val)>>4)*10)
#endif
#ifndef BIN_TO_BCD
#define BIN_TO_BCD(val) ((val)=(((val)/10)<<4) + (val)%10)
#endif
/* Structure map for NVRAM on PowerPC Reference Platform */
/* All fields are either character/byte strings which are valid either
endian or they are big-endian numbers.
There are a number of Date and Time fields which are in RTC format,
big-endian. These are stored in UT (GMT).
For enum's: if given in hex then they are bit significant, i.e. only
one bit is on for each enum.
*/
#define NVSIZE 4096 /* size of NVRAM */
#define OSAREASIZE 512 /* size of OSArea space */
#define CONFSIZE 1024 /* guess at size of Configuration space */
#ifndef ASM
typedef struct _SECURITY {
unsigned long BootErrCnt; /* Count of boot password errors */
unsigned long ConfigErrCnt; /* Count of config password errors */
unsigned long BootErrorDT[2]; /* Date&Time from RTC of last error in pw */
unsigned long ConfigErrorDT[2]; /* Date&Time from RTC of last error in pw */
unsigned long BootCorrectDT[2]; /* Date&Time from RTC of last correct pw */
unsigned long ConfigCorrectDT[2]; /* Date&Time from RTC of last correct pw */
unsigned long BootSetDT[2]; /* Date&Time from RTC of last set of pw */
unsigned long ConfigSetDT[2]; /* Date&Time from RTC of last set of pw */
unsigned char Serial[16]; /* Box serial number */
} SECURITY;
typedef enum _OS_ID {
Unknown = 0,
Firmware = 1,
AIX = 2,
NT = 3,
MKOS2 = 4,
MKAIX = 5,
Taligent = 6,
Solaris = 7,
MK = 12
} OS_ID;
typedef struct _ERROR_LOG {
unsigned char ErrorLogEntry[40]; /* To be architected */
} ERROR_LOG;
typedef enum _BOOT_STATUS {
BootStarted = 0x01,
BootFinished = 0x02,
RestartStarted = 0x04,
RestartFinished = 0x08,
PowerFailStarted = 0x10,
PowerFailFinished = 0x20,
ProcessorReady = 0x40,
ProcessorRunning = 0x80,
ProcessorStart = 0x0100
} BOOT_STATUS;
typedef struct _RESTART_BLOCK {
unsigned short Version;
unsigned short Revision;
unsigned long ResumeReserve1[2];
volatile unsigned long BootStatus;
unsigned long CheckSum; /* Checksum of RESTART_BLOCK */
void* RestartAddress;
void* SaveAreaAddr;
unsigned long SaveAreaLength;
} RESTART_BLOCK;
typedef enum _OSAREA_USAGE {
Empty = 0,
Used = 1
} OSAREA_USAGE;
typedef enum _PM_MODE {
Suspend = 0x80, /* Part of state is in memory */
Normal = 0x00 /* No power management in effect */
} PMMode;
typedef struct _HEADER {
unsigned short Size; /* NVRAM size in K(1024) */
unsigned char Version; /* Structure map different */
unsigned char Revision; /* Structure map the same -may
be new values in old fields
in other words old code still works */
unsigned short Crc1; /* check sum from beginning of nvram to OSArea */
unsigned short Crc2; /* check sum of config */
unsigned char LastOS; /* OS_ID */
unsigned char Endian; /* B if big endian, L if little endian */
unsigned char OSAreaUsage;/* OSAREA_USAGE */
unsigned char PMMode; /* Shutdown mode */
RESTART_BLOCK RestartBlock;
SECURITY Security;
ERROR_LOG ErrorLog[2];
/* Global Environment information */
void* GEAddress;
unsigned long GELength;
/* Date&Time from RTC of last change to Global Environment */
unsigned long GELastWriteDT[2];
/* Configuration information */
void* ConfigAddress;
unsigned long ConfigLength;
/* Date&Time from RTC of last change to Configuration */
unsigned long ConfigLastWriteDT[2];
unsigned long ConfigCount; /* Count of entries in Configuration */
/* OS dependent temp area */
void* OSAreaAddress;
unsigned long OSAreaLength;
/* Date&Time from RTC of last change to OSAreaArea */
unsigned long OSAreaLastWriteDT[2];
} HEADER;
/* Here is the whole map of the NVRAM */
typedef struct _NVRAM_MAP {
HEADER Header;
unsigned char GEArea[NVSIZE-CONFSIZE-OSAREASIZE-sizeof(HEADER)];
unsigned char OSArea[OSAREASIZE];
unsigned char ConfigArea[CONFSIZE];
} NVRAM_MAP;
/* Routines to manipulate the NVRAM */
void init_prep_nvram(void);
char *prep_nvram_get_var(const char *name);
char *prep_nvram_first_var(void);
char *prep_nvram_next_var(char *name);
#endif /* ASM */
#endif /* _PPC_NVRAM_H */

View File

@@ -0,0 +1,41 @@
#
# $Id$
#
@SET_MAKE@
srcdir = @srcdir@
top_srcdir = @top_srcdir@
top_builddir = ../../..
subdir = powerpc/shared/irq
RTEMS_ROOT = @RTEMS_ROOT@
PROJECT_ROOT = @PROJECT_ROOT@
VPATH = @srcdir@
H_FILES = $(srcdir)/irq.h
SRCS = $(C_FILES) $(CC_FILES) $(H_FILES) $(S_FILES)
include $(RTEMS_ROOT)/make/custom/@RTEMS_BSP@.cfg
include $(RTEMS_ROOT)/make/leaf.cfg
INSTALL_CHANGE = @INSTALL_CHANGE@
mkinstalldirs = $(SHELL) $(top_srcdir)/@RTEMS_TOPdir@/mkinstalldirs
INSTALLDIRS = $(PROJECT_INCLUDE)/bsp
$(INSTALLDIRS):
@$(mkinstalldirs) $(INSTALLDIRS)
preinstall:
@$(mkinstalldirs) $(PROJECT_INCLUDE)/bsp
@$(INSTALL_CHANGE) -m 644 $(H_FILES) $(PROJECT_INCLUDE)/bsp
all: ${ARCH} $(SRCS) preinstall
install: all
Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
cd $(top_builddir) \
&& CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status

View File

@@ -0,0 +1,152 @@
/*
* This file contains the implementation of the function described in irq.h
* related to Intel 8259 Programmable Interrupt controller.
*
* Copyright (C) 1998, 1999 valette@crf.canon.fr
*
* The license and distribution terms for this file may be
* found in found in the file LICENSE in this distribution or at
* http://www.OARcorp.com/rtems/license.html.
*
* $Id$
*/
#include <bsp.h>
#include <bsp/irq.h>
/*-------------------------------------------------------------------------+
| Cache for 1st and 2nd PIC IRQ line's status (enabled or disabled) register.
+--------------------------------------------------------------------------*/
/*
* lower byte is interrupt mask on the master PIC.
* while upper bits are interrupt on the slave PIC.
*/
volatile rtems_i8259_masks i8259s_cache = 0xfffb;
/*-------------------------------------------------------------------------+
| Function: BSP_irq_disable_at_i8259s
| Description: Mask IRQ line in appropriate PIC chip.
| Global Variables: i8259s_cache
| Arguments: vector_offset - number of IRQ line to mask.
| Returns: Nothing.
+--------------------------------------------------------------------------*/
int BSP_irq_disable_at_i8259s (const rtems_irq_symbolic_name irqLine)
{
unsigned short mask;
unsigned int level;
if ( ((int)irqLine < BSP_ISA_IRQ_LOWEST_OFFSET) ||
((int)irqLine > BSP_ISA_IRQ_MAX_OFFSET)
)
return 1;
_CPU_ISR_Disable(level);
mask = 1 << irqLine;
i8259s_cache |= mask;
if (irqLine < 8)
{
outport_byte(PIC_MASTER_IMR_IO_PORT, i8259s_cache & 0xff);
}
else
{
outport_byte(PIC_SLAVE_IMR_IO_PORT, ((i8259s_cache & 0xff00) >> 8));
}
_CPU_ISR_Enable (level);
return 0;
}
/*-------------------------------------------------------------------------+
| Function: BSP_irq_enable_at_i8259s
| Description: Unmask IRQ line in appropriate PIC chip.
| Global Variables: i8259s_cache
| Arguments: irqLine - number of IRQ line to mask.
| Returns: Nothing.
+--------------------------------------------------------------------------*/
int BSP_irq_enable_at_i8259s (const rtems_irq_symbolic_name irqLine)
{
unsigned short mask;
unsigned int level;
if ( ((int)irqLine < BSP_ISA_IRQ_LOWEST_OFFSET) ||
((int)irqLine > BSP_ISA_IRQ_MAX_OFFSET )
)
return 1;
_CPU_ISR_Disable(level);
mask = ~(1 << irqLine);
i8259s_cache &= mask;
if (irqLine < 8)
{
outport_byte(PIC_MASTER_IMR_IO_PORT, i8259s_cache & 0xff);
}
else
{
outport_byte(PIC_SLAVE_IMR_IO_PORT, ((i8259s_cache & 0xff00) >> 8));
}
_CPU_ISR_Enable (level);
return 0;
} /* mask_irq */
int BSP_irq_enabled_at_i8259s (const rtems_irq_symbolic_name irqLine)
{
unsigned short mask;
if ( ((int)irqLine < BSP_ISA_IRQ_LOWEST_OFFSET) ||
((int)irqLine > BSP_ISA_IRQ_MAX_OFFSET)
)
return 1;
mask = (1 << irqLine);
return (~(i8259s_cache & mask));
}
/*-------------------------------------------------------------------------+
| Function: BSP_irq_ack_at_i8259s
| Description: Signal generic End Of Interrupt (EOI) to appropriate PIC.
| Global Variables: None.
| Arguments: irqLine - number of IRQ line to acknowledge.
| Returns: Nothing.
+--------------------------------------------------------------------------*/
int BSP_irq_ack_at_i8259s (const rtems_irq_symbolic_name irqLine)
{
if (irqLine >= 8) {
outport_byte(PIC_MASTER_COMMAND_IO_PORT, SLAVE_PIC_EOSI);
outport_byte(PIC_SLAVE_COMMAND_IO_PORT, (PIC_EOSI | (irqLine - 8)));
}
else {
outport_byte(PIC_MASTER_COMMAND_IO_PORT, (PIC_EOSI | irqLine));
}
return 0;
} /* ackIRQ */
void BSP_i8259s_init(void)
{
/*
* init master 8259 interrupt controller
*/
outport_byte(PIC_MASTER_COMMAND_IO_PORT, 0x11); /* Start init sequence */
outport_byte(PIC_MASTER_IMR_IO_PORT, 0x00);/* Vector base = 0 */
outport_byte(PIC_MASTER_IMR_IO_PORT, 0x04);/* edge tiggered, Cascade (slave) on IRQ2 */
outport_byte(PIC_MASTER_IMR_IO_PORT, 0x01);/* Select 8086 mode */
outport_byte(PIC_MASTER_IMR_IO_PORT, 0xFB); /* Mask all except cascade */
/*
* init slave interrupt controller
*/
outport_byte(PIC_SLAVE_COMMAND_IO_PORT, 0x11); /* Start init sequence */
outport_byte(PIC_SLAVE_IMR_IO_PORT, 0x08);/* Vector base = 8 */
outport_byte(PIC_SLAVE_IMR_IO_PORT, 0x02);/* edge triggered, Cascade (slave) on IRQ2 */
outport_byte(PIC_SLAVE_IMR_IO_PORT, 0x01); /* Select 8086 mode */
outport_byte(PIC_SLAVE_IMR_IO_PORT, 0xFF); /* Mask all */
}

View File

@@ -0,0 +1,398 @@
/*
*
* This file contains the implementation of the function described in irq.h
*
* Copyright (C) 1998, 1999 valette@crf.canon.fr
*
* The license and distribution terms for this file may be
* found in found in the file LICENSE in this distribution or at
* http://www.OARcorp.com/rtems/license.html.
*
* $Id$
*/
#include <bsp.h>
#include <bsp/irq.h>
#include <bsp/openpic.h>
#include <rtems/score/thread.h>
#include <rtems/score/apiext.h>
#include <libcpu/raw_exception.h>
#include <bsp/vectors.h>
#include <libcpu/cpu.h>
#define RAVEN_INTR_ACK_REG 0xfeff0030
/*
* pointer to the mask representing the additionnal irq vectors
* that must be disabled when a particular entry is activated.
* They will be dynamically computed from teh prioruty table given
* in BSP_rtems_irq_mngt_set();
* CAUTION : this table is accessed directly by interrupt routine
* prologue.
*/
rtems_i8259_masks irq_mask_or_tbl[BSP_IRQ_NUMBER];
/*
* default handler connected on each irq after bsp initialization
*/
static rtems_irq_connect_data default_rtems_entry;
/*
* location used to store initial tables used for interrupt
* management.
*/
static rtems_irq_global_settings* internal_config;
static rtems_irq_connect_data* rtems_hdl_tbl;
/*
* Check if IRQ is an ISA IRQ
*/
static inline int is_isa_irq(const rtems_irq_symbolic_name irqLine)
{
return (((int) irqLine <= BSP_ISA_IRQ_MAX_OFFSET) &
((int) irqLine >= BSP_ISA_IRQ_LOWEST_OFFSET)
);
}
/*
* Check if IRQ is an OPENPIC IRQ
*/
static inline int is_pci_irq(const rtems_irq_symbolic_name irqLine)
{
return (((int) irqLine <= BSP_PCI_IRQ_MAX_OFFSET) &
((int) irqLine >= BSP_PCI_IRQ_LOWEST_OFFSET)
);
}
/*
* Check if IRQ is a Porcessor IRQ
*/
static inline int is_processor_irq(const rtems_irq_symbolic_name irqLine)
{
return (((int) irqLine <= BSP_PROCESSOR_IRQ_MAX_OFFSET) &
((int) irqLine >= BSP_PROCESSOR_IRQ_LOWEST_OFFSET)
);
}
/*
* ------------------------ RTEMS Irq helper functions ----------------
*/
/*
* Caution : this function assumes the variable "internal_config"
* is already set and that the tables it contains are still valid
* and accessible.
*/
static void compute_i8259_masks_from_prio ()
{
unsigned int i;
unsigned int j;
/*
* Always mask at least current interrupt to prevent re-entrance
*/
for (i=BSP_ISA_IRQ_LOWEST_OFFSET; i < BSP_ISA_IRQ_NUMBER; i++) {
* ((unsigned short*) &irq_mask_or_tbl[i]) = (1 << i);
for (j = BSP_ISA_IRQ_LOWEST_OFFSET; j < BSP_ISA_IRQ_NUMBER; j++) {
/*
* Mask interrupts at i8259 level that have a lower priority
*/
if (internal_config->irqPrioTbl [i] > internal_config->irqPrioTbl [j]) {
* ((unsigned short*) &irq_mask_or_tbl[i]) |= (1 << j);
}
}
}
}
/*
* This function check that the value given for the irq line
* is valid.
*/
static int isValidInterrupt(int irq)
{
if ( (irq < BSP_LOWEST_OFFSET) || (irq > BSP_MAX_OFFSET))
return 0;
return 1;
}
/*
* ------------------------ RTEMS Single Irq Handler Mngt Routines ----------------
*/
int BSP_install_rtems_irq_handler (const rtems_irq_connect_data* irq)
{
unsigned int level;
if (!isValidInterrupt(irq->name)) {
return 0;
}
/*
* Check if default handler is actually connected. If not issue an error.
* You must first get the current handler via i386_get_current_idt_entry
* and then disconnect it using i386_delete_idt_entry.
* RATIONALE : to always have the same transition by forcing the user
* to get the previous handler before accepting to disconnect.
*/
if (rtems_hdl_tbl[irq->name].hdl != default_rtems_entry.hdl) {
return 0;
}
_CPU_ISR_Disable(level);
/*
* store the data provided by user
*/
rtems_hdl_tbl[irq->name] = *irq;
if (is_isa_irq(irq->name)) {
/*
* Enable interrupt at PIC level
*/
BSP_irq_enable_at_i8259s (irq->name);
}
if (is_pci_irq(irq->name)) {
/*
* Enable interrupt at OPENPIC level
*/
openpic_enable_irq ((int) irq->name - BSP_PCI_IRQ_LOWEST_OFFSET);
}
if (is_processor_irq(irq->name)) {
/*
* Enable exception at processor level
*/
}
/*
* Enable interrupt on device
*/
irq->on(irq);
_CPU_ISR_Enable(level);
return 1;
}
int BSP_get_current_rtems_irq_handler (rtems_irq_connect_data* irq)
{
if (!isValidInterrupt(irq->name)) {
return 0;
}
*irq = rtems_hdl_tbl[irq->name];
return 1;
}
int BSP_remove_rtems_irq_handler (const rtems_irq_connect_data* irq)
{
unsigned int level;
if (!isValidInterrupt(irq->name)) {
return 0;
}
/*
* Check if default handler is actually connected. If not issue an error.
* You must first get the current handler via i386_get_current_idt_entry
* and then disconnect it using i386_delete_idt_entry.
* RATIONALE : to always have the same transition by forcing the user
* to get the previous handler before accepting to disconnect.
*/
if (rtems_hdl_tbl[irq->name].hdl != irq->hdl) {
return 0;
}
_CPU_ISR_Disable(level);
if (is_isa_irq(irq->name)) {
/*
* disable interrupt at PIC level
*/
BSP_irq_disable_at_i8259s (irq->name);
}
if (is_pci_irq(irq->name)) {
/*
* disable interrupt at OPENPIC level
*/
openpic_disable_irq ((int) irq->name - BSP_PCI_IRQ_LOWEST_OFFSET);
}
if (is_processor_irq(irq->name)) {
/*
* disable exception at processor level
*/
}
/*
* Disable interrupt on device
*/
irq->off(irq);
/*
* restore the default irq value
*/
rtems_hdl_tbl[irq->name] = default_rtems_entry;
_CPU_ISR_Enable(level);
return 1;
}
/*
* ------------------------ RTEMS Global Irq Handler Mngt Routines ----------------
*/
int BSP_rtems_irq_mngt_set(rtems_irq_global_settings* config)
{
int i;
unsigned int level;
/*
* Store various code accelerators
*/
internal_config = config;
default_rtems_entry = config->defaultEntry;
rtems_hdl_tbl = config->irqHdlTbl;
_CPU_ISR_Disable(level);
/*
* set up internal tables used by rtems interrupt prologue
*/
/*
* start with ISA IRQ
*/
compute_i8259_masks_from_prio ();
for (i=BSP_ISA_IRQ_LOWEST_OFFSET; i < BSP_ISA_IRQ_NUMBER; i++) {
if (rtems_hdl_tbl[i].hdl != default_rtems_entry.hdl) {
BSP_irq_enable_at_i8259s (i);
rtems_hdl_tbl[i].on(&rtems_hdl_tbl[i]);
}
else {
rtems_hdl_tbl[i].off(&rtems_hdl_tbl[i]);
BSP_irq_disable_at_i8259s (i);
}
}
/*
* must enable slave pic anyway
*/
BSP_irq_enable_at_i8259s (2);
/*
* continue with PCI IRQ
*/
for (i=BSP_PCI_IRQ_LOWEST_OFFSET; i < BSP_PCI_IRQ_LOWEST_OFFSET + BSP_PCI_IRQ_NUMBER ; i++) {
openpic_set_priority(0, internal_config->irqPrioTbl [i]);
if (rtems_hdl_tbl[i].hdl != default_rtems_entry.hdl) {
openpic_enable_irq ((int) i - BSP_PCI_IRQ_LOWEST_OFFSET);
rtems_hdl_tbl[i].on(&rtems_hdl_tbl[i]);
}
else {
rtems_hdl_tbl[i].off(&rtems_hdl_tbl[i]);
openpic_disable_irq ((int) i - BSP_PCI_IRQ_LOWEST_OFFSET);
}
}
/*
* Must enable PCI/ISA bridge IRQ
*/
openpic_enable_irq (0);
/*
* finish with Processor exceptions handled like IRQ
*/
for (i=BSP_PROCESSOR_IRQ_LOWEST_OFFSET; i < BSP_PROCESSOR_IRQ_LOWEST_OFFSET + BSP_PROCESSOR_IRQ_NUMBER; i++) {
if (rtems_hdl_tbl[i].hdl != default_rtems_entry.hdl) {
rtems_hdl_tbl[i].on(&rtems_hdl_tbl[i]);
}
else {
rtems_hdl_tbl[i].off(&rtems_hdl_tbl[i]);
}
}
_CPU_ISR_Enable(level);
return 1;
}
int BSP_rtems_irq_mngt_get(rtems_irq_global_settings** config)
{
*config = internal_config;
return 0;
}
static unsigned spuriousIntr = 0;
/*
* High level IRQ handler called from shared_raw_irq_code_entry
*/
void C_dispatch_irq_handler (CPU_Interrupt_frame *frame, unsigned int excNum)
{
register unsigned int irq;
register unsigned isaIntr; /* boolean */
register unsigned oldMask; /* old isa pic masks */
register unsigned newMask; /* new isa pic masks */
register unsigned msr;
register unsigned new_msr;
if (excNum == ASM_DEC_VECTOR) {
_CPU_MSR_GET(msr);
new_msr = msr | MSR_EE;
_CPU_MSR_SET(new_msr);
rtems_hdl_tbl[BSP_DECREMENTER].hdl();
_CPU_MSR_SET(msr);
return;
}
irq = openpic_irq(0);
if (irq == OPENPIC_VEC_SPURIOUS) {
++spuriousIntr;
return;
}
isaIntr = (irq == BSP_PCI_ISA_BRIDGE_IRQ);
if (isaIntr) {
/*
* Acknowledge and read 8259 vector
*/
irq = (unsigned int) (*(unsigned char *) RAVEN_INTR_ACK_REG);
/*
* store current PIC mask
*/
oldMask = i8259s_cache;
newMask = oldMask | irq_mask_or_tbl [irq];
i8259s_cache = newMask;
outport_byte(PIC_MASTER_IMR_IO_PORT, i8259s_cache & 0xff);
outport_byte(PIC_SLAVE_IMR_IO_PORT, ((i8259s_cache & 0xff00) >> 8));
BSP_irq_ack_at_i8259s (irq);
openpic_eoi(0);
}
_CPU_MSR_GET(msr);
new_msr = msr | MSR_EE;
_CPU_MSR_SET(new_msr);
rtems_hdl_tbl[irq].hdl();
_CPU_MSR_SET(msr);
if (isaIntr) {
i8259s_cache = oldMask;
outport_byte(PIC_MASTER_IMR_IO_PORT, i8259s_cache & 0xff);
outport_byte(PIC_SLAVE_IMR_IO_PORT, ((i8259s_cache & 0xff00) >> 8));
}
else {
openpic_eoi(0);
}
}
void _ThreadProcessSignalsFromIrq (BSP_Exception_frame* ctx)
{
/*
* Process pending signals that have not already been
* processed by _Thread_Displatch. This happens quite
* unfrequently : the ISR must have posted an action
* to the current running thread.
*/
if ( _Thread_Do_post_task_switch_extension ||
_Thread_Executing->do_post_task_switch_extension ) {
_Thread_Executing->do_post_task_switch_extension = FALSE;
_API_extensions_Run_postswitch();
}
/*
* I plan to process other thread related events here.
* This will include DEBUG session requested from keyboard...
*/
}

View File

@@ -0,0 +1,319 @@
/* irq.h
*
* This include file describe the data structure and the functions implemented
* by rtems to write interrupt handlers.
*
* CopyRight (C) 1999 valette@crf.canon.fr
*
* This code is heavilly inspired by the public specification of STREAM V2
* that can be found at :
*
* <http://www.chorus.com/Documentation/index.html> by following
* the STREAM API Specification Document link.
*
* The license and distribution terms for this file may be
* found in found in the file LICENSE in this distribution or at
* http://www.OARcorp.com/rtems/license.html.
*
* $Id$
*/
#ifndef LIBBSP_POWERPC_MCP750_IRQ_IRQ_H
#define LIBBSP_POWERPC_MCP750_IRQ_IRQ_H
/*
* 8259 edge/level control definitions at VIA
*/
#define ISA8259_M_ELCR 0x4d0
#define ISA8259_S_ELCR 0x4d1
#define ELCRS_INT15_LVL 0x80
#define ELCRS_INT14_LVL 0x40
#define ELCRS_INT13_LVL 0x20
#define ELCRS_INT12_LVL 0x10
#define ELCRS_INT11_LVL 0x08
#define ELCRS_INT10_LVL 0x04
#define ELCRS_INT9_LVL 0x02
#define ELCRS_INT8_LVL 0x01
#define ELCRM_INT7_LVL 0x80
#define ELCRM_INT6_LVL 0x40
#define ELCRM_INT5_LVL 0x20
#define ELCRM_INT4_LVL 0x10
#define ELCRM_INT3_LVL 0x8
#define ELCRM_INT2_LVL 0x4
#define ELCRM_INT1_LVL 0x2
#define ELCRM_INT0_LVL 0x1
#define BSP_ASM_IRQ_VECTOR_BASE 0x0
/* PIC's command and mask registers */
#define PIC_MASTER_COMMAND_IO_PORT 0x20 /* Master PIC command register */
#define PIC_SLAVE_COMMAND_IO_PORT 0xa0 /* Slave PIC command register */
#define PIC_MASTER_IMR_IO_PORT 0x21 /* Master PIC Interrupt Mask Register */
#define PIC_SLAVE_IMR_IO_PORT 0xa1 /* Slave PIC Interrupt Mask Register */
/* Command for specific EOI (End Of Interrupt): Interrupt acknowledge */
#define PIC_EOSI 0x60 /* End of Specific Interrupt (EOSI) */
#define SLAVE_PIC_EOSI 0x62 /* End of Specific Interrupt (EOSI) for cascade */
#define PIC_EOI 0x20 /* Generic End of Interrupt (EOI) */
#ifndef ASM
/*
* Symblolic IRQ names and related definitions.
*/
typedef enum {
/* Base vector for our ISA IRQ handlers. */
BSP_ISA_IRQ_VECTOR_BASE = BSP_ASM_IRQ_VECTOR_BASE,
/*
* ISA IRQ handler related definitions
*/
BSP_ISA_IRQ_NUMBER = 16,
BSP_ISA_IRQ_LOWEST_OFFSET = 0,
BSP_ISA_IRQ_MAX_OFFSET = BSP_ISA_IRQ_LOWEST_OFFSET + BSP_ISA_IRQ_NUMBER - 1,
/*
* PCI IRQ handlers related definitions
* CAUTION : BSP_PCI_IRQ_LOWEST_OFFSET should be equal to OPENPIC_VEC_SOURCE
*/
BSP_PCI_IRQ_NUMBER = 16,
BSP_PCI_IRQ_LOWEST_OFFSET = BSP_ISA_IRQ_NUMBER,
BSP_PCI_IRQ_MAX_OFFSET = BSP_PCI_IRQ_LOWEST_OFFSET + BSP_PCI_IRQ_NUMBER - 1,
/*
* PowerPc exceptions handled as interrupt where a rtems managed interrupt
* handler might be connected
*/
BSP_PROCESSOR_IRQ_NUMBER = 1,
BSP_PROCESSOR_IRQ_LOWEST_OFFSET = BSP_PCI_IRQ_MAX_OFFSET + 1,
BSP_PROCESSOR_IRQ_MAX_OFFSET = BSP_PROCESSOR_IRQ_LOWEST_OFFSET + BSP_PROCESSOR_IRQ_NUMBER - 1,
/*
* Summary
*/
BSP_IRQ_NUMBER = BSP_PROCESSOR_IRQ_MAX_OFFSET + 1,
BSP_LOWEST_OFFSET = BSP_ISA_IRQ_LOWEST_OFFSET,
BSP_MAX_OFFSET = BSP_PROCESSOR_IRQ_MAX_OFFSET,
/*
* Some ISA IRQ symbolic name definition
*/
BSP_ISA_PERIODIC_TIMER = 0,
BSP_ISA_KEYBOARD = 1,
BSP_ISA_UART_COM2_IRQ = 3,
BSP_ISA_UART_COM1_IRQ = 4,
BSP_ISA_RT_TIMER1 = 8,
BSP_ISA_RT_TIMER3 = 10,
/*
* Some PCI IRQ symbolic name definition
*/
BSP_PCI_IRQ0 = BSP_PCI_IRQ_LOWEST_OFFSET,
BSP_PCI_ISA_BRIDGE_IRQ = BSP_PCI_IRQ0,
/*
* Some Processor execption handled as rtems IRQ symbolic name definition
*/
BSP_DECREMENTER = BSP_PROCESSOR_IRQ_LOWEST_OFFSET
}rtems_irq_symbolic_name;
/*
* Type definition for RTEMS managed interrupts
*/
typedef unsigned char rtems_irq_prio;
typedef unsigned short rtems_i8259_masks;
extern volatile rtems_i8259_masks i8259s_cache;
struct __rtems_irq_connect_data__; /* forward declaratiuon */
typedef void (*rtems_irq_hdl) (void);
typedef void (*rtems_irq_enable) (const struct __rtems_irq_connect_data__*);
typedef void (*rtems_irq_disable) (const struct __rtems_irq_connect_data__*);
typedef int (*rtems_irq_is_enabled) (const struct __rtems_irq_connect_data__*);
typedef struct __rtems_irq_connect_data__ {
/*
* IRQ line
*/
rtems_irq_symbolic_name name;
/*
* handler. See comment on handler properties below in function prototype.
*/
rtems_irq_hdl hdl;
/*
* function for enabling interrupts at device level (ONLY!).
* The BSP code will automatically enable it at i8259s level and openpic level.
* RATIONALE : anyway such code has to exist in current driver code.
* It is usually called immediately AFTER connecting the interrupt handler.
* RTEMS may well need such a function when restoring normal interrupt
* processing after a debug session.
*
*/
rtems_irq_enable on;
/*
* function for disabling interrupts at device level (ONLY!).
* The code will disable it at i8259s level. RATIONALE : anyway
* such code has to exist for clean shutdown. It is usually called
* BEFORE disconnecting the interrupt. RTEMS may well need such
* a function when disabling normal interrupt processing for
* a debug session. May well be a NOP function.
*/
rtems_irq_disable off;
/*
* function enabling to know what interrupt may currently occur
* if someone manipulates the i8259s interrupt mask without care...
*/
rtems_irq_is_enabled isOn;
}rtems_irq_connect_data;
typedef struct {
/*
* size of all the table fields (*Tbl) described below.
*/
unsigned int irqNb;
/*
* Default handler used when disconnecting interrupts.
*/
rtems_irq_connect_data defaultEntry;
/*
* Table containing initials/current value.
*/
rtems_irq_connect_data* irqHdlTbl;
/*
* actual value of BSP_ISA_IRQ_VECTOR_BASE...
*/
rtems_irq_symbolic_name irqBase;
/*
* software priorities associated with interrupts.
* if irqPrio [i] > intrPrio [j] it means that
* interrupt handler hdl connected for interrupt name i
* will not be interrupted by the handler connected for interrupt j
* The interrupt source will be physically masked at i8259 level.
*/
rtems_irq_prio* irqPrioTbl;
}rtems_irq_global_settings;
/*-------------------------------------------------------------------------+
| Function Prototypes.
+--------------------------------------------------------------------------*/
/*
* ------------------------ Intel 8259 (or emulation) Mngt Routines -------
*/
/*
* function to disable a particular irq at 8259 level. After calling
* this function, even if the device asserts the interrupt line it will
* not be propagated further to the processor
*/
int BSP_irq_disable_at_i8259s (const rtems_irq_symbolic_name irqLine);
/*
* function to enable a particular irq at 8259 level. After calling
* this function, if the device asserts the interrupt line it will
* be propagated further to the processor
*/
int BSP_irq_enable_at_i8259s (const rtems_irq_symbolic_name irqLine);
/*
* function to acknoledge a particular irq at 8259 level. After calling
* this function, if a device asserts an enabled interrupt line it will
* be propagated further to the processor. Mainly usefull for people
* writting raw handlers as this is automagically done for rtems managed
* handlers.
*/
int BSP_irq_ack_at_i8259s (const rtems_irq_symbolic_name irqLine);
/*
* function to check if a particular irq is enabled at 8259 level. After calling
*/
int BSP_irq_enabled_at_i8259s (const rtems_irq_symbolic_name irqLine);
/*
* ------------------------ RTEMS Single Irq Handler Mngt Routines ----------------
*/
/*
* function to connect a particular irq handler. This hanlder will NOT be called
* directly as the result of the corresponding interrupt. Instead, a RTEMS
* irq prologue will be called that will :
*
* 1) save the C scratch registers,
* 2) switch to a interrupt stack if the interrupt is not nested,
* 3) store the current i8259s' interrupt masks
* 4) modify them to disable the current interrupt at 8259 level (and may
* be others depending on software priorities)
* 5) aknowledge the i8259s',
* 6) demask the processor,
* 7) call the application handler
*
* As a result the hdl function provided
*
* a) can perfectly be written is C,
* b) may also well directly call the part of the RTEMS API that can be used
* from interrupt level,
* c) It only responsible for handling the jobs that need to be done at
* the device level including (aknowledging/re-enabling the interrupt at device,
* level, getting the data,...)
*
* When returning from the function, the following will be performed by
* the RTEMS irq epilogue :
*
* 1) masks the interrupts again,
* 2) restore the original i8259s' interrupt masks
* 3) switch back on the orinal stack if needed,
* 4) perform rescheduling when necessary,
* 5) restore the C scratch registers...
* 6) restore initial execution flow
*
*/
int BSP_install_rtems_irq_handler (const rtems_irq_connect_data*);
/*
* function to get the current RTEMS irq handler for ptr->name. It enables to
* define hanlder chain...
*/
int BSP_get_current_rtems_irq_handler (rtems_irq_connect_data* ptr);
/*
* function to get disconnect the RTEMS irq handler for ptr->name.
* This function checks that the value given is the current one for safety reason.
* The user can use the previous function to get it.
*/
int BSP_remove_rtems_irq_handler (const rtems_irq_connect_data*);
/*
* ------------------------ RTEMS Global Irq Handler Mngt Routines ----------------
*/
/*
* (Re) Initialize the RTEMS interrupt management.
*
* The result of calling this function will be the same as if each individual
* handler (config->irqHdlTbl[i].hdl) different from "config->defaultEntry.hdl"
* has been individualy connected via
* BSP_install_rtems_irq_handler(&config->irqHdlTbl[i])
* And each handler currently equal to config->defaultEntry.hdl
* has been previously disconnected via
* BSP_remove_rtems_irq_handler (&config->irqHdlTbl[i])
*
* This is to say that all information given will be used and not just
* only the space.
*
* CAUTION : the various table address contained in config will be used
* directly by the interrupt mangement code in order to save
* data size so they must stay valid after the call => they should
* not be modified or declared on a stack.
*/
int BSP_rtems_irq_mngt_set(rtems_irq_global_settings* config);
/*
* (Re) get info on current RTEMS interrupt management.
*/
int BSP_rtems_irq_mngt_get(rtems_irq_global_settings**);
extern void BSP_rtems_irq_mng_init(unsigned cpuId);
extern void BSP_i8259s_init(void);
#endif
#endif

View File

@@ -0,0 +1,322 @@
/*
* This file contains the assembly code for the PowerPC
* IRQ veneers for RTEMS.
*
* The license and distribution terms for this file may be
* found in found in the file LICENSE in this distribution or at
* http://www.OARcorp.com/rtems/license.html.
*
* Modified to support the MCP750.
* Modifications Copyright (C) 1999 Eric Valette. valette@crf.canon.fr
*
*
* $Id$
*/
#include <bsp/vectors.h>
#include <libcpu/cpu.h>
#include <libcpu/raw_exception.h>
#include <rtems/score/targopts.h>
#include "asm.h"
#define SYNC \
sync; \
isync
.text
.p2align 5
PUBLIC_VAR(decrementer_exception_vector_prolog_code)
SYM (decrementer_exception_vector_prolog_code):
/*
* let room for exception frame
*/
stwu r1, - (EXCEPTION_FRAME_END)(r1)
stw r4, GPR4_OFFSET(r1)
li r4, ASM_DEC_VECTOR
ba shared_raw_irq_code_entry
PUBLIC_VAR (decrementer_exception_vector_prolog_code_size)
decrementer_exception_vector_prolog_code_size = . - decrementer_exception_vector_prolog_code
PUBLIC_VAR(external_exception_vector_prolog_code)
SYM (external_exception_vector_prolog_code):
/*
* let room for exception frame
*/
stwu r1, - (EXCEPTION_FRAME_END)(r1)
stw r4, GPR4_OFFSET(r1)
li r4, ASM_EXT_VECTOR
ba shared_raw_irq_code_entry
PUBLIC_VAR (external_exception_vector_prolog_code_size)
external_exception_vector_prolog_code_size = . - external_exception_vector_prolog_code
PUBLIC_VAR(shared_raw_irq_code_entry)
PUBLIC_VAR(C_dispatch_irq_handler)
.p2align 5
SYM (shared_raw_irq_code_entry):
/*
* Entry conditions :
* Registers already saved : R1, R4
* R1 : points to a location with enough room for the
* interrupt frame
* R4 : vector number
*/
/*
* Save SRR0/SRR1 As soon As possible as it is the minimal needed
* to reenable exception processing
*/
stw r0, GPR0_OFFSET(r1)
stw r2, GPR2_OFFSET(r1)
stw r3, GPR3_OFFSET(r1)
mfsrr0 r0
mfsrr1 r2
mfmsr r3
stw r0, SRR0_FRAME_OFFSET(r1)
stw r2, SRR1_FRAME_OFFSET(r1)
/*
* Enable data and instruction address translation, exception recovery
*/
ori r3, r3, MSR_RI | MSR_IR | MSR_DR
mtmsr r3
SYNC
/*
* Push C scratch registers on the current stack. It may
* actually be the thread stack or the interrupt stack.
* Anyway we have to make it in order to be able to call C/C++
* functions. Depending on the nesting interrupt level, we will
* switch to the right stack later.
*/
stw r5, GPR5_OFFSET(r1)
stw r6, GPR6_OFFSET(r1)
stw r7, GPR7_OFFSET(r1)
stw r8, GPR8_OFFSET(r1)
stw r9, GPR9_OFFSET(r1)
stw r10, GPR10_OFFSET(r1)
stw r11, GPR11_OFFSET(r1)
stw r12, GPR12_OFFSET(r1)
stw r13, GPR13_OFFSET(r1)
mfcr r5
mfctr r6
mfxer r7
mflr r8
stw r5, EXC_CR_OFFSET(r1)
stw r6, EXC_CTR_OFFSET(r1)
stw r7, EXC_XER_OFFSET(r1)
stw r8, EXC_LR_OFFSET(r1)
/*
* Add some non volatile registers to store information
* that will be used when returning from C handler
*/
stw r14, GPR14_OFFSET(r1)
stw r15, GPR15_OFFSET(r1)
/*
* save current stack pointer location in R14
*/
addi r14, r1, 0
/*
* store part of _Thread_Dispatch_disable_level address in R15
*/
addis r15,0, _Thread_Dispatch_disable_level@ha
/*
* Get current nesting level in R2
*/
mfspr r2, SPRG0
/*
* Check if stack switch is necessary
*/
cmpwi r2,0
bne nested
mfspr r1, SPRG1
nested:
/*
* Start Incrementing nesting level in R2
*/
addi r2,r2,1
/*
* Start Incrementing _Thread_Dispatch_disable_level R4 = _Thread_Dispatch_disable_level
*/
lwz r6,_Thread_Dispatch_disable_level@l(r15)
/*
* store new nesting level in SPRG0
*/
mtspr SPRG0, r2
addi r6, r6, 1
mfmsr r5
/*
* store new _Thread_Dispatch_disable_level value
*/
stw r6, _Thread_Dispatch_disable_level@l(r15)
/*
* We are now running on the interrupt stack. External and decrementer
* exceptions are still disabled. I see no purpose trying to optimize
* further assembler code.
*/
/*
* Call C exception handler for decrementer Interrupt frame is passed just
* in case...
*/
addi r3, r14, 0x8
bl C_dispatch_irq_handler /* C_dispatch_irq_handler(cpu_interrupt_frame* r3, vector r4) */
/*
* start decrementing nesting level. Note : do not test result against 0
* value as an easy exit condition because if interrupt nesting level > 1
* then _Thread_Dispatch_disable_level > 1
*/
mfspr r2, SPRG0
/*
* start decrementing _Thread_Dispatch_disable_level
*/
lwz r3,_Thread_Dispatch_disable_level@l(r15)
addi r2, r2, -1 /* Continue decrementing nesting level */
addi r3, r3, -1 /* Continue decrementing _Thread_Dispatch_disable_level */
mtspr SPRG0, r2 /* End decrementing nesting level */
stw r3,_Thread_Dispatch_disable_level@l(r15) /* End decrementing _Thread_Dispatch_disable_level */
cmpwi r3, 0
/*
* switch back to original stack (done here just optimize registers
* contention. Could have been done before...)
*/
addi r1, r14, 0
bne easy_exit /* if (_Thread_Dispatch_disable_level != 0) goto easy_exit */
/*
* Here we are running again on the thread system stack.
* We have interrupt nesting level = _Thread_Dispatch_disable_level = 0.
* Interrupt are still disabled. Time to check if scheduler request to
* do something with the current thread...
*/
addis r4, 0, _Context_Switch_necessary@ha
lwz r5, _Context_Switch_necessary@l(r4)
cmpwi r5, 0
bne switch
addis r6, 0, _ISR_Signals_to_thread_executing@ha
lwz r7, _ISR_Signals_to_thread_executing@l(r6)
cmpwi r7, 0
li r8, 0
beq easy_exit
stw r8, _ISR_Signals_to_thread_executing@l(r6)
/*
* going to call _ThreadProcessSignalsFromIrq
* Push a complete exception like frame...
*/
stmw r16, GPR16_OFFSET(r1)
addi r3, r1, 0x8
/*
* compute SP at exception entry
*/
addi r2, r1, EXCEPTION_FRAME_END
/*
* store it at the right place
*/
stw r2, GPR1_OFFSET(r1)
/*
* Call High Level signal handling code
*/
bl _ISR_Signals_to_thread_executing
/*
* start restoring exception like frame
*/
lwz r31, EXC_CTR_OFFSET(r1)
lwz r30, EXC_XER_OFFSET(r1)
lwz r29, EXC_CR_OFFSET(r1)
lwz r28, EXC_LR_OFFSET(r1)
mtctr r31
mtxer r30
mtcr r29
mtlr r28
lmw r4, GPR4_OFFSET(r1)
lwz r2, GPR2_OFFSET(r1)
lwz r0, GPR0_OFFSET(r1)
/*
* Disable data and instruction translation. Make path non recoverable...
*/
mfmsr r3
xori r3, r3, MSR_RI | MSR_IR | MSR_DR
mtmsr r3
SYNC
/*
* Restore rfi related settings
*/
lwz r3, SRR1_FRAME_OFFSET(r1)
mtsrr1 r3
lwz r3, SRR0_FRAME_OFFSET(r1)
mtsrr0 r3
lwz r3, GPR3_OFFSET(r1)
addi r1,r1, EXCEPTION_FRAME_END
SYNC
rfi
switch:
bl SYM (_Thread_Dispatch)
easy_exit:
/*
* start restoring interrupt frame
*/
lwz r3, EXC_CTR_OFFSET(r1)
lwz r4, EXC_XER_OFFSET(r1)
lwz r5, EXC_CR_OFFSET(r1)
lwz r6, EXC_LR_OFFSET(r1)
mtctr r3
mtxer r4
mtcr r5
mtlr r6
lwz r15, GPR15_OFFSET(r1)
lwz r14, GPR14_OFFSET(r1)
lwz r13, GPR13_OFFSET(r1)
lwz r12, GPR12_OFFSET(r1)
lwz r11, GPR11_OFFSET(r1)
lwz r10, GPR10_OFFSET(r1)
lwz r9, GPR9_OFFSET(r1)
lwz r8, GPR8_OFFSET(r1)
lwz r7, GPR7_OFFSET(r1)
lwz r6, GPR6_OFFSET(r1)
lwz r5, GPR5_OFFSET(r1)
/*
* Disable nested exception processing, data and instruction
* translation.
*/
mfmsr r3
xori r3, r3, MSR_RI | MSR_IR | MSR_DR
mtmsr r3
SYNC
/*
* Restore rfi related settings
*/
lwz r4, SRR1_FRAME_OFFSET(r1)
lwz r2, SRR0_FRAME_OFFSET(r1)
lwz r3, GPR3_OFFSET(r1)
lwz r0, GPR0_OFFSET(r1)
mtsrr1 r4
mtsrr0 r2
lwz r4, GPR4_OFFSET(r1)
lwz r2, GPR2_OFFSET(r1)
addi r1,r1, EXCEPTION_FRAME_END
SYNC
rfi

View File

@@ -0,0 +1,315 @@
/* irq_init.c
*
* This file contains the implementation of rtems initialization
* related to interrupt handling.
*
* CopyRight (C) 1999 valette@crf.canon.fr
*
* The license and distribution terms for this file may be
* found in the file LICENSE in this distribution or at
* http://www.OARcorp.com/rtems/license.html.
*
* $Id$
*/
#include <bsp/consoleIo.h>
#include <libcpu/io.h>
#include <libcpu/spr.h>
#include <bsp/pci.h>
#include <bsp/residual.h>
#include <bsp/openpic.h>
#include <bsp/irq.h>
#include <bsp.h>
#include <libcpu/raw_exception.h>
#include <bsp/motorola.h>
typedef struct {
unsigned char bus; /* few chance the PCI/ISA bridge is not on first bus but ... */
unsigned char device;
unsigned char function;
} pci_isa_bridge_device;
pci_isa_bridge_device* via_82c586 = 0;
static pci_isa_bridge_device bridge;
extern unsigned int external_exception_vector_prolog_code_size;
extern void external_exception_vector_prolog_code();
extern unsigned int decrementer_exception_vector_prolog_code_size;
extern void decrementer_exception_vector_prolog_code();
/*
* default on/off function
*/
static void nop_func(){}
/*
* default isOn function
*/
static int not_connected() {return 0;}
/*
* default possible isOn function
*/
static int connected() {return 1;}
static rtems_irq_connect_data rtemsIrq[BSP_IRQ_NUMBER];
static rtems_irq_global_settings initial_config;
static rtems_irq_connect_data defaultIrq = {
/* vectorIdex, hdl , on , off , isOn */
0, nop_func , nop_func , nop_func , not_connected
};
static rtems_irq_prio irqPrioTable[BSP_IRQ_NUMBER]={
/*
* actual rpiorities for interrupt :
* 0 means that only current interrupt is masked
* 255 means all other interrupts are masked
*/
/*
* ISA interrupts.
* The second entry has a priority of 255 because
* it is the slave pic entry and is should always remain
* unmasked.
*/
0,0,
255,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
/*
* PCI Interrupts
*/
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* for raven prio 0 means unactive... */
/*
* Processor exceptions handled as interrupts
*/
0
};
static unsigned char mcp750_openpic_initsenses[] = {
1, /* MCP750_INT_PCB(8259) */
0, /* MCP750_INT_FALCON_ECC_ERR */
1, /* MCP750_INT_PCI_ETHERNET */
1, /* MCP750_INT_PCI_PMC */
1, /* MCP750_INT_PCI_WATCHDOG_TIMER1 */
1, /* MCP750_INT_PCI_PRST_SIGNAL */
1, /* MCP750_INT_PCI_FALL_SIGNAL */
1, /* MCP750_INT_PCI_DEG_SIGNAL */
1, /* MCP750_INT_PCI_BUS1_INTA */
1, /* MCP750_INT_PCI_BUS1_INTB */
1, /* MCP750_INT_PCI_BUS1_INTC */
1, /* MCP750_INT_PCI_BUS1_INTD */
1, /* MCP750_INT_PCI_BUS2_INTA */
1, /* MCP750_INT_PCI_BUS2_INTB */
1, /* MCP750_INT_PCI_BUS2_INTC */
1, /* MCP750_INT_PCI_BUS2_INTD */
};
void VIA_isa_bridge_interrupts_setup(void)
{
pci_isa_bridge_device pci_dev;
unsigned int temp;
unsigned char tmp;
unsigned char maxBus;
unsigned found = 0;
maxBus = BusCountPCI();
pci_dev.function = 0; /* Assumes the bidge is the first function */
for (pci_dev.bus = 0; pci_dev.bus < maxBus; pci_dev.bus++) {
#ifdef SCAN_PCI_PRINT
printk("isa_bridge_interrupts_setup: Scanning bus %d\n", pci_dev.bus);
#endif
for (pci_dev.device = 0; pci_dev.device < PCI_MAX_DEVICES; pci_dev.device++) {
#ifdef SCAN_PCI_PRINT
printk("isa_bridge_interrupts_setup: Scanning device %d\n", pci_dev.device);
#endif
pci_read_config_dword(pci_dev.bus, pci_dev.device, pci_dev.function,
PCI_VENDOR_ID, &temp);
#ifdef SCAN_PCI_PRINT
printk("Vendor/device = %x\n", temp);
#endif
if ( (temp == (((unsigned short) PCI_VENDOR_ID_VIA) | (PCI_DEVICE_ID_VIA_82C586_1 << 16)))
||
(temp == (((unsigned short) PCI_VENDOR_ID_VIA) | (PCI_DEVICE_ID_VIA_82C586_0 << 16)))
) {
bridge = pci_dev;
via_82c586 = &bridge;
#ifdef SHOW_ISA_PCI_BRIDGE_SETTINGS
/*
* Should print : bus = 0, device = 11, function = 0 on a MCP750.
*/
printk("Via PCI/ISA bridge found at bus = %d, device = %d, function = %d\n",
via_82c586->bus,
via_82c586->device,
via_82c586->function);
#endif
found = 1;
goto loop_exit;
}
}
}
loop_exit:
if (!found) BSP_panic("VIA_82C586 PCI/ISA bridge not found!n");
tmp = inb(0x810);
if ( !(tmp & 0x2)) {
#ifdef SHOW_ISA_PCI_BRIDGE_SETTINGS
printk("This is a second generation MCP750 board\n");
printk("We must reprogram the PCI/ISA bridge...\n");
#endif
pci_read_config_byte(via_82c586->bus, via_82c586->device, via_82c586->function,
0x47, &tmp);
#ifdef SHOW_ISA_PCI_BRIDGE_SETTINGS
printk(" PCI ISA bridge control2 = %x\n", (unsigned) tmp);
#endif
/*
* Enable 4D0/4D1 ISA interrupt level/edge config registers
*/
tmp |= 0x20;
pci_write_config_byte(via_82c586->bus, via_82c586->device, via_82c586->function,
0x47, tmp);
/*
* Now program the ISA interrupt edge/level
*/
tmp = ELCRS_INT9_LVL | ELCRS_INT10_LVL | ELCRS_INT11_LVL;
outb(tmp, ISA8259_S_ELCR);
tmp = ELCRM_INT5_LVL;
outb(tmp, ISA8259_M_ELCR);;
/*
* Set the Interrupt inputs to non-inverting level interrupt
*/
pci_read_config_byte(via_82c586->bus, via_82c586->device, via_82c586->function,
0x54, &tmp);
#ifdef SHOW_ISA_PCI_BRIDGE_SETTINGS
printk(" PCI ISA bridge PCI/IRQ Edge/Level Select = %x\n", (unsigned) tmp);
#endif
tmp = 0;
pci_write_config_byte(via_82c586->bus, via_82c586->device, via_82c586->function,
0x54, tmp);
}
else {
#ifdef SHOW_ISA_PCI_BRIDGE_SETTINGS
printk("This is a first generation MCP750 board\n");
printk("We just show the actual value used by PCI/ISA bridge\n");
#endif
pci_read_config_byte(via_82c586->bus, via_82c586->device, via_82c586->function,
0x47, &tmp);
#ifdef SHOW_ISA_PCI_BRIDGE_SETTINGS
printk(" PCI ISA bridge control2 = %x\n", (unsigned) tmp);
#endif
/*
* Enable 4D0/4D1 ISA interrupt level/edge config registers
*/
tmp |= 0x20;
pci_write_config_byte(via_82c586->bus, via_82c586->device, via_82c586->function,
0x47, tmp);
#ifdef SHOW_ISA_PCI_BRIDGE_SETTINGS
tmp = inb(ISA8259_S_ELCR);
printk(" PCI ISA bridge slave edge/level control bit = %x\n", (unsigned) tmp);
tmp = inb(ISA8259_M_ELCR);;
printk(" PCI ISA bridge master edge/level control bit = %x\n", (unsigned) tmp);
#endif
/*
* Must disable the 4D0/4D1 ISA interrupt level/edge config registers
* or the card will die a soon as we we will enable external interrupts
*/
pci_read_config_byte(via_82c586->bus, via_82c586->device, via_82c586->function,
0x47, &tmp);
tmp &= ~(0x20);
pci_write_config_byte(via_82c586->bus, via_82c586->device, via_82c586->function,
0x47, tmp);
/*
* Show the Interrupt inputs inverting/non-inverting level status
*/
pci_read_config_byte(via_82c586->bus, via_82c586->device, via_82c586->function,
0x54, &tmp);
#ifdef SHOW_ISA_PCI_BRIDGE_SETTINGS
printk(" PCI ISA bridge PCI/IRQ Edge/Level Select = %x\n", (unsigned) tmp);
#endif
}
}
/*
* This code assumes the exceptions management setup has already
* been done. We just need to replace the exceptions that will
* be handled like interrupt. On mcp750/mpc750 and many PPC processors
* this means the decrementer exception and the external exception.
*/
void BSP_rtems_irq_mng_init(unsigned cpuId)
{
rtems_raw_except_connect_data vectorDesc;
int known_cpi_isa_bridge = 0;
int i;
/*
* First initialize the Interrupt management hardware
*/
OpenPIC_InitSenses = mcp750_openpic_initsenses;
OpenPIC_NumInitSenses = sizeof(mcp750_openpic_initsenses) / sizeof(char);
#ifdef TRACE_IRQ_INIT
printk("Going to initialize raven interrupt controller (openpic compliant)\n");
#endif
openpic_init(1);
#ifdef TRACE_IRQ_INIT
printk("Going to initialize the PCI/ISA bridge IRQ related setting (VIA 82C586)\n");
#endif
if ( (currentBoard == MESQUITE) ) {
VIA_isa_bridge_interrupts_setup();
known_cpi_isa_bridge = 1;
}
if (!known_cpi_isa_bridge) {
printk("Please add code for PCI/ISA bridge init to libbsp/shared/irq/irq_init.c\n");
printk("If your card works correctly please add a test and set known_cpi_isa_bridge to true\n");
}
#ifdef TRACE_IRQ_INIT
printk("Going to initialize the ISA PC legacy IRQ management hardware\n");
#endif
BSP_i8259s_init();
/*
* Initialize Rtems management interrupt table
*/
/*
* re-init the rtemsIrq table
*/
for (i = 0; i < BSP_IRQ_NUMBER; i++) {
rtemsIrq[i] = defaultIrq;
rtemsIrq[i].name = i;
}
/*
* Init initial Interrupt management config
*/
initial_config.irqNb = BSP_IRQ_NUMBER;
initial_config.defaultEntry = defaultIrq;
initial_config.irqHdlTbl = rtemsIrq;
initial_config.irqBase = BSP_ASM_IRQ_VECTOR_BASE;
initial_config.irqPrioTbl = irqPrioTable;
if (!BSP_rtems_irq_mngt_set(&initial_config)) {
/*
* put something here that will show the failure...
*/
BSP_panic("Unable to initialize RTEMS interrupt Management!!! System locked\n");
}
/*
* We must connect the raw irq handler for the two
* expected interrupt sources : decrementer and external interrupts.
*/
vectorDesc.exceptIndex = ASM_DEC_VECTOR;
vectorDesc.hdl.vector = ASM_DEC_VECTOR;
vectorDesc.hdl.raw_hdl = decrementer_exception_vector_prolog_code;
vectorDesc.hdl.raw_hdl_size = (unsigned) &decrementer_exception_vector_prolog_code_size;
vectorDesc.on = nop_func;
vectorDesc.off = nop_func;
vectorDesc.isOn = connected;
if (!mpc60x_set_exception (&vectorDesc)) {
BSP_panic("Unable to initialize RTEMS decrementer raw exception\n");
}
vectorDesc.exceptIndex = ASM_EXT_VECTOR;
vectorDesc.hdl.vector = ASM_EXT_VECTOR;
vectorDesc.hdl.raw_hdl = external_exception_vector_prolog_code;
vectorDesc.hdl.raw_hdl_size = (unsigned) &external_exception_vector_prolog_code_size;
if (!mpc60x_set_exception (&vectorDesc)) {
BSP_panic("Unable to initialize RTEMS external raw exception\n");
}
#ifdef TRACE_IRQ_INIT
printk("RTEMS IRQ management is now operationnal\n");
#endif
}

View File

@@ -0,0 +1,41 @@
#
# $Id$
#
@SET_MAKE@
srcdir = @srcdir@
top_srcdir = @top_srcdir@
top_builddir = ../../..
subdir = powerpc/shared/motorola
RTEMS_ROOT = @RTEMS_ROOT@
PROJECT_ROOT = @PROJECT_ROOT@
VPATH = @srcdir@
H_FILES = $(srcdir)/motorola.h
SRCS = $(C_FILES) $(H_FILES)
include $(RTEMS_ROOT)/make/custom/@RTEMS_BSP@.cfg
include $(RTEMS_ROOT)/make/leaf.cfg
INSTALL_CHANGE = @INSTALL_CHANGE@
mkinstalldirs = $(SHELL) $(top_srcdir)/@RTEMS_TOPdir@/mkinstalldirs
INSTALLDIRS = $(PROJECT_INCLUDE)/bsp
$(INSTALLDIRS):
@$(mkinstalldirs) $(INSTALLDIRS)
preinstall:
@$(mkinstalldirs) $(PROJECT_INCLUDE)/bsp
@$(INSTALL_CHANGE) -m 644 $(H_FILES) $(PROJECT_INCLUDE)/bsp
all: ${ARCH} $(SRCS) preinstall
install: all
Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
cd $(top_builddir) \
&& CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status

View File

@@ -0,0 +1,120 @@
/* motorola.h
*
* This include file describe the data structure and the functions implemented
* by rtems to identify motorola boards.
*
* CopyRight (C) 1999 valette@crf.canon.fr
*
* The license and distribution terms for this file may be
* found in found in the file LICENSE in this distribution or at
* http://www.OARcorp.com/rtems/license.html.
*
* $Id$
*/
#include <bsp/motorola.h>
#include <libcpu/io.h>
typedef struct {
/*
* 0x100 mask assumes for Raven and Hawk boards
* that the level/edge are set.
* 0x200 if this board has a Hawk chip.
*/
int cpu_type;
int base_type;
const char *name;
} mot_info_t;
static const mot_info_t mot_boards[] = {
{0x300, 0x00, "MVME 2400"},
{0x010, 0x00, "Genesis"},
{0x020, 0x00, "Powerstack (Series E)"},
{0x040, 0x00, "Blackhawk (Powerstack)"},
{0x050, 0x00, "Omaha (PowerStack II Pro3000)"},
{0x060, 0x00, "Utah (Powerstack II Pro4000)"},
{0x0A0, 0x00, "Powerstack (Series EX)"},
{0x1E0, 0xE0, "Mesquite cPCI (MCP750)"},
{0x1E0, 0xE1, "Sitka cPCI (MCPN750)"},
{0x1E0, 0xE2, "Mesquite cPCI (MCP750) w/ HAC"},
{0x1E0, 0xF6, "MTX Plus"},
{0x1E0, 0xF7, "MTX wo/ Parallel Port"},
{0x1E0, 0xF8, "MTX w/ Parallel Port"},
{0x1E0, 0xF9, "MVME 2300"},
{0x1E0, 0xFA, "MVME 2300SC/2600"},
{0x1E0, 0xFB, "MVME 2600 with MVME712M"},
{0x1E0, 0xFC, "MVME 2600/2700 with MVME761"},
{0x1E0, 0xFD, "MVME 3600 with MVME712M"},
{0x1E0, 0xFE, "MVME 3600 with MVME761"},
{0x1E0, 0xFF, "MVME 1600-001 or 1600-011"},
{0x000, 0x00, ""}
};
prep_t currentPrepType;
motorolaBoard currentBoard;
prep_t checkPrepBoardType(RESIDUAL *res)
{
prep_t PREP_type;
/* figure out what kind of prep workstation we are */
if ( res->ResidualLength != 0 ) {
if ( !strncmp(res->VitalProductData.PrintableModel,"IBM",3) )
PREP_type = PREP_IBM;
else if (!strncmp(res->VitalProductData.PrintableModel,
"Radstone",8)){
PREP_type = PREP_Radstone;
}
else
PREP_type = PREP_Motorola;
}
else /* assume motorola if no residual (netboot?) */ {
PREP_type = PREP_Motorola;
}
currentPrepType = PREP_type;
return PREP_type;
}
motorolaBoard getMotorolaBoard()
{
unsigned char cpu_type;
unsigned char base_mod;
int entry;
int mot_entry = -1;
cpu_type = inb(MOTOROLA_CPUTYPE_REG) & 0xF0;
base_mod = inb(MOTOROLA_BASETYPE_REG);
for (entry = 0; mot_boards[entry].cpu_type != 0; entry++) {
if ((mot_boards[entry].cpu_type & 0xff) != cpu_type)
continue;
if (mot_boards[entry].base_type == 0) {
mot_entry = entry;
break;
}
if (mot_boards[entry].base_type != base_mod)
continue;
else{
mot_entry = entry;
break;
}
}
if (mot_entry == -1) {
printk("Unkwon motorola board Please update libbsp/powerpc/shared/motorola/motorola.c\n");
printk("cpu_type = %x\n", (unsigned) cpu_type);
printk("base_mod = %x\n", (unsigned) base_mod);
currentBoard = MOTOROLA_UNKNOWN;
return currentBoard;
}
currentBoard = (motorolaBoard) mot_entry;
return currentBoard;
}
const char* motorolaBoardToString(motorolaBoard board)
{
if (board == MOTOROLA_UNKNOWN) return "Unknown motorola board";
return (mot_boards[board].name);
}

View File

@@ -0,0 +1,67 @@
/* motorola.h
*
* This include file describe the data structure and the functions implemented
* by rtems to identify motorola boards.
*
* CopyRight (C) 1999 valette@crf.canon.fr
*
* The license and distribution terms for this file may be
* found in found in the file LICENSE in this distribution or at
* http://www.OARcorp.com/rtems/license.html.
*
* $Id$
*/
#ifndef LIBBSP_POWERPC_SHARED_MOTOROLA_MOTOROLA_H
#define LIBBSP_POWERPC_SHARED_MOTOROLA_MOTOROLA_H
#include <bsp/residual.h>
typedef enum {
PREP_IBM = 0,
PREP_Radstone = 1,
PREP_Motorola = 2
}prep_t;
typedef enum {
MVME_2400 = 0,
GENESIS = 1,
POWERSTACK_E = 2,
BLACKAWK = 3,
OMAHA = 4,
UTAH = 5,
POWERSTACK_EX = 6,
MESQUITE = 7,
SITKA = 8,
MESQUITE_W_HAC = 9,
MTX_PLUS = 10,
MTX_WO_PP = 11,
MTX_W_PP = 12,
MVME_2300 = 13,
MVME_2300SC_2600 = 14,
MVME_2600_W_MVME712M = 15,
MVME_2600_2700_W_MVME761 = 16,
MVME_3600_W_MVME712M = 17,
MVME_3600_W_MVME761 = 18,
MVME_1600 = 19,
MOTOROLA_UNKNOWN = 255
} motorolaBoard;
typedef enum {
HOST_BRIDGE_RAVEN = 0,
HOST_BRIDGE_HAWK = 1,
HOST_BRIDGE_UNKNOWN = 255
}motorolaHostBridge;
#define MOTOROLA_CPUTYPE_REG 0x800
#define MOTOROLA_BASETYPE_REG 0x803
extern prep_t checkPrepBoardType(RESIDUAL *res);
extern prep_t currentPrepType;
extern motorolaBoard getMotorolaBoard();
extern motorolaBoard currentBoard;
extern const char* motorolaBoardToString(motorolaBoard);
#endif /* LIBBSP_POWERPC_SHARED_MOTOROLA_MOTOROLA_H */

View File

@@ -0,0 +1,42 @@
#
# $Id$
#
@SET_MAKE@
srcdir = @srcdir@
top_srcdir = @top_srcdir@
top_builddir = ../../..
subdir = powerpc/shared/openpic
RTEMS_ROOT = @RTEMS_ROOT@
PROJECT_ROOT = @PROJECT_ROOT@
VPATH = @srcdir@
H_FILES = $(srcdir)/openpic.h
SRCS = $(C_FILES) $(H_FILES)
include $(RTEMS_ROOT)/make/custom/@RTEMS_BSP@.cfg
include $(RTEMS_ROOT)/make/leaf.cfg
INSTALL_CHANGE = @INSTALL_CHANGE@
mkinstalldirs = $(SHELL) $(top_srcdir)/@RTEMS_TOPdir@/mkinstalldirs
INSTALLDIRS = $(PROJECT_INCLUDE)/bsp
$(INSTALLDIRS):
@$(mkinstalldirs) $(INSTALLDIRS)
preinstall:
@$(mkinstalldirs) $(PROJECT_INCLUDE)/bsp
@$(INSTALL_CHANGE) -m 644 $(H_FILES) $(PROJECT_INCLUDE)/bsp
all: ${ARCH} $(SRCS) preinstall
# the .rel file built here will be put into libbsp.a by ../wrapup/Makefile
install: all
Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
cd $(top_builddir) \
&& CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status

View File

@@ -0,0 +1,509 @@
/*
* openpic.c -- OpenPIC Interrupt Handling
*
* Copyright (C) 1997 Geert Uytterhoeven
*
* Modified to compile in RTEMS development environment
* by Eric Valette
*
* Copyright (C) 1999 Eric Valette. valette@crf.canon.fr
*
* The license and distribution terms for this file may be
* found in found in the file LICENSE in this distribution or at
* http://www.OARcorp.com/rtems/license.html.
*
* $Id$
*/
/*
* Note: Interprocessor Interrupt (IPI) and Timer support is incomplete
*/
#include <bsp/openpic.h>
#include <bsp/pci.h>
#include <bsp/consoleIo.h>
#include <libcpu/io.h>
#include <libcpu/byteorder.h>
#include <bsp.h>
#define NULL 0
#define REGISTER_DEBUG
#undef REGISTER_DEBUG
volatile struct OpenPIC *OpenPIC = NULL;
unsigned int OpenPIC_NumInitSenses = 0;
unsigned char *OpenPIC_InitSenses = NULL;
static unsigned int NumProcessors;
static unsigned int NumSources;
/*
* Accesses to the current processor's registers
*/
#define THIS_CPU Processor[cpu]
#define CHECK_THIS_CPU check_arg_cpu(cpu)
/*
* Sanity checks
*/
#if 1
#define check_arg_ipi(ipi) \
if (ipi < 0 || ipi >= OPENPIC_NUM_IPI) \
printk("openpic.c:%d: illegal ipi %d\n", __LINE__, ipi);
#define check_arg_timer(timer) \
if (timer < 0 || timer >= OPENPIC_NUM_TIMERS) \
printk("openpic.c:%d: illegal timer %d\n", __LINE__, timer);
#define check_arg_vec(vec) \
if (vec < 0 || vec >= OPENPIC_NUM_VECTORS) \
printk("openpic.c:%d: illegal vector %d\n", __LINE__, vec);
#define check_arg_pri(pri) \
if (pri < 0 || pri >= OPENPIC_NUM_PRI) \
printk("openpic.c:%d: illegal priority %d\n", __LINE__, pri);
#define check_arg_irq(irq) \
if (irq < 0 || irq >= NumSources) \
printk("openpic.c:%d: illegal irq %d from %p,[%p],[[%p]]\n", \
__LINE__, irq, __builtin_return_address(0), \
__builtin_return_address(1), __builtin_return_address(2) \
);
#define check_arg_cpu(cpu) \
if (cpu < 0 || cpu >= NumProcessors) \
printk("openpic.c:%d: illegal cpu %d\n", __LINE__, cpu);
#else
#define check_arg_ipi(ipi) do {} while (0)
#define check_arg_timer(timer) do {} while (0)
#define check_arg_vec(vec) do {} while (0)
#define check_arg_pri(pri) do {} while (0)
#define check_arg_irq(irq) do {} while (0)
#define check_arg_cpu(cpu) do {} while (0)
#endif
/*
* I/O functions
*/
static inline unsigned int openpic_read(volatile unsigned int *addr)
{
unsigned int val;
val = ld_le32(addr);
#ifdef REGISTER_DEBUG
printk("openpic_read(0x%08x) = 0x%08x\n", (unsigned int)addr, val);
#endif
return val;
}
static inline void openpic_write(volatile unsigned int *addr, unsigned int val)
{
#ifdef REGISTER_DEBUG
printk("openpic_write(0x%08x, 0x%08x)\n", (unsigned int)addr, val);
#endif
out_le32(addr, val);
}
static inline unsigned int openpic_readfield(volatile unsigned int *addr, unsigned int mask)
{
unsigned int val = openpic_read(addr);
return val & mask;
}
inline void openpic_writefield(volatile unsigned int *addr, unsigned int mask,
unsigned int field)
{
unsigned int val = openpic_read(addr);
openpic_write(addr, (val & ~mask) | (field & mask));
}
static inline void openpic_clearfield(volatile unsigned int *addr, unsigned int mask)
{
openpic_writefield(addr, mask, 0);
}
static inline void openpic_setfield(volatile unsigned int *addr, unsigned int mask)
{
openpic_writefield(addr, mask, mask);
}
/*
* Update a Vector/Priority register in a safe manner. The interrupt will
* be disabled.
*/
static void openpic_safe_writefield(volatile unsigned int *addr, unsigned int mask,
unsigned int field)
{
openpic_setfield(addr, OPENPIC_MASK);
/* wait until it's not in use */
while (openpic_read(addr) & OPENPIC_ACTIVITY);
openpic_writefield(addr, mask | OPENPIC_MASK, field | OPENPIC_MASK);
}
/* -------- Global Operations ---------------------------------------------- */
/*
* Initialize the OpenPIC
*
* Add some kludge to use the Motorola Raven OpenPIC which does not
* report vendor and device id, and gets the wrong number of interrupts.
* (Motorola did a great job on that one!)
*/
void openpic_init(int main_pic)
{
unsigned int t, i;
unsigned int vendorid, devid, stepping, timerfreq;
const char *version, *vendor, *device;
if (!OpenPIC)
BSP_panic("No OpenPIC found");
t = openpic_read(&OpenPIC->Global.Feature_Reporting0);
switch (t & OPENPIC_FEATURE_VERSION_MASK) {
case 1:
version = "1.0";
break;
case 2:
version = "1.2";
break;
default:
version = "?";
break;
}
NumProcessors = ((t & OPENPIC_FEATURE_LAST_PROCESSOR_MASK) >>
OPENPIC_FEATURE_LAST_PROCESSOR_SHIFT) + 1;
NumSources = ((t & OPENPIC_FEATURE_LAST_SOURCE_MASK) >>
OPENPIC_FEATURE_LAST_SOURCE_SHIFT) + 1;
t = openpic_read(&OpenPIC->Global.Vendor_Identification);
vendorid = t & OPENPIC_VENDOR_ID_VENDOR_ID_MASK;
devid = (t & OPENPIC_VENDOR_ID_DEVICE_ID_MASK) >>
OPENPIC_VENDOR_ID_DEVICE_ID_SHIFT;
stepping = (t & OPENPIC_VENDOR_ID_STEPPING_MASK) >>
OPENPIC_VENDOR_ID_STEPPING_SHIFT;
/* Kludge for the Raven */
pci_read_config_dword(0, 0, 0, 0, &t);
if (t == PCI_VENDOR_ID_MOTOROLA + (PCI_DEVICE_ID_MOTOROLA_RAVEN<<16)) {
vendor = "Motorola";
device = "Raven";
NumSources += 1;
} else {
switch (vendorid) {
case OPENPIC_VENDOR_ID_APPLE:
vendor = "Apple";
break;
default:
vendor = "Unknown";
break;
}
switch (devid) {
case OPENPIC_DEVICE_ID_APPLE_HYDRA:
device = "Hydra";
break;
default:
device = "Unknown";
break;
}
}
printk("OpenPIC Version %s (%d CPUs and %d IRQ sources) at %p\n", version,
NumProcessors, NumSources, OpenPIC);
printk("OpenPIC Vendor %d (%s), Device %d (%s), Stepping %d\n", vendorid,
vendor, devid, device, stepping);
timerfreq = openpic_read(&OpenPIC->Global.Timer_Frequency);
printk("OpenPIC timer frequency is ");
if (timerfreq)
printk("%d Hz\n", timerfreq);
else
printk("not set\n");
if ( main_pic )
{
/* Initialize timer interrupts */
for (i = 0; i < OPENPIC_NUM_TIMERS; i++) {
/* Disabled, Priority 0 */
openpic_inittimer(i, 0, OPENPIC_VEC_TIMER+i);
/* No processor */
openpic_maptimer(i, 0);
}
/* Initialize IPI interrupts */
for (i = 0; i < OPENPIC_NUM_IPI; i++) {
/* Disabled, Priority 0 */
openpic_initipi(i, 0, OPENPIC_VEC_IPI+i);
}
/* Initialize external interrupts */
/* SIOint (8259 cascade) is special */
openpic_initirq(0, 8, OPENPIC_VEC_SOURCE, 1, 1);
/* Processor 0 */
openpic_mapirq(0, 1<<0);
for (i = 1; i < NumSources; i++) {
/* Enabled, Priority 8 */
openpic_initirq(i, 8, OPENPIC_VEC_SOURCE+i, 0,
i < OpenPIC_NumInitSenses ? OpenPIC_InitSenses[i] : 1);
/* Processor 0 */
openpic_mapirq(i, 1<<0);
}
/* Initialize the spurious interrupt */
openpic_set_spurious(OPENPIC_VEC_SPURIOUS);
#if 0
if (request_irq(IRQ_8259_CASCADE, no_action, SA_INTERRUPT,
"82c59 cascade", NULL))
printk("Unable to get OpenPIC IRQ 0 for cascade\n");
#endif
openpic_set_priority(0, 0);
openpic_disable_8259_pass_through();
}
}
/*
* Reset the OpenPIC
*/
void openpic_reset(void)
{
openpic_setfield(&OpenPIC->Global.Global_Configuration0,
OPENPIC_CONFIG_RESET);
}
/*
* Enable/disable 8259 Pass Through Mode
*/
void openpic_enable_8259_pass_through(void)
{
openpic_clearfield(&OpenPIC->Global.Global_Configuration0,
OPENPIC_CONFIG_8259_PASSTHROUGH_DISABLE);
}
void openpic_disable_8259_pass_through(void)
{
openpic_setfield(&OpenPIC->Global.Global_Configuration0,
OPENPIC_CONFIG_8259_PASSTHROUGH_DISABLE);
}
/*
* Find out the current interrupt
*/
unsigned int openpic_irq(unsigned int cpu)
{
unsigned int vec;
check_arg_cpu(cpu);
vec = openpic_readfield(&OpenPIC->THIS_CPU.Interrupt_Acknowledge,
OPENPIC_VECTOR_MASK);
return vec;
}
/*
* Signal end of interrupt (EOI) processing
*/
void openpic_eoi(unsigned int cpu)
{
check_arg_cpu(cpu);
openpic_write(&OpenPIC->THIS_CPU.EOI, 0);
}
/*
* Get/set the current task priority
*/
unsigned int openpic_get_priority(unsigned int cpu)
{
CHECK_THIS_CPU;
return openpic_readfield(&OpenPIC->THIS_CPU.Current_Task_Priority,
OPENPIC_CURRENT_TASK_PRIORITY_MASK);
}
void openpic_set_priority(unsigned int cpu, unsigned int pri)
{
CHECK_THIS_CPU;
check_arg_pri(pri);
openpic_writefield(&OpenPIC->THIS_CPU.Current_Task_Priority,
OPENPIC_CURRENT_TASK_PRIORITY_MASK, pri);
}
/*
* Get/set the spurious vector
*/
unsigned int openpic_get_spurious(void)
{
return openpic_readfield(&OpenPIC->Global.Spurious_Vector,
OPENPIC_VECTOR_MASK);
}
void openpic_set_spurious(unsigned int vec)
{
check_arg_vec(vec);
openpic_writefield(&OpenPIC->Global.Spurious_Vector, OPENPIC_VECTOR_MASK,
vec);
}
/*
* Initialize one or more CPUs
*/
void openpic_init_processor(unsigned int cpumask)
{
openpic_write(&OpenPIC->Global.Processor_Initialization, cpumask);
}
/* -------- Interprocessor Interrupts -------------------------------------- */
/*
* Initialize an interprocessor interrupt (and disable it)
*
* ipi: OpenPIC interprocessor interrupt number
* pri: interrupt source priority
* vec: the vector it will produce
*/
void openpic_initipi(unsigned int ipi, unsigned int pri, unsigned int vec)
{
check_arg_timer(ipi);
check_arg_pri(pri);
check_arg_vec(vec);
openpic_safe_writefield(&OpenPIC->Global.IPI_Vector_Priority(ipi),
OPENPIC_PRIORITY_MASK | OPENPIC_VECTOR_MASK,
(pri << OPENPIC_PRIORITY_SHIFT) | vec);
}
/*
* Send an IPI to one or more CPUs
*/
void openpic_cause_IPI(unsigned int cpu, unsigned int ipi, unsigned int cpumask)
{
CHECK_THIS_CPU;
check_arg_ipi(ipi);
openpic_write(&OpenPIC->THIS_CPU.IPI_Dispatch(ipi), cpumask);
}
/* -------- Timer Interrupts ----------------------------------------------- */
/*
* Initialize a timer interrupt (and disable it)
*
* timer: OpenPIC timer number
* pri: interrupt source priority
* vec: the vector it will produce
*/
void openpic_inittimer(unsigned int timer, unsigned int pri, unsigned int vec)
{
check_arg_timer(timer);
check_arg_pri(pri);
check_arg_vec(vec);
openpic_safe_writefield(&OpenPIC->Global.Timer[timer].Vector_Priority,
OPENPIC_PRIORITY_MASK | OPENPIC_VECTOR_MASK,
(pri << OPENPIC_PRIORITY_SHIFT) | vec);
}
/*
* Map a timer interrupt to one or more CPUs
*/
void openpic_maptimer(unsigned int timer, unsigned int cpumask)
{
check_arg_timer(timer);
openpic_write(&OpenPIC->Global.Timer[timer].Destination, cpumask);
}
/* -------- Interrupt Sources ---------------------------------------------- */
/*
* Enable/disable an interrupt source
*/
void openpic_enable_irq(unsigned int irq)
{
check_arg_irq(irq);
openpic_clearfield(&OpenPIC->Source[irq].Vector_Priority, OPENPIC_MASK);
}
void openpic_disable_irq(unsigned int irq)
{
check_arg_irq(irq);
openpic_setfield(&OpenPIC->Source[irq].Vector_Priority, OPENPIC_MASK);
}
/*
* Initialize an interrupt source (and disable it!)
*
* irq: OpenPIC interrupt number
* pri: interrupt source priority
* vec: the vector it will produce
* pol: polarity (1 for positive, 0 for negative)
* sense: 1 for level, 0 for edge
*/
void openpic_initirq(unsigned int irq, unsigned int pri, unsigned int vec, int pol, int sense)
{
check_arg_irq(irq);
check_arg_pri(pri);
check_arg_vec(vec);
openpic_safe_writefield(&OpenPIC->Source[irq].Vector_Priority,
OPENPIC_PRIORITY_MASK | OPENPIC_VECTOR_MASK |
OPENPIC_SENSE_POLARITY | OPENPIC_SENSE_LEVEL,
(pri << OPENPIC_PRIORITY_SHIFT) | vec |
(pol ? OPENPIC_SENSE_POLARITY : 0) |
(sense ? OPENPIC_SENSE_LEVEL : 0));
}
/*
* Map an interrupt source to one or more CPUs
*/
void openpic_mapirq(unsigned int irq, unsigned int cpumask)
{
check_arg_irq(irq);
openpic_write(&OpenPIC->Source[irq].Destination, cpumask);
}
/*
* Set the sense for an interrupt source (and disable it!)
*
* sense: 1 for level, 0 for edge
*/
void openpic_set_sense(unsigned int irq, int sense)
{
check_arg_irq(irq);
openpic_safe_writefield(&OpenPIC->Source[irq].Vector_Priority,
OPENPIC_SENSE_LEVEL,
(sense ? OPENPIC_SENSE_LEVEL : 0));
}

View File

@@ -0,0 +1,340 @@
/*
* openpic.h -- OpenPIC definitions
*
* Copyright (C) 1997 Geert Uytterhoeven
*
* This file is based on the following documentation:
*
* The Open Programmable Interrupt Controller (PIC)
* Register Interface Specification Revision 1.2
*
* Issue Date: October 1995
*
* Issued jointly by Advanced Micro Devices and Cyrix Corporation
*
* AMD is a registered trademark of Advanced Micro Devices, Inc.
* Copyright (C) 1995, Advanced Micro Devices, Inc. and Cyrix, Inc.
* All Rights Reserved.
*
* To receive a copy of this documentation, send an email to openpic@amd.com.
*
* This file is subject to the terms and conditions of the GNU General Public
* License. See the file COPYING in the main directory of this archive
* for more details.
*
* Modified to compile in RTEMS development environment
* by Eric Valette
*
* Copyright (C) 1999 Eric Valette. valette@crf.canon.fr
*
* The license and distribution terms for this file may be
* found in found in the file LICENSE in this distribution or at
* http://www.OARcorp.com/rtems/license.html.
*
* $Id$
*/
#ifndef _RTEMS_OPENPIC_H
#define _RTEMS_OPENPIC_H
/*
* OpenPIC supports up to 2048 interrupt sources and up to 32 processors
*/
#define OPENPIC_MAX_SOURCES 2048
#define OPENPIC_MAX_PROCESSORS 32
#define OPENPIC_NUM_TIMERS 4
#define OPENPIC_NUM_IPI 4
#define OPENPIC_NUM_PRI 16
#define OPENPIC_NUM_VECTORS 256
/*
* Vector numbers
*/
#define OPENPIC_VEC_SOURCE 0x10 /* and up */
#define OPENPIC_VEC_TIMER 0x40 /* and up */
#define OPENPIC_VEC_IPI 0x50 /* and up */
#define OPENPIC_VEC_SPURIOUS 99
/*
* OpenPIC Registers are 32 bits and aligned on 128 bit boundaries
*/
typedef struct _OpenPIC_Reg {
unsigned int Reg; /* Little endian! */
char Pad[0xc];
} OpenPIC_Reg;
/*
* Per Processor Registers
*/
typedef struct _OpenPIC_Processor {
/*
* Private Shadow Registers (for SLiC backwards compatibility)
*/
unsigned int IPI0_Dispatch_Shadow; /* Write Only */
char Pad1[0x4];
unsigned int IPI0_Vector_Priority_Shadow; /* Read/Write */
char Pad2[0x34];
/*
* Interprocessor Interrupt Command Ports
*/
OpenPIC_Reg _IPI_Dispatch[OPENPIC_NUM_IPI]; /* Write Only */
/*
* Current Task Priority Register
*/
OpenPIC_Reg _Current_Task_Priority; /* Read/Write */
char Pad3[0x10];
/*
* Interrupt Acknowledge Register
*/
OpenPIC_Reg _Interrupt_Acknowledge; /* Read Only */
/*
* End of Interrupt (EOI) Register
*/
OpenPIC_Reg _EOI; /* Read/Write */
char Pad5[0xf40];
} OpenPIC_Processor;
/*
* Timer Registers
*/
typedef struct _OpenPIC_Timer {
OpenPIC_Reg _Current_Count; /* Read Only */
OpenPIC_Reg _Base_Count; /* Read/Write */
OpenPIC_Reg _Vector_Priority; /* Read/Write */
OpenPIC_Reg _Destination; /* Read/Write */
} OpenPIC_Timer;
/*
* Global Registers
*/
typedef struct _OpenPIC_Global {
/*
* Feature Reporting Registers
*/
OpenPIC_Reg _Feature_Reporting0; /* Read Only */
OpenPIC_Reg _Feature_Reporting1; /* Future Expansion */
/*
* Global Configuration Registers
*/
OpenPIC_Reg _Global_Configuration0; /* Read/Write */
OpenPIC_Reg _Global_Configuration1; /* Future Expansion */
/*
* Vendor Specific Registers
*/
OpenPIC_Reg _Vendor_Specific[4];
/*
* Vendor Identification Register
*/
OpenPIC_Reg _Vendor_Identification; /* Read Only */
/*
* Processor Initialization Register
*/
OpenPIC_Reg _Processor_Initialization; /* Read/Write */
/*
* IPI Vector/Priority Registers
*/
OpenPIC_Reg _IPI_Vector_Priority[OPENPIC_NUM_IPI]; /* Read/Write */
/*
* Spurious Vector Register
*/
OpenPIC_Reg _Spurious_Vector; /* Read/Write */
/*
* Global Timer Registers
*/
OpenPIC_Reg _Timer_Frequency; /* Read/Write */
OpenPIC_Timer Timer[OPENPIC_NUM_TIMERS];
char Pad1[0xee00];
} OpenPIC_Global;
/*
* Interrupt Source Registers
*/
typedef struct _OpenPIC_Source {
OpenPIC_Reg _Vector_Priority; /* Read/Write */
OpenPIC_Reg _Destination; /* Read/Write */
} OpenPIC_Source;
/*
* OpenPIC Register Map
*/
struct OpenPIC {
char Pad1[0x1000];
/*
* Global Registers
*/
OpenPIC_Global Global;
/*
* Interrupt Source Configuration Registers
*/
OpenPIC_Source Source[OPENPIC_MAX_SOURCES];
/*
* Per Processor Registers
*/
OpenPIC_Processor Processor[OPENPIC_MAX_PROCESSORS];
};
extern volatile struct OpenPIC *OpenPIC;
extern unsigned int OpenPIC_NumInitSenses;
extern unsigned char *OpenPIC_InitSenses;
/*
* Current Task Priority Register
*/
#define OPENPIC_CURRENT_TASK_PRIORITY_MASK 0x0000000f
/*
* Who Am I Register
*/
#define OPENPIC_WHO_AM_I_ID_MASK 0x0000001f
/*
* Feature Reporting Register 0
*/
#define OPENPIC_FEATURE_LAST_SOURCE_MASK 0x07ff0000
#define OPENPIC_FEATURE_LAST_SOURCE_SHIFT 16
#define OPENPIC_FEATURE_LAST_PROCESSOR_MASK 0x00001f00
#define OPENPIC_FEATURE_LAST_PROCESSOR_SHIFT 8
#define OPENPIC_FEATURE_VERSION_MASK 0x000000ff
/*
* Global Configuration Register 0
*/
#define OPENPIC_CONFIG_RESET 0x80000000
#define OPENPIC_CONFIG_8259_PASSTHROUGH_DISABLE 0x20000000
#define OPENPIC_CONFIG_BASE_MASK 0x000fffff
/*
* Vendor Identification Register
*/
#define OPENPIC_VENDOR_ID_STEPPING_MASK 0x00ff0000
#define OPENPIC_VENDOR_ID_STEPPING_SHIFT 16
#define OPENPIC_VENDOR_ID_DEVICE_ID_MASK 0x0000ff00
#define OPENPIC_VENDOR_ID_DEVICE_ID_SHIFT 8
#define OPENPIC_VENDOR_ID_VENDOR_ID_MASK 0x000000ff
/*
* Vector/Priority Registers
*/
#define OPENPIC_MASK 0x80000000
#define OPENPIC_ACTIVITY 0x40000000 /* Read Only */
#define OPENPIC_PRIORITY_MASK 0x000f0000
#define OPENPIC_PRIORITY_SHIFT 16
#define OPENPIC_VECTOR_MASK 0x000000ff
/*
* Interrupt Source Registers
*/
#define OPENPIC_SENSE_POLARITY 0x00800000 /* Undoc'd */
#define OPENPIC_SENSE_LEVEL 0x00400000
/*
* Timer Registers
*/
#define OPENPIC_COUNT_MASK 0x7fffffff
#define OPENPIC_TIMER_TOGGLE 0x80000000
#define OPENPIC_TIMER_COUNT_INHIBIT 0x80000000
/*
* Aliases to make life simpler
*/
/* Per Processor Registers */
#define IPI_Dispatch(i) _IPI_Dispatch[i].Reg
#define Current_Task_Priority _Current_Task_Priority.Reg
#define Interrupt_Acknowledge _Interrupt_Acknowledge.Reg
#define EOI _EOI.Reg
/* Global Registers */
#define Feature_Reporting0 _Feature_Reporting0.Reg
#define Feature_Reporting1 _Feature_Reporting1.Reg
#define Global_Configuration0 _Global_Configuration0.Reg
#define Global_Configuration1 _Global_Configuration1.Reg
#define Vendor_Specific(i) _Vendor_Specific[i].Reg
#define Vendor_Identification _Vendor_Identification.Reg
#define Processor_Initialization _Processor_Initialization.Reg
#define IPI_Vector_Priority(i) _IPI_Vector_Priority[i].Reg
#define Spurious_Vector _Spurious_Vector.Reg
#define Timer_Frequency _Timer_Frequency.Reg
/* Timer Registers */
#define Current_Count _Current_Count.Reg
#define Base_Count _Base_Count.Reg
#define Vector_Priority _Vector_Priority.Reg
#define Destination _Destination.Reg
/* Interrupt Source Registers */
#define Vector_Priority _Vector_Priority.Reg
#define Destination _Destination.Reg
/*
* Vendor and Device IDs
*/
#define OPENPIC_VENDOR_ID_APPLE 0x14
#define OPENPIC_DEVICE_ID_APPLE_HYDRA 0x46
/*
* OpenPIC Operations
*/
/* Global Operations */
extern void openpic_init(int);
extern void openpic_reset(void);
extern void openpic_enable_8259_pass_through(void);
extern void openpic_disable_8259_pass_through(void);
extern unsigned int openpic_irq(unsigned int cpu);
extern void openpic_eoi(unsigned int cpu);
extern unsigned int openpic_get_priority(unsigned int cpu);
extern void openpic_set_priority(unsigned int cpu, unsigned int pri);
extern unsigned int openpic_get_spurious(void);
extern void openpic_set_spurious(unsigned int vector);
extern void openpic_init_processor(unsigned int cpumask);
/* Interprocessor Interrupts */
extern void openpic_initipi(unsigned int ipi, unsigned int pri, unsigned int vector);
extern void openpic_cause_IPI(unsigned int cpu, unsigned int ipi, unsigned int cpumask);
/* Timer Interrupts */
extern void openpic_inittimer(unsigned int timer, unsigned int pri, unsigned int vector);
extern void openpic_maptimer(unsigned int timer, unsigned int cpumask);
/* Interrupt Sources */
extern void openpic_enable_irq(unsigned int irq);
extern void openpic_disable_irq(unsigned int irq);
extern void openpic_initirq(unsigned int irq, unsigned int pri, unsigned int vector, int polarity,
int is_level);
extern void openpic_mapirq(unsigned int irq, unsigned int cpumask);
extern void openpic_set_sense(unsigned int irq, int sense);
#endif /* RTEMS_OPENPIC_H */

View File

@@ -0,0 +1,42 @@
#
# $Id$
#
@SET_MAKE@
srcdir = @srcdir@
top_srcdir = @top_srcdir@
top_builddir = ../../..
subdir = powerpc/shared/pci
RTEMS_ROOT = @RTEMS_ROOT@
PROJECT_ROOT = @PROJECT_ROOT@
VPATH = @srcdir@
H_FILES = $(srcdir)/pci.h
SRCS = $(C_FILES) $(H_FILES)
include $(RTEMS_ROOT)/make/custom/@RTEMS_BSP@.cfg
include $(RTEMS_ROOT)/make/leaf.cfg
INSTALL_CHANGE = @INSTALL_CHANGE@
mkinstalldirs = $(SHELL) $(top_srcdir)/@RTEMS_TOPdir@/mkinstalldirs
INSTALLDIRS = $(PROJECT_INCLUDE)/bsp
$(INSTALLDIRS):
@$(mkinstalldirs) $(INSTALLDIRS)
preinstall:
@$(mkinstalldirs) $(PROJECT_INCLUDE)/bsp
@$(INSTALL_CHANGE) -m 644 $(H_FILES) $(PROJECT_INCLUDE)/bsp
all: ${ARCH} $(SRCS) preinstall
# the .rel file built here will be put into libbsp.a by ../wrapup/Makefile
install: all
Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
cd $(top_builddir) \
&& CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status

View File

@@ -0,0 +1,388 @@
/*
* pci.c : this file contains basic PCI Io functions.
*
* CopyRight (C) 1999 valette@crf.canon.fr
*
* This code is heavilly inspired by the public specification of STREAM V2
* that can be found at :
*
* <http://www.chorus.com/Documentation/index.html> by following
* the STREAM API Specification Document link.
*
* The license and distribution terms for this file may be
* found in found in the file LICENSE in this distribution or at
* http://www.OARcorp.com/rtems/license.html.
*
* $Id$
*/
#include <bsp/consoleIo.h>
#include <libcpu/io.h>
#include <bsp/pci.h>
#include <bsp/residual.h>
#include <bsp/openpic.h>
#include <bsp.h>
#define PCI_CONFIG_ADDR 0xcf8
#define PCI_CONFIG_DATA 0xcfc
#define PCI_INVALID_VENDORDEVICEID 0xffffffff
#define PCI_MULTI_FUNCTION 0x80
#define RAVEN_MPIC_IOSPACE_ENABLE 0x1
#define RAVEN_MPIC_MEMSPACE_ENABLE 0x2
#define RAVEN_MASTER_ENABLE 0x4
#define RAVEN_PARITY_CHECK_ENABLE 0x40
#define RAVEN_SYSTEM_ERROR_ENABLE 0x100
#define RAVEN_CLEAR_EVENTS_MASK 0xf9000000
/*
* Bit encode for PCI_CONFIG_HEADER_TYPE register
*/
unsigned char ucMaxPCIBus;
static int
indirect_pci_read_config_byte(unsigned char bus, unsigned char slot,
unsigned char function,
unsigned char offset, unsigned char *val) {
out_be32((unsigned int*) pci.pci_config_addr,
0x80|(bus<<8)|(PCI_DEVFN(slot,function)<<16)|((offset&~3)<<24));
*val = in_8(pci.pci_config_data + (offset&3));
return PCIBIOS_SUCCESSFUL;
}
static int
indirect_pci_read_config_word(unsigned char bus, unsigned char slot,
unsigned char function,
unsigned char offset, unsigned short *val) {
*val = 0xffff;
if (offset&1) return PCIBIOS_BAD_REGISTER_NUMBER;
out_be32((unsigned int*) pci.pci_config_addr,
0x80|(bus<<8)|(PCI_DEVFN(slot,function)<<16)|((offset&~3)<<24));
*val = in_le16((volatile unsigned short *)(pci.pci_config_data + (offset&3)));
return PCIBIOS_SUCCESSFUL;
}
static int
indirect_pci_read_config_dword(unsigned char bus, unsigned char slot,
unsigned char function,
unsigned char offset, unsigned int *val) {
*val = 0xffffffff;
if (offset&3) return PCIBIOS_BAD_REGISTER_NUMBER;
out_be32((unsigned int*) pci.pci_config_addr,
0x80|(bus<<8)|(PCI_DEVFN(slot,function)<<16)|(offset<<24));
*val = in_le32((volatile unsigned int *)pci.pci_config_data);
return PCIBIOS_SUCCESSFUL;
}
static int
indirect_pci_write_config_byte(unsigned char bus, unsigned char slot,
unsigned char function,
unsigned char offset, unsigned char val) {
out_be32((unsigned int*) pci.pci_config_addr,
0x80|(bus<<8)|(PCI_DEVFN(slot,function)<<16)|((offset&~3)<<24));
out_8(pci.pci_config_data + (offset&3), val);
return PCIBIOS_SUCCESSFUL;
}
static int
indirect_pci_write_config_word(unsigned char bus, unsigned char slot,
unsigned char function,
unsigned char offset, unsigned short val) {
if (offset&1) return PCIBIOS_BAD_REGISTER_NUMBER;
out_be32((unsigned int*) pci.pci_config_addr,
0x80|(bus<<8)|(PCI_DEVFN(slot,function)<<16)|((offset&~3)<<24));
out_le16((volatile unsigned short *)(pci.pci_config_data + (offset&3)), val);
return PCIBIOS_SUCCESSFUL;
}
static int
indirect_pci_write_config_dword(unsigned char bus, unsigned char slot,
unsigned char function,
unsigned char offset, unsigned int val) {
if (offset&3) return PCIBIOS_BAD_REGISTER_NUMBER;
out_be32((unsigned int*) pci.pci_config_addr,
0x80|(bus<<8)|(PCI_DEVFN(slot,function)<<16)|(offset<<24));
out_le32((volatile unsigned int *)pci.pci_config_data, val);
return PCIBIOS_SUCCESSFUL;
}
static const pci_config_access_functions indirect_functions = {
indirect_pci_read_config_byte,
indirect_pci_read_config_word,
indirect_pci_read_config_dword,
indirect_pci_write_config_byte,
indirect_pci_write_config_word,
indirect_pci_write_config_dword
};
pci_config pci = {(volatile unsigned char*)PCI_CONFIG_ADDR,
(volatile unsigned char*)PCI_CONFIG_DATA,
&indirect_functions};
static int
direct_pci_read_config_byte(unsigned char bus, unsigned char slot,
unsigned char function,
unsigned char offset, unsigned char *val) {
if (bus != 0 || (1<<slot & 0xff8007fe)) {
*val=0xff;
return PCIBIOS_DEVICE_NOT_FOUND;
}
*val=in_8(pci.pci_config_data + ((1<<slot)&~1)
+ (function<<8) + offset);
return PCIBIOS_SUCCESSFUL;
}
static int
direct_pci_read_config_word(unsigned char bus, unsigned char slot,
unsigned char function,
unsigned char offset, unsigned short *val) {
*val = 0xffff;
if (offset&1) return PCIBIOS_BAD_REGISTER_NUMBER;
if (bus != 0 || (1<<slot & 0xff8007fe)) {
return PCIBIOS_DEVICE_NOT_FOUND;
}
*val=in_le16((volatile unsigned short *)
(pci.pci_config_data + ((1<<slot)&~1)
+ (function<<8) + offset));
return PCIBIOS_SUCCESSFUL;
}
static int
direct_pci_read_config_dword(unsigned char bus, unsigned char slot,
unsigned char function,
unsigned char offset, unsigned int *val) {
*val = 0xffffffff;
if (offset&3) return PCIBIOS_BAD_REGISTER_NUMBER;
if (bus != 0 || (1<<slot & 0xff8007fe)) {
return PCIBIOS_DEVICE_NOT_FOUND;
}
*val=in_le32((volatile unsigned int *)
(pci.pci_config_data + ((1<<slot)&~1)
+ (function<<8) + offset));
return PCIBIOS_SUCCESSFUL;
}
static int
direct_pci_write_config_byte(unsigned char bus, unsigned char slot,
unsigned char function,
unsigned char offset, unsigned char val) {
if (bus != 0 || (1<<slot & 0xff8007fe)) {
return PCIBIOS_DEVICE_NOT_FOUND;
}
out_8(pci.pci_config_data + ((1<<slot)&~1)
+ (function<<8) + offset,
val);
return PCIBIOS_SUCCESSFUL;
}
static int
direct_pci_write_config_word(unsigned char bus, unsigned char slot,
unsigned char function,
unsigned char offset, unsigned short val) {
if (offset&1) return PCIBIOS_BAD_REGISTER_NUMBER;
if (bus != 0 || (1<<slot & 0xff8007fe)) {
return PCIBIOS_DEVICE_NOT_FOUND;
}
out_le16((volatile unsigned short *)
(pci.pci_config_data + ((1<<slot)&~1)
+ (function<<8) + offset),
val);
return PCIBIOS_SUCCESSFUL;
}
static int
direct_pci_write_config_dword(unsigned char bus, unsigned char slot,
unsigned char function,
unsigned char offset, unsigned int val) {
if (offset&3) return PCIBIOS_BAD_REGISTER_NUMBER;
if (bus != 0 || (1<<slot & 0xff8007fe)) {
return PCIBIOS_DEVICE_NOT_FOUND;
}
out_le32((volatile unsigned int *)
(pci.pci_config_data + ((1<<slot)&~1)
+ (function<<8) + offset),
val);
return PCIBIOS_SUCCESSFUL;
}
static const pci_config_access_functions direct_functions = {
direct_pci_read_config_byte,
direct_pci_read_config_word,
direct_pci_read_config_dword,
direct_pci_write_config_byte,
direct_pci_write_config_word,
direct_pci_write_config_dword
};
void detect_host_bridge()
{
PPC_DEVICE *hostbridge;
unsigned int id0;
unsigned int tmp;
/*
* This code assumes that the host bridge is located at
* bus 0, dev 0, func 0 AND that the old pre PCI 2.1
* standart devices detection mecahnism that was used on PC
* (still used in BSD source code) works.
*/
hostbridge=residual_find_device(&residualCopy, PROCESSORDEVICE, NULL,
BridgeController,
PCIBridge, -1, 0);
if (hostbridge) {
if (hostbridge->DeviceId.Interface==PCIBridgeIndirect) {
pci.pci_functions=&indirect_functions;
/* Should be extracted from residual data,
* indeed MPC106 in CHRP mode is different,
* but we should not use residual data in
* this case anyway.
*/
pci.pci_config_addr = ((volatile unsigned char *)
(ptr_mem_map->io_base+0xcf8));
pci.pci_config_data = ptr_mem_map->io_base+0xcfc;
} else if(hostbridge->DeviceId.Interface==PCIBridgeDirect) {
pci.pci_functions=&direct_functions;
pci.pci_config_data=(unsigned char *) 0x80800000;
} else {
}
} else {
/* Let us try by experimentation at our own risk! */
pci.pci_functions = &direct_functions;
/* On all direct bridges I know the host bridge itself
* appears as device 0 function 0.
*/
pci_read_config_dword(0, 0, 0, PCI_VENDOR_ID, &id0);
if (id0==~0U) {
pci.pci_functions = &indirect_functions;
pci.pci_config_addr = ((volatile unsigned char*)
(ptr_mem_map->io_base+0xcf8));
pci.pci_config_data = ((volatile unsigned char*)ptr_mem_map->io_base+0xcfc);
}
/* Here we should check that the host bridge is actually
* present, but if it not, we are in such a desperate
* situation, that we probably can't even tell it.
*/
}
pci_read_config_dword(0, 0, 0, 0, &id0);
if(id0 == PCI_VENDOR_ID_MOTOROLA +
(PCI_DEVICE_ID_MOTOROLA_RAVEN<<16)) {
/*
* We have a Raven bridge. We will get information about its settings
*/
pci_read_config_dword(0, 0, 0, PCI_COMMAND, &id0);
#ifdef SHOW_RAVEN_SETTING
printk("RAVEN PCI command register = %x\n",id0);
#endif
id0 |= RAVEN_CLEAR_EVENTS_MASK;
pci_write_config_dword(0, 0, 0, PCI_COMMAND, id0);
pci_read_config_dword(0, 0, 0, PCI_COMMAND, &id0);
#ifdef SHOW_RAVEN_SETTING
printk("After error clearing RAVEN PCI command register = %x\n",id0);
#endif
if (id0 & RAVEN_MPIC_IOSPACE_ENABLE) {
pci_read_config_dword(0, 0, 0,PCI_BASE_ADDRESS_0, &tmp);
#ifdef SHOW_RAVEN_SETTING
printk("Raven MPIC is accessed via IO Space Access at address : %x\n",(tmp & ~0x1));
#endif
}
if (id0 & RAVEN_MPIC_MEMSPACE_ENABLE) {
pci_read_config_dword(0, 0, 0,PCI_BASE_ADDRESS_1, &tmp);
#ifdef SHOW_RAVEN_SETTING
printk("Raven MPIC is accessed via memory Space Access at address : %x\n", tmp);
#endif
OpenPIC=(volatile struct OpenPIC *) (tmp + PREP_ISA_MEM_BASE);
printk("OpenPIC found at %p.\n",
OpenPIC);
}
}
if (OpenPIC == (volatile struct OpenPIC *)0) {
BSP_panic("OpenPic Not found\n");
}
}
/*
* This routine determines the maximum bus number in the system
*/
void InitializePCI()
{
unsigned char ucSlotNumber, ucFnNumber, ucNumFuncs;
unsigned char ucHeader;
unsigned char ucMaxSubordinate;
unsigned int ulClass, ulDeviceID;
detect_host_bridge();
/*
* Scan PCI bus 0 looking for PCI-PCI bridges
*/
for(ucSlotNumber=0;ucSlotNumber<PCI_MAX_DEVICES;ucSlotNumber++) {
(void)pci_read_config_dword(0,
ucSlotNumber,
0,
PCI_VENDOR_ID,
&ulDeviceID);
if(ulDeviceID==PCI_INVALID_VENDORDEVICEID) {
/*
* This slot is empty
*/
continue;
}
(void)pci_read_config_byte(0,
ucSlotNumber,
0,
PCI_HEADER_TYPE,
&ucHeader);
if(ucHeader&PCI_MULTI_FUNCTION) {
ucNumFuncs=PCI_MAX_FUNCTIONS;
}
else {
ucNumFuncs=1;
}
for(ucFnNumber=0;ucFnNumber<ucNumFuncs;ucFnNumber++) {
(void)pci_read_config_dword(0,
ucSlotNumber,
ucFnNumber,
PCI_VENDOR_ID,
&ulDeviceID);
if(ulDeviceID==PCI_INVALID_VENDORDEVICEID) {
/*
* This slot/function is empty
*/
continue;
}
/*
* This slot/function has a device fitted.
*/
(void)pci_read_config_dword(0,
ucSlotNumber,
ucFnNumber,
PCI_CLASS_REVISION,
&ulClass);
ulClass >>= 16;
if (ulClass == PCI_CLASS_BRIDGE_PCI) {
/*
* We have found a PCI-PCI bridge
*/
(void)pci_read_config_byte(0,
ucSlotNumber,
ucFnNumber,
PCI_SUBORDINATE_BUS,
&ucMaxSubordinate);
if(ucMaxSubordinate>ucMaxPCIBus) {
ucMaxPCIBus=ucMaxSubordinate;
}
}
}
}
}
/*
* Return the number of PCI busses in the system
*/
unsigned char BusCountPCI()
{
return(ucMaxPCIBus+1);
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,50 @@
#
# $Id$
#
@SET_MAKE@
srcdir = @srcdir@
top_srcdir = @top_srcdir@
top_builddir = ../../..
subdir = powerpc/shared/residual
RTEMS_ROOT = @RTEMS_ROOT@
PROJECT_ROOT = @PROJECT_ROOT@
VPATH = @srcdir@
PGM = ${ARCH}/residual.rel
# C source names, if any, go here -- minus the .c
C_PIECES = $(RESIDUAL_C_PIECES)
C_FILES = $(C_PIECES:%=%.c)
C_O_FILES = $(C_PIECES:%=${ARCH}/%.o)
H_FILES = $(srcdir)/pnp.h $(srcdir)/residual.h
SRCS = $(C_FILES) $(H_FILES)
OBJS = $(C_O_FILES)
include $(RTEMS_ROOT)/make/custom/@RTEMS_BSP@.cfg
include $(RTEMS_ROOT)/make/leaf.cfg
INSTALL_CHANGE = @INSTALL_CHANGE@
mkinstalldirs = $(SHELL) $(top_srcdir)/@RTEMS_TOPdir@/mkinstalldirs
INSTALLDIRS = $(PROJECT_INCLUDE)/bsp
$(INSTALLDIRS):
@$(mkinstalldirs) $(INSTALLDIRS)
preinstall:
@$(mkinstalldirs) $(PROJECT_INCLUDE)/bsp
@$(INSTALL_CHANGE) -m 644 $(H_FILES) $(PROJECT_INCLUDE)/bsp
all: ${ARCH} $(SRCS) preinstall
# the .rel file built here will be put into libbsp.a by ../wrapup/Makefile
install: all
Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
cd $(top_builddir) \
&& CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status

View File

@@ -0,0 +1,647 @@
/* 11/02/95 */
/*----------------------------------------------------------------------------*/
/* Plug and Play header definitions */
/*----------------------------------------------------------------------------*/
/* Structure map for PnP on PowerPC Reference Platform */
/* See Plug and Play ISA Specification, Version 1.0, May 28, 1993. It */
/* (or later versions) is available on Compuserve in the PLUGPLAY area. */
/* This code has extensions to that specification, namely new short and */
/* long tag types for platform dependent information */
/* Warning: LE notation used throughout this file */
/* For enum's: if given in hex then they are bit significant, i.e. */
/* only one bit is on for each enum */
/*
* $Id$
*/
#ifndef _PNP_
#define _PNP_
#ifndef ASM
#define MAX_MEM_REGISTERS 9
#define MAX_IO_PORTS 20
#define MAX_IRQS 7
/*#define MAX_DMA_CHANNELS 7*/
/* Interrupt controllers */
#define PNPinterrupt0 "PNP0000" /* AT Interrupt Controller */
#define PNPinterrupt1 "PNP0001" /* EISA Interrupt Controller */
#define PNPinterrupt2 "PNP0002" /* MCA Interrupt Controller */
#define PNPinterrupt3 "PNP0003" /* APIC */
#define PNPExtInt "IBM000D" /* PowerPC Extended Interrupt Controller */
/* Timers */
#define PNPtimer0 "PNP0100" /* AT Timer */
#define PNPtimer1 "PNP0101" /* EISA Timer */
#define PNPtimer2 "PNP0102" /* MCA Timer */
/* DMA controllers */
#define PNPdma0 "PNP0200" /* AT DMA Controller */
#define PNPdma1 "PNP0201" /* EISA DMA Controller */
#define PNPdma2 "PNP0202" /* MCA DMA Controller */
/* start of August 15, 1994 additions */
/* CMOS */
#define PNPCMOS "IBM0009" /* CMOS */
/* L2 Cache */
#define PNPL2 "IBM0007" /* L2 Cache */
/* NVRAM */
#define PNPNVRAM "IBM0008" /* NVRAM */
/* Power Management */
#define PNPPM "IBM0005" /* Power Management */
/* end of August 15, 1994 additions */
/* Keyboards */
#define PNPkeyboard0 "PNP0300" /* IBM PC/XT KB Cntlr (83 key, no mouse) */
#define PNPkeyboard1 "PNP0301" /* Olivetti ICO (102 key) */
#define PNPkeyboard2 "PNP0302" /* IBM PC/AT KB Cntlr (84 key) */
#define PNPkeyboard3 "PNP0303" /* IBM Enhanced (101/2 key, PS/2 mouse) */
#define PNPkeyboard4 "PNP0304" /* Nokia 1050 KB Cntlr */
#define PNPkeyboard5 "PNP0305" /* Nokia 9140 KB Cntlr */
#define PNPkeyboard6 "PNP0306" /* Standard Japanese KB Cntlr */
#define PNPkeyboard7 "PNP0307" /* Microsoft Windows (R) KB Cntlr */
/* Parallel port controllers */
#define PNPparallel0 "PNP0400" /* Standard LPT Parallel Port */
#define PNPparallel1 "PNP0401" /* ECP Parallel Port */
#define PNPepp "IBM001C" /* EPP Parallel Port */
/* Serial port controllers */
#define PNPserial0 "PNP0500" /* Standard PC Serial port */
#define PNPSerial1 "PNP0501" /* 16550A Compatible Serial port */
/* Disk controllers */
#define PNPdisk0 "PNP0600" /* Generic ESDI/IDE/ATA Compat HD Cntlr */
#define PNPdisk1 "PNP0601" /* Plus Hardcard II */
#define PNPdisk2 "PNP0602" /* Plus Hardcard IIXL/EZ */
/* Diskette controllers */
#define PNPdiskette0 "PNP0700" /* PC Standard Floppy Disk Controller */
/* Display controllers */
#define PNPdisplay0 "PNP0900" /* VGA Compatible */
#define PNPdisplay1 "PNP0901" /* Video Seven VGA */
#define PNPdisplay2 "PNP0902" /* 8514/A Compatible */
#define PNPdisplay3 "PNP0903" /* Trident VGA */
#define PNPdisplay4 "PNP0904" /* Cirrus Logic Laptop VGA */
#define PNPdisplay5 "PNP0905" /* Cirrus Logic VGA */
#define PNPdisplay6 "PNP0906" /* Tseng ET4000 or ET4000/W32 */
#define PNPdisplay7 "PNP0907" /* Western Digital VGA */
#define PNPdisplay8 "PNP0908" /* Western Digital Laptop VGA */
#define PNPdisplay9 "PNP0909" /* S3 */
#define PNPdisplayA "PNP090A" /* ATI Ultra Pro/Plus (Mach 32) */
#define PNPdisplayB "PNP090B" /* ATI Ultra (Mach 8) */
#define PNPdisplayC "PNP090C" /* XGA Compatible */
#define PNPdisplayD "PNP090D" /* ATI VGA Wonder */
#define PNPdisplayE "PNP090E" /* Weitek P9000 Graphics Adapter */
#define PNPdisplayF "PNP090F" /* Oak Technology VGA */
/* Peripheral busses */
#define PNPbuses0 "PNP0A00" /* ISA Bus */
#define PNPbuses1 "PNP0A01" /* EISA Bus */
#define PNPbuses2 "PNP0A02" /* MCA Bus */
#define PNPbuses3 "PNP0A03" /* PCI Bus */
#define PNPbuses4 "PNP0A04" /* VESA/VL Bus */
/* RTC, BIOS, planar devices */
#define PNPspeaker0 "PNP0800" /* AT Style Speaker Sound */
#define PNPrtc0 "PNP0B00" /* AT RTC */
#define PNPpnpbios0 "PNP0C00" /* PNP BIOS (only created by root enum) */
#define PNPpnpbios1 "PNP0C01" /* System Board Memory Device */
#define PNPpnpbios2 "PNP0C02" /* Math Coprocessor */
#define PNPpnpbios3 "PNP0C03" /* PNP BIOS Event Notification Interrupt */
/* PCMCIA controller */
#define PNPpcmcia0 "PNP0E00" /* Intel 82365 Compatible PCMCIA Cntlr */
/* Mice */
#define PNPmouse0 "PNP0F00" /* Microsoft Bus Mouse */
#define PNPmouse1 "PNP0F01" /* Microsoft Serial Mouse */
#define PNPmouse2 "PNP0F02" /* Microsoft Inport Mouse */
#define PNPmouse3 "PNP0F03" /* Microsoft PS/2 Mouse */
#define PNPmouse4 "PNP0F04" /* Mousesystems Mouse */
#define PNPmouse5 "PNP0F05" /* Mousesystems 3 Button Mouse - COM2 */
#define PNPmouse6 "PNP0F06" /* Genius Mouse - COM1 */
#define PNPmouse7 "PNP0F07" /* Genius Mouse - COM2 */
#define PNPmouse8 "PNP0F08" /* Logitech Serial Mouse */
#define PNPmouse9 "PNP0F09" /* Microsoft Ballpoint Serial Mouse */
#define PNPmouseA "PNP0F0A" /* Microsoft PNP Mouse */
#define PNPmouseB "PNP0F0B" /* Microsoft PNP Ballpoint Mouse */
/* Modems */
#define PNPmodem0 "PNP9000" /* Specific IDs TBD */
/* Network controllers */
#define PNPnetworkC9 "PNP80C9" /* IBM Token Ring */
#define PNPnetworkCA "PNP80CA" /* IBM Token Ring II */
#define PNPnetworkCB "PNP80CB" /* IBM Token Ring II/Short */
#define PNPnetworkCC "PNP80CC" /* IBM Token Ring 4/16Mbs */
#define PNPnetwork27 "PNP8327" /* IBM Token Ring (All types) */
#define PNPnetworket "IBM0010" /* IBM Ethernet used by Power PC */
#define PNPneteisaet "IBM2001" /* IBM Ethernet EISA adapter */
#define PNPAMD79C970 "IBM0016" /* AMD 79C970 (PCI Ethernet) */
/* SCSI controllers */
#define PNPscsi0 "PNPA000" /* Adaptec 154x Compatible SCSI Cntlr */
#define PNPscsi1 "PNPA001" /* Adaptec 174x Compatible SCSI Cntlr */
#define PNPscsi2 "PNPA002" /* Future Domain 16-700 Compat SCSI Cntlr*/
#define PNPscsi3 "PNPA003" /* Panasonic CDROM Adapter (SBPro/SB16) */
#define PNPscsiF "IBM000F" /* NCR 810 SCSI Controller */
#define PNPscsi825 "IBM001B" /* NCR 825 SCSI Controller */
#define PNPscsi875 "IBM0018" /* NCR 875 SCSI Controller */
/* Sound/Video, Multimedia */
#define PNPmm0 "PNPB000" /* Sound Blaster Compatible Sound Device */
#define PNPmm1 "PNPB001" /* MS Windows Sound System Compat Device */
#define PNPmmF "IBM000E" /* Crystal CS4231 Audio Device */
#define PNPv7310 "IBM0015" /* ASCII V7310 Video Capture Device */
#define PNPmm4232 "IBM0017" /* Crystal CS4232 Audio Device */
#define PNPpmsyn "IBM001D" /* YMF 289B chip (Yamaha) */
#define PNPgp4232 "IBM0012" /* Crystal CS4232 Game Port */
#define PNPmidi4232 "IBM0013" /* Crystal CS4232 MIDI */
/* Operator Panel */
#define PNPopctl "IBM000B" /* Operator's panel */
/* Service Processor */
#define PNPsp "IBM0011" /* IBM Service Processor */
#define PNPLTsp "IBM001E" /* Lightning/Terlingua Support Processor */
#define PNPLTmsp "IBM001F" /* Lightning/Terlingua Mini-SP */
/* Memory Controller */
#define PNPmemctl "IBM000A" /* Memory controller */
/* Graphics Assist */
#define PNPg_assist "IBM0014" /* Graphics Assist */
/* Miscellaneous Device Controllers */
#define PNPtablet "IBM0019" /* IBM Tablet Controller */
/* PNP Packet Handles */
#define S1_Packet 0x0A /* Version resource */
#define S2_Packet 0x15 /* Logical DEVID (without flags) */
#define S2_Packet_flags 0x16 /* Logical DEVID (with flags) */
#define S3_Packet 0x1C /* Compatible device ID */
#define S4_Packet 0x22 /* IRQ resource (without flags) */
#define S4_Packet_flags 0x23 /* IRQ resource (with flags) */
#define S5_Packet 0x2A /* DMA resource */
#define S6_Packet 0x30 /* Depend funct start (w/o priority) */
#define S6_Packet_priority 0x31 /* Depend funct start (w/ priority) */
#define S7_Packet 0x38 /* Depend funct end */
#define S8_Packet 0x47 /* I/O port resource (w/o fixed loc) */
#define S9_Packet_fixed 0x4B /* I/O port resource (w/ fixed loc) */
#define S14_Packet 0x71 /* Vendor defined */
#define S15_Packet 0x78 /* End of resource (w/o checksum) */
#define S15_Packet_checksum 0x79 /* End of resource (w/ checksum) */
#define L1_Packet 0x81 /* Memory range */
#define L1_Shadow 0x20 /* Memory is shadowable */
#define L1_32bit_mem 0x18 /* 32-bit memory only */
#define L1_8_16bit_mem 0x10 /* 8- and 16-bit supported */
#define L1_Decode_Hi 0x04 /* decode supports high address */
#define L1_Cache 0x02 /* read cacheable, write-through */
#define L1_Writeable 0x01 /* Memory is writeable */
#define L2_Packet 0x82 /* ANSI ID string */
#define L3_Packet 0x83 /* Unicode ID string */
#define L4_Packet 0x84 /* Vendor defined */
#define L5_Packet 0x85 /* Large I/O */
#define L6_Packet 0x86 /* 32-bit Fixed Loc Mem Range Desc */
#define END_TAG 0x78 /* End of resource */
#define DF_START_TAG 0x30 /* Dependent function start */
#define DF_START_TAG_priority 0x31 /* Dependent function start */
#define DF_END_TAG 0x38 /* Dependent function end */
#define SUBOPTIMAL_CONFIGURATION 0x2 /* Priority byte sub optimal config */
/* Device Base Type Codes */
typedef enum _PnP_BASE_TYPE {
Reserved = 0,
MassStorageDevice = 1,
NetworkInterfaceController = 2,
DisplayController = 3,
MultimediaController = 4,
MemoryController = 5,
BridgeController = 6,
CommunicationsDevice = 7,
SystemPeripheral = 8,
InputDevice = 9,
ServiceProcessor = 0x0A, /* 11/2/95 */
} PnP_BASE_TYPE;
/* Device Sub Type Codes */
typedef enum _PnP_SUB_TYPE {
SCSIController = 0,
IDEController = 1,
FloppyController = 2,
IPIController = 3,
OtherMassStorageController = 0x80,
EthernetController = 0,
TokenRingController = 1,
FDDIController = 2,
OtherNetworkController = 0x80,
VGAController= 0,
SVGAController= 1,
XGAController= 2,
OtherDisplayController = 0x80,
VideoController = 0,
AudioController = 1,
OtherMultimediaController = 0x80,
RAM = 0,
FLASH = 1,
OtherMemoryDevice = 0x80,
HostProcessorBridge = 0,
ISABridge = 1,
EISABridge = 2,
MicroChannelBridge = 3,
PCIBridge = 4,
PCMCIABridge = 5,
VMEBridge = 6,
OtherBridgeDevice = 0x80,
RS232Device = 0,
ATCompatibleParallelPort = 1,
OtherCommunicationsDevice = 0x80,
ProgrammableInterruptController = 0,
DMAController = 1,
SystemTimer = 2,
RealTimeClock = 3,
L2Cache = 4,
NVRAM = 5,
PowerManagement = 6,
CMOS = 7,
OperatorPanel = 8,
ServiceProcessorClass1 = 9,
ServiceProcessorClass2 = 0xA,
ServiceProcessorClass3 = 0xB,
GraphicAssist = 0xC,
SystemPlanar = 0xF, /* 10/5/95 */
OtherSystemPeripheral = 0x80,
KeyboardController = 0,
Digitizer = 1,
MouseController = 2,
TabletController = 3, /* 10/27/95 */
OtherInputController = 0x80,
GeneralMemoryController = 0,
} PnP_SUB_TYPE;
/* Device Interface Type Codes */
typedef enum _PnP_INTERFACE {
General = 0,
GeneralSCSI = 0,
GeneralIDE = 0,
ATACompatible = 1,
GeneralFloppy = 0,
Compatible765 = 1,
NS398_Floppy = 2, /* NS Super I/O wired to use index
register at port 398 and data
register at port 399 */
NS26E_Floppy = 3, /* Ports 26E and 26F */
NS15C_Floppy = 4, /* Ports 15C and 15D */
NS2E_Floppy = 5, /* Ports 2E and 2F */
CHRP_Floppy = 6, /* CHRP Floppy in PR*P system */
GeneralIPI = 0,
GeneralEther = 0,
GeneralToken = 0,
GeneralFDDI = 0,
GeneralVGA = 0,
GeneralSVGA = 0,
GeneralXGA = 0,
GeneralVideo = 0,
GeneralAudio = 0,
CS4232Audio = 1, /* CS 4232 Plug 'n Play Configured */
GeneralRAM = 0,
GeneralFLASH = 0,
PCIMemoryController = 0, /* PCI Config Method */
RS6KMemoryController = 1, /* RS6K Config Method */
GeneralHostBridge = 0,
GeneralISABridge = 0,
GeneralEISABridge = 0,
GeneralMCABridge = 0,
GeneralPCIBridge = 0,
PCIBridgeDirect = 0,
PCIBridgeIndirect = 1,
PCIBridgeRS6K = 2,
GeneralPCMCIABridge = 0,
GeneralVMEBridge = 0,
GeneralRS232 = 0,
COMx = 1,
Compatible16450 = 2,
Compatible16550 = 3,
NS398SerPort = 4, /* NS Super I/O wired to use index
register at port 398 and data
register at port 399 */
NS26ESerPort = 5, /* Ports 26E and 26F */
NS15CSerPort = 6, /* Ports 15C and 15D */
NS2ESerPort = 7, /* Ports 2E and 2F */
GeneralParPort = 0,
LPTx = 1,
NS398ParPort = 2, /* NS Super I/O wired to use index
register at port 398 and data
register at port 399 */
NS26EParPort = 3, /* Ports 26E and 26F */
NS15CParPort = 4, /* Ports 15C and 15D */
NS2EParPort = 5, /* Ports 2E and 2F */
GeneralPIC = 0,
ISA_PIC = 1,
EISA_PIC = 2,
MPIC = 3,
RS6K_PIC = 4,
GeneralDMA = 0,
ISA_DMA = 1,
EISA_DMA = 2,
GeneralTimer = 0,
ISA_Timer = 1,
EISA_Timer = 2,
GeneralRTC = 0,
ISA_RTC = 1,
StoreThruOnly = 1,
StoreInEnabled = 2,
RS6KL2Cache = 3,
IndirectNVRAM = 0, /* Indirectly addressed */
DirectNVRAM = 1, /* Memory Mapped */
IndirectNVRAM24 = 2, /* Indirectly addressed - 24 bit */
GeneralPowerManagement = 0,
EPOWPowerManagement = 1,
PowerControl = 2, /* d1378 */
GeneralCMOS = 0,
GeneralOPPanel = 0,
HarddiskLight = 1,
CDROMLight = 2,
PowerLight = 3,
KeyLock = 4,
ANDisplay = 5, /* AlphaNumeric Display */
SystemStatusLED = 6, /* 3 digit 7 segment LED */
CHRP_SystemStatusLED = 7, /* CHRP LEDs in PR*P system */
GeneralServiceProcessor = 0,
TransferData = 1,
IGMC32 = 2,
IGMC64 = 3,
GeneralSystemPlanar = 0, /* 10/5/95 */
} PnP_INTERFACE;
/* PnP resources */
/* Compressed ASCII is 5 bits per char; 00001=A ... 11010=Z */
typedef struct _SERIAL_ID {
unsigned char VendorID0; /* Bit(7)=0 */
/* Bits(6:2)=1st character in */
/* compressed ASCII */
/* Bits(1:0)=2nd character in */
/* compressed ASCII bits(4:3) */
unsigned char VendorID1; /* Bits(7:5)=2nd character in */
/* compressed ASCII bits(2:0) */
/* Bits(4:0)=3rd character in */
/* compressed ASCII */
unsigned char VendorID2; /* Product number - vendor assigned */
unsigned char VendorID3; /* Product number - vendor assigned */
/* Serial number is to provide uniqueness if more than one board of same */
/* type is in system. Must be "FFFFFFFF" if feature not supported. */
unsigned char Serial0; /* Unique serial number bits (7:0) */
unsigned char Serial1; /* Unique serial number bits (15:8) */
unsigned char Serial2; /* Unique serial number bits (23:16) */
unsigned char Serial3; /* Unique serial number bits (31:24) */
unsigned char Checksum;
} SERIAL_ID;
typedef enum _PnPItemName {
Unused = 0,
PnPVersion = 1,
LogicalDevice = 2,
CompatibleDevice = 3,
IRQFormat = 4,
DMAFormat = 5,
StartDepFunc = 6,
EndDepFunc = 7,
IOPort = 8,
FixedIOPort = 9,
Res1 = 10,
Res2 = 11,
Res3 = 12,
SmallVendorItem = 14,
EndTag = 15,
MemoryRange = 1,
ANSIIdentifier = 2,
UnicodeIdentifier = 3,
LargeVendorItem = 4,
MemoryRange32 = 5,
MemoryRangeFixed32 = 6,
} PnPItemName;
/* Define a bunch of access functions for the bits in the tag field */
/* Tag type - 0 = small; 1 = large */
#define tag_type(t) (((t) & 0x80)>>7)
#define set_tag_type(t,v) (t = (t & 0x7f) | ((v)<<7))
/* Small item name is 4 bits - one of PnPItemName enum above */
#define tag_small_item_name(t) (((t) & 0x78)>>3)
#define set_tag_small_item_name(t,v) (t = (t & 0x07) | ((v)<<3))
/* Small item count is 3 bits - count of further bytes in packet */
#define tag_small_count(t) ((t) & 0x07)
#define set_tag_count(t,v) (t = (t & 0x78) | (v))
/* Large item name is 7 bits - one of PnPItemName enum above */
#define tag_large_item_name(t) ((t) & 0x7f)
#define set_tag_large_item_name(t,v) (t = (t | 0x80) | (v))
/* a PnP resource is a bunch of contiguous TAG packets ending with an end tag */
typedef union _PnP_TAG_PACKET {
struct _S1_Pack{ /* VERSION PACKET */
unsigned char Tag; /* small tag = 0x0a */
unsigned char Version[2]; /* PnP version, Vendor version */
} S1_Pack;
struct _S2_Pack{ /* LOGICAL DEVICE ID PACKET */
unsigned char Tag; /* small tag = 0x15 or 0x16 */
unsigned char DevId[4]; /* Logical device id */
unsigned char Flags[2]; /* bit(0) boot device; */
/* bit(7:1) cmd in range x31-x37 */
/* bit(7:0) cmd in range x28-x3f (opt)*/
} S2_Pack;
struct _S3_Pack{ /* COMPATIBLE DEVICE ID PACKET */
unsigned char Tag; /* small tag = 0x1c */
unsigned char CompatId[4]; /* Compatible device id */
} S3_Pack;
struct _S4_Pack{ /* IRQ PACKET */
unsigned char Tag; /* small tag = 0x22 or 0x23 */
unsigned char IRQMask[2]; /* bit(0) is IRQ0, ...; */
/* bit(0) is IRQ8 ... */
unsigned char IRQInfo; /* optional; assume bit(0)=1; else */
/* bit(0) - high true edge sensitive */
/* bit(1) - low true edge sensitive */
/* bit(2) - high true level sensitive*/
/* bit(3) - low true level sensitive */
/* bit(7:4) - must be 0 */
} S4_Pack;
struct _S5_Pack{ /* DMA PACKET */
unsigned char Tag; /* small tag = 0x2a */
unsigned char DMAMask; /* bit(0) is channel 0 ... */
unsigned char DMAInfo;
} S5_Pack;
struct _S6_Pack{ /* START DEPENDENT FUNCTION PACKET */
unsigned char Tag; /* small tag = 0x30 or 0x31 */
unsigned char Priority; /* Optional; if missing then x01; else*/
/* x00 = best possible */
/* x01 = acceptible */
/* x02 = sub-optimal but functional */
} S6_Pack;
struct _S7_Pack{ /* END DEPENDENT FUNCTION PACKET */
unsigned char Tag; /* small tag = 0x38 */
} S7_Pack;
struct _S8_Pack{ /* VARIABLE I/O PORT PACKET */
unsigned char Tag; /* small tag x47 */
unsigned char IOInfo; /* x0 = decode only bits(9:0); */
#define ISAAddr16bit 0x01 /* x01 = decode bits(15:0) */
unsigned char RangeMin[2]; /* Min base address */
unsigned char RangeMax[2]; /* Max base address */
unsigned char IOAlign; /* base alignmt, incr in 1B blocks */
unsigned char IONum; /* number of contiguous I/O ports */
} S8_Pack;
struct _S9_Pack{ /* FIXED I/O PORT PACKET */
unsigned char Tag; /* small tag = 0x4b */
unsigned char Range[2]; /* base address 10 bits */
unsigned char IONum; /* number of contiguous I/O ports */
} S9_Pack;
struct _S14_Pack{ /* VENDOR DEFINED PACKET */
unsigned char Tag; /* small tag = 0x7m m = 1-7 */
union _S14_Data{
unsigned char Data[7]; /* Vendor defined */
struct _S14_PPCPack{ /* Pr*p s14 pack */
unsigned char Type; /* 00=non-IBM */
unsigned char PPCData[6]; /* Vendor defined */
} S14_PPCPack;
} S14_Data;
} S14_Pack;
struct _S15_Pack{ /* END PACKET */
unsigned char Tag; /* small tag = 0x78 or 0x79 */
unsigned char Check; /* optional - checksum */
} S15_Pack;
struct _L1_Pack{ /* MEMORY RANGE PACKET */
unsigned char Tag; /* large tag = 0x81 */
unsigned char Count0; /* x09 */
unsigned char Count1; /* x00 */
unsigned char Data[9]; /* a variable array of bytes, */
/* count in tag */
} L1_Pack;
struct _L2_Pack{ /* ANSI ID STRING PACKET */
unsigned char Tag; /* large tag = 0x82 */
unsigned char Count0; /* Length of string */
unsigned char Count1;
unsigned char Identifier[1]; /* a variable array of bytes, */
/* count in tag */
} L2_Pack;
struct _L3_Pack{ /* UNICODE ID STRING PACKET */
unsigned char Tag; /* large tag = 0x83 */
unsigned char Count0; /* Length + 2 of string */
unsigned char Count1;
unsigned char Country0; /* TBD */
unsigned char Country1; /* TBD */
unsigned char Identifier[1]; /* a variable array of bytes, */
/* count in tag */
} L3_Pack;
struct _L4_Pack{ /* VENDOR DEFINED PACKET */
unsigned char Tag; /* large tag = 0x84 */
unsigned char Count0;
unsigned char Count1;
union _L4_Data{
unsigned char Data[1]; /* a variable array of bytes, */
/* count in tag */
struct _L4_PPCPack{ /* Pr*p L4 packet */
unsigned char Type; /* 00=non-IBM */
unsigned char PPCData[1]; /* a variable array of bytes, */
/* count in tag */
} L4_PPCPack;
} L4_Data;
} L4_Pack;
struct _L5_Pack{
unsigned char Tag; /* large tag = 0x85 */
unsigned char Count0; /* Count = 17 */
unsigned char Count1;
unsigned char Data[17];
} L5_Pack;
struct _L6_Pack{
unsigned char Tag; /* large tag = 0x86 */
unsigned char Count0; /* Count = 9 */
unsigned char Count1;
unsigned char Data[9];
} L6_Pack;
} PnP_TAG_PACKET;
#endif /* ASM */
#endif /* ndef _PNP_ */

View File

@@ -0,0 +1,106 @@
/*
* residual.c : function used to parse residual data.
*
* CopyRight (C) 1999 valette@crf.canon.fr
*
* This code is heavilly inspired by the public specification of STREAM V2
* that can be found at :
*
* The license and distribution terms for this file may be
* found in found in the file LICENSE in this distribution or at
* http://www.OARcorp.com/rtems/license.html.
*
* $Id$
*/
#include <bsp/residual.h>
#include <libcpu/io.h>
#include <libcpu/byteorder.h>
static int same_DevID(unsigned short vendor,
unsigned short Number,
char * str)
{
static unsigned const char hexdigit[]="0123456789ABCDEF";
if (strlen(str)!=7) return 0;
if ( ( ((vendor>>10)&0x1f)+'A'-1 == str[0]) &&
( ((vendor>>5)&0x1f)+'A'-1 == str[1]) &&
( (vendor&0x1f)+'A'-1 == str[2]) &&
(hexdigit[(Number>>12)&0x0f] == str[3]) &&
(hexdigit[(Number>>8)&0x0f] == str[4]) &&
(hexdigit[(Number>>4)&0x0f] == str[5]) &&
(hexdigit[Number&0x0f] == str[6]) ) return 1;
return 0;
}
PPC_DEVICE *residual_find_device(RESIDUAL *res,unsigned long BusMask,
unsigned char * DevID,
int BaseType,
int SubType,
int Interface,
int n)
{
int i;
if ( !res || !res->ResidualLength ) return NULL;
for (i=0; i<res->ActualNumDevices; i++) {
#define Dev res->Devices[i].DeviceId
if ( (Dev.BusId&BusMask) &&
(BaseType==-1 || Dev.BaseType==BaseType) &&
(SubType==-1 || Dev.SubType==SubType) &&
(Interface==-1 || Dev.Interface==Interface) &&
(DevID==NULL || same_DevID((Dev.DevId>>16)&0xffff,
Dev.DevId&0xffff, DevID)) &&
!(n--) ) return res->Devices+i;
#undef Dev
}
return 0;
}
PnP_TAG_PACKET *PnP_find_packet(unsigned char *p,
unsigned packet_tag,
int n)
{
unsigned mask, masked_tag, size;
if(!p) return 0;
if (tag_type(packet_tag)) mask=0xff; else mask=0xF8;
masked_tag = packet_tag&mask;
for(; *p != END_TAG; p+=size) {
if ((*p & mask) == masked_tag && !(n--))
return (PnP_TAG_PACKET *) p;
if (tag_type(*p))
size=ld_le16((unsigned short *)(p+1))+3;
else
size=tag_small_count(*p)+1;
}
return 0; /* not found */
}
PnP_TAG_PACKET *PnP_find_small_vendor_packet(unsigned char *p,
unsigned packet_type,
int n)
{
int next=0;
while (p) {
p = (unsigned char *) PnP_find_packet(p, 0x70, next);
if (p && p[1]==packet_type && !(n--))
return (PnP_TAG_PACKET *) p;
next = 1;
};
return 0; /* not found */
}
PnP_TAG_PACKET *PnP_find_large_vendor_packet(unsigned char *p,
unsigned packet_type,
int n)
{
int next=0;
while (p) {
p = (unsigned char *) PnP_find_packet(p, 0x84, next);
if (p && p[3]==packet_type && !(n--))
return (PnP_TAG_PACKET *) p;
next = 1;
};
return 0; /* not found */
}

View File

@@ -0,0 +1,346 @@
/* 7/18/95 */
/*----------------------------------------------------------------------------*/
/* Residual Data header definitions and prototypes */
/*----------------------------------------------------------------------------*/
/* Structure map for RESIDUAL on PowerPC Reference Platform */
/* residual.h - Residual data structure passed in r3. */
/* Load point passed in r4 to boot image. */
/* For enum's: if given in hex then they are bit significant, */
/* i.e. only one bit is on for each enum */
/* Reserved fields must be filled with zeros. */
/*
* $Id$
*/
#ifndef _RESIDUAL_
#define _RESIDUAL_
#ifndef ASM
#define MAX_CPUS 32 /* These should be set to the maximum */
#define MAX_MEMS 64 /* number possible for this system. */
#define MAX_DEVICES 256 /* Changing these will change the */
#define AVE_PNP_SIZE 32 /* structure, hence the version of */
#define MAX_MEM_SEGS 64 /* this header file. */
/*----------------------------------------------------------------------------*/
/* Public structures... */
/*----------------------------------------------------------------------------*/
#include <bsp/pnp.h>
typedef enum _L1CACHE_TYPE {
NoneCAC = 0,
SplitCAC = 1,
CombinedCAC = 2
} L1CACHE_TYPE;
typedef enum _TLB_TYPE {
NoneTLB = 0,
SplitTLB = 1,
CombinedTLB = 2
} TLB_TYPE;
typedef enum _FIRMWARE_SUPPORT {
Conventional = 0x01,
OpenFirmware = 0x02,
Diagnostics = 0x04,
LowDebug = 0x08,
Multiboot = 0x10,
LowClient = 0x20,
Hex41 = 0x40,
FAT = 0x80,
ISO9660 = 0x0100,
SCSI_InitiatorID_Override = 0x0200,
Tape_Boot = 0x0400,
FW_Boot_Path = 0x0800
} FIRMWARE_SUPPORT;
typedef enum _FIRMWARE_SUPPLIERS {
IBMFirmware = 0x00,
MotoFirmware = 0x01, /* 7/18/95 */
FirmWorks = 0x02, /* 10/5/95 */
Bull = 0x03, /* 04/03/96 */
} FIRMWARE_SUPPLIERS;
typedef enum _ENDIAN_SWITCH_METHODS {
UsePort92 = 0x01,
UsePCIConfigA8 = 0x02,
UseFF001030 = 0x03,
} ENDIAN_SWITCH_METHODS;
typedef enum _SPREAD_IO_METHODS {
UsePort850 = 0x00,
/*UsePCIConfigA8 = 0x02,*/
} SPREAD_IO_METHODS;
typedef struct _VPD {
/* Box dependent stuff */
unsigned char PrintableModel[32]; /* Null terminated string.
Must be of the form:
vvv,<20h>,<model designation>,<0x0>
where vvv is the vendor ID
e.g. IBM PPS MODEL 6015<0x0> */
unsigned char Serial[16]; /* 12/94:
Serial Number; must be of the form:
vvv<serial number> where vvv is the
vendor ID.
e.g. IBM60151234567<20h><20h> */
unsigned char Reserved[48];
unsigned long FirmwareSupplier; /* See FirmwareSuppliers enum */
unsigned long FirmwareSupports; /* See FirmwareSupport enum */
unsigned long NvramSize; /* Size of nvram in bytes */
unsigned long NumSIMMSlots;
unsigned short EndianSwitchMethod; /* See EndianSwitchMethods enum */
unsigned short SpreadIOMethod; /* See SpreadIOMethods enum */
unsigned long SmpIar;
unsigned long RAMErrLogOffset; /* Heap offset to error log */
unsigned long Reserved5;
unsigned long Reserved6;
unsigned long ProcessorHz; /* Processor clock frequency in Hertz */
unsigned long ProcessorBusHz; /* Processor bus clock frequency */
unsigned long Reserved7;
unsigned long TimeBaseDivisor; /* (Bus clocks per timebase tic)*1000 */
unsigned long WordWidth; /* Word width in bits */
unsigned long PageSize; /* Page size in bytes */
unsigned long CoherenceBlockSize; /* Unit of transfer in/out of cache
for which coherency is maintained;
normally <= CacheLineSize. */
unsigned long GranuleSize; /* Unit of lock allocation to avoid */
/* false sharing of locks. */
/* L1 Cache variables */
unsigned long CacheSize; /* L1 Cache size in KB. This is the */
/* total size of the L1, whether */
/* combined or split */
unsigned long CacheAttrib; /* L1CACHE_TYPE */
unsigned long CacheAssoc; /* L1 Cache associativity. Use this
for combined cache. If split, put
zeros here. */
unsigned long CacheLineSize; /* L1 Cache line size in bytes. Use
for combined cache. If split, put
zeros here. */
/* For split L1 Cache: (= combined if combined cache) */
unsigned long I_CacheSize;
unsigned long I_CacheAssoc;
unsigned long I_CacheLineSize;
unsigned long D_CacheSize;
unsigned long D_CacheAssoc;
unsigned long D_CacheLineSize;
/* Translation Lookaside Buffer variables */
unsigned long TLBSize; /* Total number of TLBs on the system */
unsigned long TLBAttrib; /* Combined I+D or split TLB */
unsigned long TLBAssoc; /* TLB Associativity. Use this for
combined TLB. If split, put zeros
here. */
/* For split TLB: (= combined if combined TLB) */
unsigned long I_TLBSize;
unsigned long I_TLBAssoc;
unsigned long D_TLBSize;
unsigned long D_TLBAssoc;
unsigned long ExtendedVPD; /* Offset to extended VPD area;
null if unused */
} VPD;
typedef enum _DEVICE_FLAGS {
Enabled = 0x4000, /* 1 - PCI device is enabled */
Integrated = 0x2000,
Failed = 0x1000, /* 1 - device failed POST code tests */
Static = 0x0800, /* 0 - dynamically configurable
1 - static */
Dock = 0x0400, /* 0 - not a docking station device
1 - is a docking station device */
Boot = 0x0200, /* 0 - device cannot be used for BOOT
1 - can be a BOOT device */
Configurable = 0x0100, /* 1 - device is configurable */
Disableable = 0x80, /* 1 - device can be disabled */
PowerManaged = 0x40, /* 0 - not managed; 1 - managed */
ReadOnly = 0x20, /* 1 - device is read only */
Removable = 0x10, /* 1 - device is removable */
ConsoleIn = 0x08,
ConsoleOut = 0x04,
Input = 0x02,
Output = 0x01
} DEVICE_FLAGS;
typedef enum _BUS_ID {
ISADEVICE = 0x01,
EISADEVICE = 0x02,
PCIDEVICE = 0x04,
PCMCIADEVICE = 0x08,
PNPISADEVICE = 0x10,
MCADEVICE = 0x20,
MXDEVICE = 0x40, /* Devices on mezzanine bus */
PROCESSORDEVICE = 0x80, /* Devices on processor bus */
VMEDEVICE = 0x100,
} BUS_ID;
typedef struct _DEVICE_ID {
unsigned long BusId; /* See BUS_ID enum above */
unsigned long DevId; /* Big Endian format */
unsigned long SerialNum; /* For multiple usage of a single
DevId */
unsigned long Flags; /* See DEVICE_FLAGS enum above */
unsigned char BaseType; /* See pnp.h for bit definitions */
unsigned char SubType; /* See pnp.h for bit definitions */
unsigned char Interface; /* See pnp.h for bit definitions */
unsigned char Spare;
} DEVICE_ID;
typedef union _BUS_ACCESS {
struct _PnPAccess{
unsigned char CSN;
unsigned char LogicalDevNumber;
unsigned short ReadDataPort;
} PnPAccess;
struct _ISAAccess{
unsigned char SlotNumber; /* ISA Slot Number generally not
available; 0 if unknown */
unsigned char LogicalDevNumber;
unsigned short ISAReserved;
} ISAAccess;
struct _MCAAccess{
unsigned char SlotNumber;
unsigned char LogicalDevNumber;
unsigned short MCAReserved;
} MCAAccess;
struct _PCMCIAAccess{
unsigned char SlotNumber;
unsigned char LogicalDevNumber;
unsigned short PCMCIAReserved;
} PCMCIAAccess;
struct _EISAAccess{
unsigned char SlotNumber;
unsigned char FunctionNumber;
unsigned short EISAReserved;
} EISAAccess;
struct _PCIAccess{
unsigned char BusNumber;
unsigned char DevFuncNumber;
unsigned short PCIReserved;
} PCIAccess;
struct _ProcBusAccess{
unsigned char BusNumber;
unsigned char BUID;
unsigned short ProcBusReserved;
} ProcBusAccess;
} BUS_ACCESS;
/* Per logical device information */
typedef struct _PPC_DEVICE {
DEVICE_ID DeviceId;
BUS_ACCESS BusAccess;
/* The following three are offsets into the DevicePnPHeap */
/* All are in PnP compressed format */
unsigned long AllocatedOffset; /* Allocated resource description */
unsigned long PossibleOffset; /* Possible resource description */
unsigned long CompatibleOffset; /* Compatible device identifiers */
} PPC_DEVICE;
typedef enum _CPU_STATE {
CPU_GOOD = 0, /* CPU is present, and active */
CPU_GOOD_FW = 1, /* CPU is present, and in firmware */
CPU_OFF = 2, /* CPU is present, but inactive */
CPU_FAILED = 3, /* CPU is present, but failed POST */
CPU_NOT_PRESENT = 255 /* CPU not present */
} CPU_STATE;
typedef struct _PPC_CPU {
unsigned long CpuType; /* Result of mfspr from Processor
Version Register (PVR).
PVR(0-15) = Version (e.g. 601)
PVR(16-31 = EC Level */
unsigned char CpuNumber; /* CPU Number for this processor */
unsigned char CpuState; /* CPU State, see CPU_STATE enum */
unsigned short Reserved;
} PPC_CPU;
typedef struct _PPC_MEM {
unsigned long SIMMSize; /* 0 - absent or bad
8M, 32M (in MB) */
} PPC_MEM;
typedef enum _MEM_USAGE {
Other = 0x8000,
ResumeBlock = 0x4000, /* for use by power management */
SystemROM = 0x2000, /* Flash memory (populated) */
UnPopSystemROM = 0x1000, /* Unpopulated part of SystemROM area */
IOMemory = 0x0800,
SystemIO = 0x0400,
SystemRegs = 0x0200,
PCIAddr = 0x0100,
PCIConfig = 0x80,
ISAAddr = 0x40,
Unpopulated = 0x20, /* Unpopulated part of System Memory */
Free = 0x10, /* Free part of System Memory */
BootImage = 0x08, /* BootImage part of System Memory */
FirmwareCode = 0x04, /* FirmwareCode part of System Memory */
FirmwareHeap = 0x02, /* FirmwareHeap part of System Memory */
FirmwareStack = 0x01 /* FirmwareStack part of System Memory*/
} MEM_USAGE;
typedef struct _MEM_MAP {
unsigned long Usage; /* See MEM_USAGE above */
unsigned long BasePage; /* Page number measured in 4KB pages */
unsigned long PageCount; /* Page count measured in 4KB pages */
} MEM_MAP;
typedef struct _RESIDUAL {
unsigned long ResidualLength; /* Length of Residual */
unsigned char Version; /* of this data structure */
unsigned char Revision; /* of this data structure */
unsigned short EC; /* of this data structure */
/* VPD */
VPD VitalProductData;
/* CPU */
unsigned short MaxNumCpus; /* Max CPUs in this system */
unsigned short ActualNumCpus; /* ActualNumCpus < MaxNumCpus means */
/* that there are unpopulated or */
/* otherwise unusable cpu locations */
PPC_CPU Cpus[MAX_CPUS];
/* Memory */
unsigned long TotalMemory; /* Total amount of memory installed */
unsigned long GoodMemory; /* Total amount of good memory */
unsigned long ActualNumMemSegs;
MEM_MAP Segs[MAX_MEM_SEGS];
unsigned long ActualNumMemories;
PPC_MEM Memories[MAX_MEMS];
/* Devices */
unsigned long ActualNumDevices;
PPC_DEVICE Devices[MAX_DEVICES];
unsigned char DevicePnPHeap[2*MAX_DEVICES*AVE_PNP_SIZE];
} RESIDUAL;
#ifndef NULL
#define NULL 0
#endif
extern RESIDUAL residualCopy;
extern void print_residual_device_info(void);
#ifndef __BOOT__
extern PPC_DEVICE *residual_find_device(RESIDUAL *res, unsigned long BusMask,
unsigned char * DevID, int BaseType,
int SubType, int Interface, int n);
#else
extern PPC_DEVICE *residual_find_device(unsigned long BusMask,
unsigned char * DevID, int BaseType,
int SubType, int Interface, int n);
#endif
extern PnP_TAG_PACKET *PnP_find_packet(unsigned char *p, unsigned packet_tag,
int n);
extern PnP_TAG_PACKET *PnP_find_small_vendor_packet(unsigned char *p,
unsigned packet_type,
int n);
extern PnP_TAG_PACKET *PnP_find_large_vendor_packet(unsigned char *p,
unsigned packet_type,
int n);
#endif /* ASM */
#endif /* ndef _RESIDUAL_ */

View File

@@ -0,0 +1,29 @@
#
# $Id$
#
@SET_MAKE@
srcdir = @srcdir@
top_srcdir = @top_srcdir@
top_builddir = ../../..
subdir = powerpc/mcp750/start
RTEMS_ROOT = @RTEMS_ROOT@
PROJECT_ROOT = @PROJECT_ROOT@
VPATH = @srcdir@
H_FILES =
SRCS = $(C_FILES) $(CC_FILES) $(H_FILES) $(S_FILES)
include $(RTEMS_ROOT)/make/custom/@RTEMS_BSP@.cfg
include $(RTEMS_ROOT)/make/leaf.cfg
INSTALL_CHANGE = @INSTALL_CHANGE@
all: ${ARCH} $(SRCS)
Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
cd $(top_builddir) \
&& CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status

View File

@@ -0,0 +1,131 @@
/*
* start.S : RTEMS entry point
*
* Copyright (C) 1999 Eric Valette. valette@crf.canon.fr
*
* The license and distribution terms for this file may be
* found in found in the file LICENSE in this distribution or at
* http://www.OARcorp.com/rtems/license.html.
*
* $Id$
*
*/
#include <libcpu/cpu.h>
#include <libcpu/io.h>
#include <rtems/score/targopts.h>
#include <rtems/score/cpu.h>
#include "asm.h"
#define SYNC \
sync; \
isync
#define KERNELBASE 0x0
#define MONITOR_ENTER \
mfmsr r10 ; \
ori r10,r10,MSR_IP ; \
mtmsr r10 ; \
li r10,0x63 ; \
sc
.text
.globl __rtems_entry_point
.type __rtems_entry_point,@function
__rtems_entry_point:
#ifdef DEBUG_EARLY_START
MONITOR_ENTER
#endif
/*
* PREP
* This is jumped to on prep systems right after the kernel is relocated
* to its proper place in memory by the boot loader. The expected layout
* of the regs is:
* r3: ptr to residual data
* r4: initrd_start or if no initrd then 0
* r5: initrd_end - unused if r4 is 0
* r6: Start of command line string
* r7: End of command line string
*
*/
mr r31,r3 /* save parameters */
mr r30,r4
mr r29,r5
mr r28,r6
mr r27,r7
/*
* Use the first pair of BAT registers to map the 1st 64MB
* of RAM to KERNELBASE.
*/
lis r11,KERNELBASE@h
ori r11,r11,0x7fe /* set up BAT registers for 604 */
li r8,2 /* R/W access */
mtspr DBAT0L,r8 /* N.B. 6xx (not 601) have valid */
mtspr DBAT0U,r11 /* bit in upper BAT register */
mtspr IBAT0L,r8
mtspr IBAT0U,r11
isync
/*
* we now have the 1st 64M of ram mapped with the bats.
*/
enter_C_code:
bl MMUon
/*
* stack = &__rtems_end + 4096
*/
addis r9,r0, __rtems_end+(4096-CPU_MINIMUM_STACK_FRAME_SIZE)@ha
addi r9,r9, __rtems_end+(4096-CPU_MINIMUM_STACK_FRAME_SIZE)@l
mr r1, r9
bl zero_bss
/*
* restore prep boot params
*/
mr r3,r31
mr r4,r30
mr r5,r29
mr r6,r28
mr r7,r27
bl save_boot_params
bl boot_card
bl _return_to_ppcbug
.globl MMUon
.type MMUon,@function
MMUon:
mfmsr r0
ori r0,r0, MSR_IP | MSR_RI | MSR_IR | MSR_DR | MSR_EE | MSR_FE0 | MSR_FE1
xori r0, r0, MSR_EE | MSR_IP | MSR_FP
mflr r11
mtsrr0 r11
mtsrr1 r0
SYNC
rfi
.globl MMUoff
.type MMUoff,@function
MMUoff:
mfmsr r0
ori r0,r0,MSR_IR| MSR_DR | MSR_IP
mflr r11
xori r0,r0,MSR_IR|MSR_DR
mtsrr0 r11
mtsrr1 r0
SYNC
rfi
.globl _return_to_ppcbug
.type _return_to_ppcbug,@function
_return_to_ppcbug:
mflr r30
bl MMUoff
MONITOR_ENTER
bl MMUon
mtctr r30
bctr

Some files were not shown because too many files have changed in this diff Show More