forked from Imagelibrary/rtems
This is a large patch from Eric Valette <valette@crf.canon.fr> that was
described in the message following this paragraph. This patch also includes a mcp750 BSP. From valette@crf.canon.fr Mon Jun 14 10:03:08 1999 Date: Tue, 18 May 1999 01:30:14 +0200 (CEST) From: VALETTE Eric <valette@crf.canon.fr> To: joel@oarcorp.com Cc: raguet@crf.canon.fr, rtems-snapshots@oarcorp.com, valette@crf.canon.fr Subject: Questions/Suggestion regarding RTEMS PowerPC code (long) Dear knowledgeable RTEMS powerpc users, As some of you may know, I'm currently finalizing a port of RTEMS on a MCP750 Motorola board. I have done most of it but have some questions to ask before submitting the port. In order to understand some of the changes I have made or would like to make, maybe it is worth describing the MCP750 Motorola board. the MCP750 is a COMPACT PCI powerpc board with : 1) a MPC750 233 MHz processor, 2) a raven bus bridge/PCI controller that implement an OPENPIC compliant interrupt controller, 3) a VIA 82C586 PCI/ISA bridge that offers a PC compliant IO for keyboard, serial line, IDE, and the well known PC 8259 cascaded PIC interrupt architecture model, 4) a DEC 21140 Ethernet controller, 5) the PPCBUG Motorola firmware in flash, 6) A DEC PCI bridge, This architecture is common to most Motorola 60x/7xx board except that : 1) on VME board, the DEC PCI bridge is replaced by a VME chipset, 2) the VIA 82C586 PCI/ISA bridge is replaced by another bridge that is almost fully compatible with the via bridge... So the port should be a rather close basis for many 60x/7xx motorola board... On this board, I already have ported Linux 2.2.3 and use it both as a development and target board. Now the questions/suggestions I have : 1) EXCEPTION CODE ------------------- As far as I know exceptions on PPC are handled like interrupts. I dislike this very much as : a) Except for the decrementer exception (and maybe some other on mpc8xx), exceptions are not recoverable and the handler just need to print the full context and go to the firmware or debugger... b) The interrupt switch is only necessary for the decrementer and external interrupt (at least on 6xx,7xx). c) The full context for exception is never saved and thus cannot be used by debugger... I do understand the most important for interrupts low level code is to save the minimal context enabling to call C code for performance reasons. On non recoverable exception on the other hand, the most important is to save the maximum information concerning proc status in order to analyze the reason of the fault. At least we will need this in order to implement the port of RGDB on PPC ==> I wrote an API for connecting raw exceptions (and thus raw interrupts) for mpc750. It should be valid for most powerpc processors... I hope to find a way to make this coexist with actual code layout. The code is actually located in lib/libcpu/powerpc/mpc750 and is thus optional (provided I write my own version of exec/score/cpu/powerpc/cpu.c ...) See remark about files/directory layout organization in 4) 2) Current Implementation of ISR low level code ----------------------------------------------- I do not understand why the MSR EE flags is cleared again in exec/score/cpu/powerpc/irq_stubs.S #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 Reading the doc, when a decrementer interrupt or an external interrupt is active, the MSR EE flag is already cleared. BTW if exception/interrupt could occur, it would trash SRR0 and SRR1. In fact the code may be useful to set MSR[RI] that re-enables exception processing. BTW I will need to set other value in MSR to handle interrupts : a) I want the MSR[IR] and MSR[DR] to be set for performance reasons and also because I need DBAT support to have access to PCI memory space as the interrupt controller is in the PCI space. Reading the code, I see others have the same kind of request : /* SCE 980217 * * We need address translation ON when we call our ISR routine mtmsr r5 */ This is just another prof that even the lowest level IRQ code is fundamentally board dependent and not simply processor dependent especially when the processor use external interrupt controller because it has a single interrupt request line... Note that if you look at the PPC code high level interrupt handling code, as the "set_vector" routine that really connects the interrupt is in the BSP/startup/genpvec.c, the fact that IRQ handling is BSP specific is DE-FACTO acknowledged. I know I have already expressed this and understand that this would require some heavy change in the code but believe me you will reach a point where you will not be able to find a compatible while optimum implementation for low level interrupt handling code...) In my case this is already true... So please consider removing low level IRQ handling from exec/score/cpu/* and only let there exception handling code... Exceptions are usually only processor dependent and do not depend on external hardware mechanism to be masked or acknowledged or re-enabled (there are probably exception but ...) I have already done this for pc386 bsp but need to make it again. This time I will even propose an API. 3) R2/R13 manipulation for EABI implementation ---------------------------------------------- I do not understand the handling of r2 and r13 in the EABI case. The specification for r2 says pointer to sdata2, sbss2 section => constant. However I do not see -ffixed-r2 passed to any compilation system in make/custom/* (for info linux does this on PPC). So either this is a default compiler option when choosing powerpc-rtems and thus we do not need to do anything with this register as all the code is compiled with this compiler and linked together OR this register may be used by rtems code and then we do not need any special initialization or handling. The specification for r13 says pointer to the small data area. r13 argumentation is the same except that as far as I know the usage of the small data area requires specific compiler support so that access to variables is compiled via loading the LSB in a register and then using r13 to get full address... It is like a small memory model and it was present in IBM C compilers. => I propose to suppress any specific code for r2 and r13 in the EABI case. 4) Code layout organization (yes again :-)) ------------------------------------------- I think there are a number of design flaws in the way the code is for ppc organized and I will try to point them out. I have been beaten by this again on this new port, and was beaten last year while modifying code for pc386. a) exec/score/cpu/* vs lib/libcpu/cpu/*. I think that too many things are put in exec/score/cpu that have nothing to do with RTEMS internals but are rather related to CPU feature. This include at least : a) registers access routine (e.g GET_MSR_Value), b) interrupt masking/unmasking routines, c) cache_mngt_routine, d) mmu_mngt_routine, e) Routines to connect the raw_exception, raw_interrupt handler, b) lib/libcpu/cpu/powerpc/* With a processor family as exuberant as the powerpc family, and their well known subtle differences (604 vs 750) or unfortunately majors (8xx vs 60x) the directory structure is fine (except maybe the names that are not homogeneous) powerpc ppc421 mpc821 ... I only needed to add mpc750. But the fact that libcpu.a was not produced was a pain and the fact that this organization may duplicates code is also problematic. So, except if the support of automake provides a better solution I would like to propose something like this : powerpc mpc421 mpc821 ... mpc750 shared wrapup with the following rules : a) "shared" would act as a source container for sources that may be shared among processors. Needed files would be compiled inside the processor specific directory using the vpath Makefile mechanism. "shared" may also contain compilation code for routine that are really shared and not worth to inline... (did not found many things so far as registers access routine ARE WORTH INLINING)... In the case something is compiled there, it should create libcpushared.a b) layout under processor specific directory is free provided that 1)the result of the compilation process exports : libcpu/powerpc/"PROC"/*.h in $(PROJECT_INCLUDE)/libcpu 2) each processor specific directory creates a library called libcpuspecific.a Note that this organization enables to have a file that is nearly the same than in shared but that must differ because of processor differences... c) "wrapup" should create libcpu.a using libcpushared.a libcpuspecific.a and export it $(PROJECT_INCLUDE)/libcpu The only thing I have no ideal solution is the way to put shared definitions in "shared" and only processor specific definition in "proc". To give a concrete example, most MSR bit definition are shared among PPC processors and only some differs. if we create a single msr.h in shared it will have ifdef. If in msr.h we include libcpu/msr_c.h we will need to have it in each prowerpc specific directory (even empty). Opinions are welcomed ... Note that a similar mechanism exist in libbsp/i386 that also contains a shared directory that is used by several bsp like pc386 and i386ex and a similar wrapup mechanism... NB: I have done this for mpc750 and other processors could just use similar Makefiles... c) The exec/score/cpu/powerpc directory layout. I think the directory layout should be the same than the libcpu/powerpc. As it is not, there are a lot of ifdefs inside the code... And of course low level interrupt handling code should be removed... Besides that I do not understand why 1) things are compiled in the wrap directory, 2) some includes are moved to rtems/score, I think the "preinstall" mechanism enables to put everything in the current directory (or better in a per processor directory), 5) Interrupt handling API ------------------------- Again :-). But I think that using all the features the PIC offers is a MUST for RT system. I already explained in the prologue of this (long and probably boring) mail that the MCP750 boards offers an OPENPIC compliant architecture and that the VIA 82586 PCI/ISA bridge offers a PC compatible IO and PIC mapping. Here is a logical view of the RAVEN/VIA 82586 interrupt mapping : --------- 0 ------ | OPEN | <-----|8259| | PIC | | | 2 ------ |(RAVEN)| | | <-----|8259| | | | | | | 11 | | | | | | <---- | | | | | | | | | | | | --------- ------ | | ^ ------ | VIA PCI/ISA bridge | x -------- PCI interrupts OPENPIC offers interrupt priorities among PCI interrupts and interrupt selective masking. The 8259 offers the same kind of feature. With actual powerpc interrupt code : 1) there is no way to specify priorities among interrupts handler. This is REALLY a bad thing. For me it is as importnat as having priorities for threads... 2) for my implementation, each ISR should contain the code that acknowledge the RAVEN and 8259 cascade, modify interrupt mask on both chips, and reenable interrupt at processor level, ..., restore then on interrupt return,.... This code is actually similar to code located in some genpvec.c powerpc files, 3) I must update _ISR_Nesting_level because irq.inl use it... 4) the libchip code connects the ISR via set_vector but the libchip handler code does not contain any code to manipulate external interrupt controller hardware in order to acknoledge the interrupt or re-enable them (except for the target hardware of course) So this code is broken unless set_vector adds an additionnal prologue/epilogue before calling/returning from in order to acknoledge/mask the raven and the 8259 PICS... => Anyway already EACH BSP MUST REWRITE PART OF INTERRUPT HANDLING CODE TO CORRECTLY IMPLEMENT SET_VECTOR. I would rather offer an API similar to the one provided in libbsp/i386/shared/irq/irq.h so that : 1) Once the driver supplied methods is called the only things the ISR has to do is to worry about the external hardware that triggered the interrupt. Everything on openpic/VIA/processor would have been done by the low levels (same things as set-vector) 2) The caller will need to supply the on/off/isOn routine that are fundamental to correctly implements debuggers/performance monitoring is a portable way 3) A globally configurable interrupt priorities mechanism... I have nothing against providing a compatible set_vector just to make libchip happy but as I have already explained in other mails (months ago), I really think that the ISR connection should be handled by the BSP and that no code containing irq connection should exist the rtems generic layers... Thus I really dislike libchip on this aspect because in a long term it will force to adopt the less reach API for interrupt handling that exists (set_vector). Additional note : I think the _ISR_Is_in_progress() inline routine should be : 1) Put in a processor specific section, 2) Should not rely on a global variable, As : a) on symmetric MP, there is one interrupt level per CPU, b) On processor that have an ISP (e,g 68040), this variable is useless (MSR bit testing could be used) c) On PPC, instead of using the address of the variable via __CPU_IRQ_info.Nest_level a dedicated SPR could be used. NOTE: most of this is also true for _Thread_Dispatch_disable_level END NOTE -------- Please do not take what I said in the mail as a criticism for anyone who submitted ppc code. Any code present helped me a lot understanding PPC behavior. I just wanted by this mail to : 1) try to better understand the actual code, 2) propose concrete ways of enhancing current code by providing an alternative implementation for MCP750. I will make my best effort to try to brake nothing but this is actually hard due to the file layout organisation. 3) make understandable some changes I will probably make if joel let me do them :-) Any comments/objections are welcomed as usual. -- __ / ` Eric Valette /-- __ o _. Canon CRF (___, / (_(_(__ Rue de la touche lambert 35517 Cesson-Sevigne Cedex FRANCE Tel: +33 (0)2 99 87 68 91 Fax: +33 (0)2 99 84 11 30 E-mail: valette@crf.canon.fr
This commit is contained in:
@@ -1,6 +1,9 @@
|
||||
#
|
||||
# $Id$
|
||||
#
|
||||
#
|
||||
# $Id$
|
||||
#
|
||||
|
||||
@SET_MAKE@
|
||||
srcdir = @srcdir@
|
||||
@@ -18,8 +21,13 @@ VPATH = @srcdir@
|
||||
include $(RTEMS_ROOT)/make/custom/${RTEMS_BSP}.cfg
|
||||
include $(RTEMS_ROOT)/make/directory.cfg
|
||||
|
||||
SUB_DIRS = rtems wrap
|
||||
SHARED_LIB=shared
|
||||
|
||||
ifeq ($(RTEMS_CPU_MODEL),mpc750)
|
||||
CPUDIR=mpc750
|
||||
else
|
||||
CPUDIR=other_cpu
|
||||
endif
|
||||
|
||||
SUB_DIRS=$(CPUDIR) $(SHARED_LIB)
|
||||
|
||||
Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
|
||||
cd $(top_builddir) \
|
||||
&& CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status
|
||||
|
||||
275
c/src/exec/score/cpu/powerpc/asm.h
Normal file
275
c/src/exec/score/cpu/powerpc/asm.h
Normal file
@@ -0,0 +1,275 @@
|
||||
/* asm.h
|
||||
*
|
||||
* This include file attempts to address the problems
|
||||
* caused by incompatible flavors of assemblers and
|
||||
* toolsets. It primarily addresses variations in the
|
||||
* use of leading underscores on symbols and the requirement
|
||||
* that register names be preceded by a %.
|
||||
*
|
||||
*
|
||||
* NOTE: The spacing in the use of these macros
|
||||
* is critical to them working as advertised.
|
||||
*
|
||||
* COPYRIGHT:
|
||||
*
|
||||
* This file is based on similar code found in newlib available
|
||||
* from ftp.cygnus.com. The file which was used had no copyright
|
||||
* notice. This file is freely distributable as long as the source
|
||||
* of the file is noted. This file is:
|
||||
*
|
||||
* COPYRIGHT (c) 1995.
|
||||
* i-cubed ltd.
|
||||
*
|
||||
* COPYRIGHT (c) 1994.
|
||||
* On-Line Applications Research Corporation (OAR).
|
||||
*
|
||||
* $Id$
|
||||
*/
|
||||
|
||||
#ifndef __PPC_ASM_h
|
||||
#define __PPC_ASM_h
|
||||
|
||||
/*
|
||||
* Indicate we are in an assembly file and get the basic CPU definitions.
|
||||
*/
|
||||
|
||||
#ifndef ASM
|
||||
#define ASM
|
||||
#endif
|
||||
#include <rtems/score/targopts.h>
|
||||
#include <rtems/score/ppc.h>
|
||||
|
||||
/*
|
||||
* Recent versions of GNU cpp define variables which indicate the
|
||||
* need for underscores and percents. If not using GNU cpp or
|
||||
* the version does not support this, then you will obviously
|
||||
* have to define these as appropriate.
|
||||
*/
|
||||
|
||||
#ifndef __USER_LABEL_PREFIX__
|
||||
#define __USER_LABEL_PREFIX__
|
||||
#endif
|
||||
|
||||
#ifndef __REGISTER_PREFIX__
|
||||
#define __REGISTER_PREFIX__
|
||||
#endif
|
||||
|
||||
#ifndef __FLOAT_REGISTER_PREFIX__
|
||||
#define __FLOAT_REGISTER_PREFIX__ __REGISTER_PREFIX__
|
||||
#endif
|
||||
|
||||
#if (PPC_ABI == PPC_ABI_POWEROPEN)
|
||||
#ifndef __PROC_LABEL_PREFIX__
|
||||
#define __PROC_LABEL_PREFIX__ .
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef __PROC_LABEL_PREFIX__
|
||||
#define __PROC_LABEL_PREFIX__ __USER_LABEL_PREFIX__
|
||||
#endif
|
||||
|
||||
/* ANSI concatenation macros. */
|
||||
|
||||
#define CONCAT1(a, b) CONCAT2(a, b)
|
||||
#define CONCAT2(a, b) a ## b
|
||||
|
||||
/* Use the right prefix for global labels. */
|
||||
|
||||
#define SYM(x) CONCAT1 (__USER_LABEL_PREFIX__, x)
|
||||
|
||||
/* Use the right prefix for procedure labels. */
|
||||
|
||||
#define PROC(x) CONCAT1 (__PROC_LABEL_PREFIX__, x)
|
||||
|
||||
/* Use the right prefix for registers. */
|
||||
|
||||
#define REG(x) CONCAT1 (__REGISTER_PREFIX__, x)
|
||||
|
||||
/* Use the right prefix for floating point registers. */
|
||||
|
||||
#define FREG(x) CONCAT1 (__FLOAT_REGISTER_PREFIX__, x)
|
||||
|
||||
/*
|
||||
* define macros for all of the registers on this CPU
|
||||
*
|
||||
* EXAMPLE: #define d0 REG (d0)
|
||||
*/
|
||||
#define r0 REG(0)
|
||||
#define r1 REG(1)
|
||||
#define r2 REG(2)
|
||||
#define r3 REG(3)
|
||||
#define r4 REG(4)
|
||||
#define r5 REG(5)
|
||||
#define r6 REG(6)
|
||||
#define r7 REG(7)
|
||||
#define r8 REG(8)
|
||||
#define r9 REG(9)
|
||||
#define r10 REG(10)
|
||||
#define r11 REG(11)
|
||||
#define r12 REG(12)
|
||||
#define r13 REG(13)
|
||||
#define r14 REG(14)
|
||||
#define r15 REG(15)
|
||||
#define r16 REG(16)
|
||||
#define r17 REG(17)
|
||||
#define r18 REG(18)
|
||||
#define r19 REG(19)
|
||||
#define r20 REG(20)
|
||||
#define r21 REG(21)
|
||||
#define r22 REG(22)
|
||||
#define r23 REG(23)
|
||||
#define r24 REG(24)
|
||||
#define r25 REG(25)
|
||||
#define r26 REG(26)
|
||||
#define r27 REG(27)
|
||||
#define r28 REG(28)
|
||||
#define r29 REG(29)
|
||||
#define r30 REG(30)
|
||||
#define r31 REG(31)
|
||||
#define f0 FREG(0)
|
||||
#define f1 FREG(1)
|
||||
#define f2 FREG(2)
|
||||
#define f3 FREG(3)
|
||||
#define f4 FREG(4)
|
||||
#define f5 FREG(5)
|
||||
#define f6 FREG(6)
|
||||
#define f7 FREG(7)
|
||||
#define f8 FREG(8)
|
||||
#define f9 FREG(9)
|
||||
#define f10 FREG(10)
|
||||
#define f11 FREG(11)
|
||||
#define f12 FREG(12)
|
||||
#define f13 FREG(13)
|
||||
#define f14 FREG(14)
|
||||
#define f15 FREG(15)
|
||||
#define f16 FREG(16)
|
||||
#define f17 FREG(17)
|
||||
#define f18 FREG(18)
|
||||
#define f19 FREG(19)
|
||||
#define f20 FREG(20)
|
||||
#define f21 FREG(21)
|
||||
#define f22 FREG(22)
|
||||
#define f23 FREG(23)
|
||||
#define f24 FREG(24)
|
||||
#define f25 FREG(25)
|
||||
#define f26 FREG(26)
|
||||
#define f27 FREG(27)
|
||||
#define f28 FREG(28)
|
||||
#define f29 FREG(29)
|
||||
#define f30 FREG(30)
|
||||
#define f31 FREG(31)
|
||||
|
||||
/*
|
||||
* Some special purpose registers (SPRs).
|
||||
*/
|
||||
#define srr0 0x01a
|
||||
#define srr1 0x01b
|
||||
#define srr2 0x3de /* IBM 400 series only */
|
||||
#define srr3 0x3df /* IBM 400 series only */
|
||||
#define sprg0 0x110
|
||||
#define sprg1 0x111
|
||||
#define sprg2 0x112
|
||||
#define sprg3 0x113
|
||||
|
||||
|
||||
/* the following SPR/DCR registers exist only in IBM 400 series */
|
||||
#define dear 0x3d5
|
||||
#define evpr 0x3d6 /* SPR: exception vector prefix register */
|
||||
#define iccr 0x3fb /* SPR: instruction cache control reg. */
|
||||
#define dccr 0x3fa /* SPR: data cache control reg. */
|
||||
|
||||
#define exisr 0x040 /* DCR: external interrupt status register */
|
||||
#define exier 0x042 /* DCR: external interrupt enable register */
|
||||
#define br0 0x080 /* DCR: memory bank register 0 */
|
||||
#define br1 0x081 /* DCR: memory bank register 1 */
|
||||
#define br2 0x082 /* DCR: memory bank register 2 */
|
||||
#define br3 0x083 /* DCR: memory bank register 3 */
|
||||
#define br4 0x084 /* DCR: memory bank register 4 */
|
||||
#define br5 0x085 /* DCR: memory bank register 5 */
|
||||
#define br6 0x086 /* DCR: memory bank register 6 */
|
||||
#define br7 0x087 /* DCR: memory bank register 7 */
|
||||
/* end of IBM400 series register definitions */
|
||||
|
||||
/* The following registers are for the MPC8x0 */
|
||||
#define der 0x095 /* Debug Enable Register */
|
||||
/* end of MPC8x0 registers */
|
||||
|
||||
/*
|
||||
* Following must be tailor for a particular flavor of the C compiler.
|
||||
* They may need to put underscores in front of the symbols.
|
||||
*/
|
||||
|
||||
#define PUBLIC_VAR(sym) .globl SYM (sym)
|
||||
#define EXTERN_VAR(sym) .extern SYM (sym)
|
||||
#define PUBLIC_PROC(sym) .globl PROC (sym)
|
||||
#define EXTERN_PROC(sym) .extern PROC (sym)
|
||||
|
||||
/* Other potentially assembler specific operations */
|
||||
#if PPC_ASM == PPC_ASM_ELF
|
||||
#define ALIGN(n,p) .align p
|
||||
#define DESCRIPTOR(x) \
|
||||
.section .descriptors,"aw"; \
|
||||
PUBLIC_VAR (x); \
|
||||
SYM (x):; \
|
||||
.long PROC (x); \
|
||||
.long s.got; \
|
||||
.long 0
|
||||
|
||||
#define EXT_SYM_REF(x) .long x
|
||||
#define EXT_PROC_REF(x) .long x
|
||||
|
||||
/*
|
||||
* Define macros to handle section beginning and ends.
|
||||
*/
|
||||
|
||||
#define BEGIN_CODE_DCL .text
|
||||
#define END_CODE_DCL
|
||||
#define BEGIN_DATA_DCL .data
|
||||
#define END_DATA_DCL
|
||||
#define BEGIN_CODE .text
|
||||
#define END_CODE
|
||||
#define BEGIN_DATA .data
|
||||
#define END_DATA
|
||||
#define BEGIN_BSS .bss
|
||||
#define END_BSS
|
||||
#define END
|
||||
|
||||
#elif PPC_ASM == PPC_ASM_XCOFF
|
||||
#define ALIGN(n,p) .align p
|
||||
#define DESCRIPTOR(x) \
|
||||
.csect x[DS]; \
|
||||
.globl x[DS]; \
|
||||
.long PROC (x)[PR]; \
|
||||
.long TOC[tc0]
|
||||
|
||||
#define EXT_SYM_REF(x) .long x[RW]
|
||||
#define EXT_PROC_REF(x) .long x[DS]
|
||||
|
||||
/*
|
||||
* Define macros to handle section beginning and ends.
|
||||
*/
|
||||
|
||||
#define BEGIN_CODE_DCL .csect .text[PR]
|
||||
#define END_CODE_DCL
|
||||
#define BEGIN_DATA_DCL .csect .data[RW]
|
||||
#define END_DATA_DCL
|
||||
#define BEGIN_CODE .csect .text[PR]
|
||||
#define END_CODE
|
||||
#define BEGIN_DATA .csect .data[RW]
|
||||
#define END_DATA
|
||||
#define BEGIN_BSS .bss
|
||||
#define END_BSS
|
||||
#define END
|
||||
|
||||
#else
|
||||
#error "PPC_ASM_TYPE is not properly defined"
|
||||
#endif
|
||||
#ifndef PPC_ASM
|
||||
#error "PPC_ASM_TYPE is not properly defined"
|
||||
#endif
|
||||
|
||||
|
||||
#endif
|
||||
/* end of include file */
|
||||
|
||||
|
||||
83
c/src/exec/score/cpu/powerpc/mpc750/Makefile.in
Normal file
83
c/src/exec/score/cpu/powerpc/mpc750/Makefile.in
Normal file
@@ -0,0 +1,83 @@
|
||||
#
|
||||
# $Id$
|
||||
#
|
||||
|
||||
@SET_MAKE@
|
||||
srcdir = @srcdir@
|
||||
top_srcdir = @top_srcdir@
|
||||
top_builddir = ../../../../../../..
|
||||
subdir = c/src/exec/score/cpu/powerpc/wrap
|
||||
|
||||
INSTALL = @INSTALL@
|
||||
|
||||
RTEMS_ROOT = $(top_srcdir)/@RTEMS_TOPdir@
|
||||
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
|
||||
|
||||
#
|
||||
# (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 444 ${RTEMS_SCORE_H_FILES} ${I_FILES} $(PROJECT_INCLUDE)/rtems/score
|
||||
$(INSTALL_CHANGE) -m 444 ${ROOT_H_FILES} $(PROJECT_INCLUDE)
|
||||
|
||||
Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
|
||||
cd $(top_builddir) \
|
||||
&& CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status
|
||||
9
c/src/exec/score/cpu/powerpc/mpc750/c_isr.inl
Normal file
9
c/src/exec/score/cpu/powerpc/mpc750/c_isr.inl
Normal 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;
|
||||
}
|
||||
118
c/src/exec/score/cpu/powerpc/mpc750/cpu.c
Normal file
118
c/src/exec/score/cpu/powerpc/mpc750/cpu.c
Normal file
@@ -0,0 +1,118 @@
|
||||
/*
|
||||
* 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
|
||||
*/
|
||||
|
||||
#define CPU_MINIMUM_STACK_FRAME_SIZE 8
|
||||
|
||||
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 )
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
* On-Line Applications Research Corporation (OAR).
|
||||
* Copyright assigned to U.S. Government, 1994.
|
||||
*
|
||||
* The license and distribution terms for this file may in
|
||||
* 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.
|
||||
*
|
||||
@@ -39,9 +39,9 @@ extern "C" {
|
||||
#endif
|
||||
|
||||
#include <rtems/score/ppc.h> /* pick up machine definitions */
|
||||
#ifndef ASM
|
||||
struct CPU_Interrupt_frame;
|
||||
#include <libcpu/cpu.h>
|
||||
|
||||
#ifndef ASM
|
||||
#include <rtems/score/ppctypes.h>
|
||||
#endif
|
||||
|
||||
@@ -110,7 +110,7 @@ struct CPU_Interrupt_frame;
|
||||
* procedure on that CPU.
|
||||
*/
|
||||
|
||||
#define CPU_HAS_SOFTWARE_INTERRUPT_STACK FALSE
|
||||
#define CPU_HAS_SOFTWARE_INTERRUPT_STACK TRUE
|
||||
|
||||
/*
|
||||
* Does this CPU have hardware support for a dedicated interrupt stack?
|
||||
@@ -127,12 +127,7 @@ struct CPU_Interrupt_frame;
|
||||
* procedure on that CPU.
|
||||
*/
|
||||
|
||||
/*
|
||||
* ACB: This is a lie, but it gets us a handle on a call to set up
|
||||
* a variable derived from the top of the interrupt stack.
|
||||
*/
|
||||
|
||||
#define CPU_HAS_HARDWARE_INTERRUPT_STACK TRUE
|
||||
#define CPU_HAS_HARDWARE_INTERRUPT_STACK FALSE
|
||||
|
||||
/*
|
||||
* Does RTEMS allocate a dedicated interrupt stack in the Interrupt Manager?
|
||||
@@ -144,7 +139,7 @@ struct CPU_Interrupt_frame;
|
||||
* or CPU_INSTALL_HARDWARE_INTERRUPT_STACK is TRUE.
|
||||
*/
|
||||
|
||||
#define CPU_ALLOCATE_INTERRUPT_STACK TRUE
|
||||
#define CPU_ALLOCATE_INTERRUPT_STACK FALSE
|
||||
|
||||
/*
|
||||
* Does the RTEMS invoke the user's ISR with the vector number and
|
||||
@@ -152,7 +147,7 @@ struct CPU_Interrupt_frame;
|
||||
* number (0)?
|
||||
*/
|
||||
|
||||
#define CPU_ISR_PASSES_FRAME_POINTER 1
|
||||
#define CPU_ISR_PASSES_FRAME_POINTER 0
|
||||
|
||||
/*
|
||||
* Does the CPU have hardware floating point?
|
||||
@@ -304,31 +299,6 @@ struct CPU_Interrupt_frame;
|
||||
#define CPU_BIG_ENDIAN TRUE
|
||||
#define CPU_LITTLE_ENDIAN FALSE
|
||||
|
||||
/*
|
||||
* The following defines the number of bits actually used in the
|
||||
* interrupt field of the task mode. How those bits map to the
|
||||
* CPU interrupt levels is defined by the routine _CPU_ISR_Set_level().
|
||||
*
|
||||
* The interrupt level is bit mapped for the PowerPC family. The
|
||||
* bits are set to 0 to indicate that a particular exception source
|
||||
* enabled and 1 if it is disabled. This keeps with RTEMS convention
|
||||
* that interrupt level 0 means all sources are enabled.
|
||||
*
|
||||
* The bits are assigned to correspond to enable bits in the MSR.
|
||||
*/
|
||||
|
||||
#define PPC_INTERRUPT_LEVEL_ME 0x01
|
||||
#define PPC_INTERRUPT_LEVEL_EE 0x02
|
||||
#define PPC_INTERRUPT_LEVEL_CE 0x04
|
||||
|
||||
/* XXX should these be maskable? */
|
||||
#if 0
|
||||
#define PPC_INTERRUPT_LEVEL_DE 0x08
|
||||
#define PPC_INTERRUPT_LEVEL_BE 0x10
|
||||
#define PPC_INTERRUPT_LEVEL_SE 0x20
|
||||
#endif
|
||||
|
||||
#define CPU_MODES_INTERRUPT_MASK 0x00000007
|
||||
|
||||
/*
|
||||
* Processor defined structures
|
||||
@@ -419,11 +389,7 @@ typedef struct {
|
||||
|
||||
typedef struct CPU_Interrupt_frame {
|
||||
unsigned32 stacklink; /* Ensure this is a real frame (also reg1 save) */
|
||||
#if (PPC_ABI == PPC_ABI_POWEROPEN || PPC_ABI == PPC_ABI_GCC27)
|
||||
unsigned32 dummy[13]; /* Used by callees: PowerOpen ABI */
|
||||
#else
|
||||
unsigned32 dummy[1]; /* Used by callees: SVR4/EABI */
|
||||
#endif
|
||||
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 */
|
||||
@@ -451,7 +417,6 @@ typedef struct CPU_Interrupt_frame {
|
||||
unsigned32 pad[3];
|
||||
} CPU_Interrupt_frame;
|
||||
|
||||
|
||||
/*
|
||||
* The following table contains the information required to configure
|
||||
* the PowerPC processor specific parameters.
|
||||
@@ -471,41 +436,10 @@ typedef struct {
|
||||
/* end of fields required on all CPUs */
|
||||
|
||||
unsigned32 clicks_per_usec; /* Timer clicks per microsecond */
|
||||
void (*spurious_handler)(unsigned32 vector, CPU_Interrupt_frame *);
|
||||
boolean exceptions_in_RAM; /* TRUE if in RAM */
|
||||
|
||||
#if (defined(ppc403) || defined(mpc860) || defined(mpc821))
|
||||
unsigned32 serial_per_sec; /* Serial clocks per second */
|
||||
boolean serial_external_clock;
|
||||
boolean serial_xon_xoff;
|
||||
boolean serial_cts_rts;
|
||||
unsigned32 serial_rate;
|
||||
unsigned32 timer_average_overhead; /* Average overhead of timer in ticks */
|
||||
unsigned32 timer_least_valid; /* Least valid number from timer */
|
||||
boolean timer_internal_clock; /* TRUE, when timer runs with CPU clk */
|
||||
#endif
|
||||
|
||||
#if (defined(mpc860) || defined(mpc821))
|
||||
unsigned32 clock_speed; /* Speed of CPU in Hz */
|
||||
#endif
|
||||
} rtems_cpu_table;
|
||||
|
||||
/*
|
||||
* The following type defines an entry in the PPC's trap table.
|
||||
*
|
||||
* NOTE: The instructions chosen are RTEMS dependent although one is
|
||||
* obligated to use two of the four instructions to perform a
|
||||
* long jump. The other instructions load one register with the
|
||||
* trap type (a.k.a. vector) and another with the psr.
|
||||
*/
|
||||
|
||||
typedef struct {
|
||||
unsigned32 stwu_r1; /* stwu %r1, -(??+IP_END)(%1)*/
|
||||
unsigned32 stw_r0; /* stw %r0, IP_0(%r1) */
|
||||
unsigned32 li_r0_IRQ; /* li %r0, _IRQ */
|
||||
unsigned32 b_Handler; /* b PROC (_ISR_Handler) */
|
||||
} CPU_Trap_table_entry;
|
||||
|
||||
/*
|
||||
* 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
|
||||
@@ -531,6 +465,14 @@ typedef struct {
|
||||
SCORE_EXTERN void *_CPU_Interrupt_stack_low;
|
||||
SCORE_EXTERN void *_CPU_Interrupt_stack_high;
|
||||
|
||||
/*
|
||||
* 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
|
||||
@@ -549,22 +491,11 @@ SCORE_EXTERN void *_CPU_Interrupt_stack_high;
|
||||
|
||||
|
||||
SCORE_EXTERN struct {
|
||||
unsigned32 *Nest_level;
|
||||
unsigned32 *Disable_level;
|
||||
void *Vector_table;
|
||||
void *Stack;
|
||||
#if (PPC_ABI == PPC_ABI_POWEROPEN)
|
||||
unsigned32 Dispatch_r2;
|
||||
#else
|
||||
unsigned32 Default_r2;
|
||||
#if (PPC_ABI != PPC_ABI_GCC27)
|
||||
unsigned32 Default_r13;
|
||||
#endif
|
||||
#endif
|
||||
volatile boolean *Switch_necessary;
|
||||
boolean *Signal;
|
||||
|
||||
unsigned32 msr_initial;
|
||||
} _CPU_IRQ_info CPU_STRUCTURE_ALIGNMENT;
|
||||
|
||||
/*
|
||||
@@ -662,148 +593,29 @@ SCORE_EXTERN struct {
|
||||
|
||||
#define loc_string(a,b) a " (" #b ")\n"
|
||||
|
||||
#define _CPU_MSR_Value( _msr_value ) \
|
||||
do { \
|
||||
_msr_value = 0; \
|
||||
asm volatile ("mfmsr %0" : "=&r" ((_msr_value)) : "0" ((_msr_value))); \
|
||||
} while (0)
|
||||
|
||||
#define _CPU_MSR_SET( _msr_value ) \
|
||||
{ asm volatile ("mtmsr %0" : "=&r" ((_msr_value)) : "0" ((_msr_value))); }
|
||||
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;
|
||||
}
|
||||
|
||||
#if 0
|
||||
#define _CPU_ISR_Disable( _isr_cookie ) \
|
||||
{ register unsigned int _disable_mask = PPC_MSR_DISABLE_MASK; \
|
||||
_isr_cookie = 0; \
|
||||
asm volatile (
|
||||
"mfmsr %0" : \
|
||||
"=r" ((_isr_cookie)) : \
|
||||
"0" ((_isr_cookie)) \
|
||||
); \
|
||||
asm volatile (
|
||||
"andc %1,%0,%1" : \
|
||||
"=r" ((_isr_cookie)), "=&r" ((_disable_mask)) : \
|
||||
"0" ((_isr_cookie)), "1" ((_disable_mask)) \
|
||||
); \
|
||||
asm volatile (
|
||||
"mtmsr %1" : \
|
||||
"=r" ((_disable_mask)) : \
|
||||
"0" ((_disable_mask)) \
|
||||
); \
|
||||
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;
|
||||
}
|
||||
#endif
|
||||
|
||||
#define _CPU_ISR_Disable( _isr_cookie ) \
|
||||
{ register unsigned int _disable_mask = PPC_MSR_DISABLE_MASK; \
|
||||
_isr_cookie = 0; \
|
||||
asm volatile ( \
|
||||
"mfmsr %0; andc %1,%0,%1; mtmsr %1" : \
|
||||
"=&r" ((_isr_cookie)), "=&r" ((_disable_mask)) : \
|
||||
"0" ((_isr_cookie)), "1" ((_disable_mask)) \
|
||||
); \
|
||||
else {
|
||||
msr &= ~MSR_EE;
|
||||
}
|
||||
_CPU_MSR_SET(msr);
|
||||
}
|
||||
|
||||
|
||||
#define _CPU_Data_Cache_Block_Flush( _address ) \
|
||||
do { register void *__address = (_address); \
|
||||
register unsigned32 _zero = 0; \
|
||||
asm volatile ( "dcbf %0,%1" : \
|
||||
"=r" (_zero), "=r" (__address) : \
|
||||
"0" (_zero), "1" (__address) \
|
||||
); \
|
||||
} while (0)
|
||||
|
||||
|
||||
/*
|
||||
* Enable interrupts to the previous level (returned by _CPU_ISR_Disable).
|
||||
* This indicates the end of an RTEMS critical section. The parameter
|
||||
* _isr_cookie is not modified.
|
||||
*/
|
||||
|
||||
#define _CPU_ISR_Enable( _isr_cookie ) \
|
||||
{ \
|
||||
asm volatile ( "mtmsr %0" : \
|
||||
"=r" ((_isr_cookie)) : \
|
||||
"0" ((_isr_cookie))); \
|
||||
}
|
||||
|
||||
/*
|
||||
* This temporarily restores the interrupt to _isr_cookie before immediately
|
||||
* disabling them again. This is used to divide long RTEMS critical
|
||||
* sections into two or more parts. The parameter _isr_cookie is not
|
||||
* modified.
|
||||
*
|
||||
* NOTE: The version being used is not very optimized but it does
|
||||
* not trip a problem in gcc where the disable mask does not
|
||||
* get loaded. Check this for future (post 10/97 gcc versions.
|
||||
*/
|
||||
|
||||
#define _CPU_ISR_Flash( _isr_cookie ) \
|
||||
{ register unsigned int _disable_mask = PPC_MSR_DISABLE_MASK; \
|
||||
asm volatile ( \
|
||||
"mtmsr %0; andc %1,%0,%1; mtmsr %1" : \
|
||||
"=r" ((_isr_cookie)), "=r" ((_disable_mask)) : \
|
||||
"0" ((_isr_cookie)), "1" ((_disable_mask)) \
|
||||
); \
|
||||
}
|
||||
|
||||
/*
|
||||
* Map interrupt level in task mode onto the hardware that the CPU
|
||||
* actually provides. Currently, interrupt levels which do not
|
||||
* map onto the CPU in a generic fashion are undefined. Someday,
|
||||
* it would be nice if these were "mapped" by the application
|
||||
* via a callout. For example, m68k has 8 levels 0 - 7, levels
|
||||
* 8 - 255 would be available for bsp/application specific meaning.
|
||||
* This could be used to manage a programmable interrupt controller
|
||||
* via the rtems_task_mode directive.
|
||||
*/
|
||||
|
||||
unsigned32 _CPU_ISR_Calculate_level(
|
||||
unsigned32 new_level
|
||||
);
|
||||
|
||||
void _CPU_ISR_Set_level(
|
||||
unsigned32 new_level
|
||||
);
|
||||
|
||||
unsigned32 _CPU_ISR_Get_level( void );
|
||||
|
||||
void _CPU_ISR_install_raw_handler(
|
||||
unsigned32 vector,
|
||||
proc_ptr new_handler,
|
||||
proc_ptr *old_handler
|
||||
);
|
||||
|
||||
/* end of ISR handler macros */
|
||||
|
||||
/*
|
||||
* Simple spin delay in microsecond units for device drivers.
|
||||
* This is very dependent on the clock speed of the target.
|
||||
*/
|
||||
|
||||
#define CPU_Get_timebase_low( _value ) \
|
||||
asm volatile( "mftb %0" : "=r" (_value) )
|
||||
|
||||
#define delay( _microseconds ) \
|
||||
do { \
|
||||
unsigned32 start, ticks, now; \
|
||||
CPU_Get_timebase_low( start ) ; \
|
||||
ticks = (_microseconds) * Cpu_table.clicks_per_usec; \
|
||||
do \
|
||||
CPU_Get_timebase_low( now ) ; \
|
||||
while (now - start < ticks); \
|
||||
} while (0)
|
||||
|
||||
#define delay_in_bus_cycles( _cycles ) \
|
||||
do { \
|
||||
unsigned32 start, now; \
|
||||
CPU_Get_timebase_low( start ); \
|
||||
do \
|
||||
CPU_Get_timebase_low( now ); \
|
||||
while (now - start < (_cycles)); \
|
||||
} while (0)
|
||||
|
||||
|
||||
#define _CPU_ISR_install_vector(irq, new, old) {BSP_panic("_CPU_ISR_install_vector called\n");}
|
||||
|
||||
/* Context handler macros */
|
||||
|
||||
@@ -892,7 +704,7 @@ void _CPU_Context_Initialize(
|
||||
*/
|
||||
|
||||
#define _CPU_Fatal_halt( _error ) \
|
||||
_CPU_Fatal_error(_error)
|
||||
_BSP_Fatal_error(_error)
|
||||
|
||||
/* end of Fatal Error manager macros */
|
||||
|
||||
@@ -999,17 +811,6 @@ void _CPU_Initialize(
|
||||
void (*thread_dispatch)
|
||||
);
|
||||
|
||||
/*
|
||||
* _CPU_ISR_install_vector
|
||||
*
|
||||
* This routine installs an interrupt vector.
|
||||
*/
|
||||
|
||||
void _CPU_ISR_install_vector(
|
||||
unsigned32 vector,
|
||||
proc_ptr new_handler,
|
||||
proc_ptr *old_handler
|
||||
);
|
||||
|
||||
/*
|
||||
* _CPU_Install_interrupt_stack
|
||||
396
c/src/exec/score/cpu/powerpc/mpc750/cpu_asm.S
Normal file
396
c/src/exec/score/cpu/powerpc/mpc750/cpu_asm.S
Normal 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
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
83
c/src/exec/score/cpu/powerpc/other_cpu/Makefile.in
Normal file
83
c/src/exec/score/cpu/powerpc/other_cpu/Makefile.in
Normal file
@@ -0,0 +1,83 @@
|
||||
#
|
||||
# $Id$
|
||||
#
|
||||
|
||||
@SET_MAKE@
|
||||
srcdir = @srcdir@
|
||||
top_srcdir = @top_srcdir@
|
||||
top_builddir = ../../../../../../..
|
||||
subdir = c/src/exec/score/cpu/powerpc/wrap
|
||||
|
||||
INSTALL = @INSTALL@
|
||||
|
||||
RTEMS_ROOT = $(top_srcdir)/@RTEMS_TOPdir@
|
||||
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
|
||||
|
||||
#
|
||||
# (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 444 ${RTEMS_SCORE_H_FILES} ${I_FILES} $(PROJECT_INCLUDE)/rtems/score
|
||||
$(INSTALL_CHANGE) -m 444 ${ROOT_H_FILES} $(PROJECT_INCLUDE)
|
||||
|
||||
Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
|
||||
cd $(top_builddir) \
|
||||
&& CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status
|
||||
4
c/src/exec/score/cpu/powerpc/other_cpu/c_isr.inl
Normal file
4
c/src/exec/score/cpu/powerpc/other_cpu/c_isr.inl
Normal file
@@ -0,0 +1,4 @@
|
||||
RTEMS_INLINE_ROUTINE boolean _ISR_Is_in_progress( void )
|
||||
{
|
||||
return (_ISR_Nest_level != 0);
|
||||
}
|
||||
@@ -41,6 +41,7 @@ extern "C" {
|
||||
#include <rtems/score/ppc.h> /* pick up machine definitions */
|
||||
#ifndef ASM
|
||||
struct CPU_Interrupt_frame;
|
||||
typedef void ( *ppc_isr_entry )( int, struct CPU_Interrupt_frame * );
|
||||
|
||||
#include <rtems/score/ppctypes.h>
|
||||
#endif
|
||||
615
c/src/exec/score/cpu/powerpc/rtems/score/ppc.h
Normal file
615
c/src/exec/score/cpu/powerpc/rtems/score/ppc.h
Normal file
@@ -0,0 +1,615 @@
|
||||
/* ppc.h
|
||||
*
|
||||
* This file contains definitions for the IBM/Motorola PowerPC
|
||||
* family members.
|
||||
*
|
||||
* Author: Andrew Bray <andy@i-cubed.co.uk>
|
||||
*
|
||||
* COPYRIGHT (c) 1995 by i-cubed ltd.
|
||||
*
|
||||
* MPC860 support code was added by Jay Monkman <jmonkman@frasca.com>
|
||||
*
|
||||
* 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/no_cpu.h:
|
||||
*
|
||||
* COPYRIGHT (c) 1989-1997.
|
||||
* On-Line Applications Research Corporation (OAR).
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*
|
||||
* Note:
|
||||
* This file is included by both C and assembler code ( -DASM )
|
||||
*
|
||||
* $Id$
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _INCLUDE_PPC_h
|
||||
#define _INCLUDE_PPC_h
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Define the name of the CPU family.
|
||||
*/
|
||||
|
||||
#define CPU_NAME "PowerPC"
|
||||
|
||||
/*
|
||||
* This file contains the information required to build
|
||||
* RTEMS for a particular member of the PowerPC family. It does
|
||||
* this by setting variables to indicate which implementation
|
||||
* dependent features are present in a particular member
|
||||
* of the family.
|
||||
*
|
||||
* The following architectural feature definitions are defaulted
|
||||
* unless specifically set by the model definition:
|
||||
*
|
||||
* + PPC_DEBUG_MODEL - PPC_DEBUG_MODEL_STANDARD
|
||||
* + PPC_INTERRUPT_MAX - 16
|
||||
* + PPC_CACHE_ALIGNMENT - 32
|
||||
* + PPC_LOW_POWER_MODE - PPC_LOW_POWER_MODE_NONE
|
||||
* + PPC_HAS_EXCEPTION_PREFIX - 1
|
||||
* + PPC_HAS_FPU - 1
|
||||
* + PPC_HAS_DOUBLE - 1 if PPC_HAS_FPU,
|
||||
* - 0 otherwise
|
||||
* + PPC_USE_MULTIPLE - 0
|
||||
*/
|
||||
|
||||
/*
|
||||
* Define the debugging assistance models found in the PPC family.
|
||||
*
|
||||
* Standard: single step and branch trace
|
||||
* Single Step Only: single step only
|
||||
* IBM 4xx: debug exception
|
||||
*/
|
||||
|
||||
#define PPC_DEBUG_MODEL_STANDARD 1
|
||||
#define PPC_DEBUG_MODEL_SINGLE_STEP_ONLY 2
|
||||
#define PPC_DEBUG_MODEL_IBM4xx 3
|
||||
|
||||
/*
|
||||
* Define the low power mode models
|
||||
*
|
||||
* Standard: as defined for 603e
|
||||
* Nap Mode: nap mode only (604)
|
||||
* XXX 403GB, 603, 603e, 604, 821
|
||||
*/
|
||||
|
||||
#define PPC_LOW_POWER_MODE_NONE 0
|
||||
#define PPC_LOW_POWER_MODE_STANDARD 1
|
||||
|
||||
#if defined(ppc403)
|
||||
/*
|
||||
* IBM 403
|
||||
*
|
||||
* Developed for 403GA. Book checked for 403GB.
|
||||
*
|
||||
* Does not have user mode.
|
||||
*/
|
||||
|
||||
#define CPU_MODEL_NAME "PowerPC 403"
|
||||
#define PPC_ALIGNMENT 4
|
||||
#define PPC_CACHE_ALIGNMENT 16
|
||||
#define PPC_HAS_RFCI 1
|
||||
#define PPC_HAS_FPU 0
|
||||
#define PPC_USE_MULTIPLE 1
|
||||
#define PPC_I_CACHE 2048
|
||||
#define PPC_D_CACHE 1024
|
||||
|
||||
#define PPC_DEBUG_MODEL PPC_DEBUG_MODEL_IBM4xx
|
||||
#define PPC_HAS_EXCEPTION_PREFIX 0
|
||||
#define PPC_HAS_EVPR 1
|
||||
|
||||
#elif defined(ppc601)
|
||||
/*
|
||||
* Submitted with original port -- book checked only.
|
||||
*/
|
||||
|
||||
#define CPU_MODEL_NAME "PowerPC 601"
|
||||
|
||||
#define PPC_ALIGNMENT 8
|
||||
#define PPC_USE_MULTIPLE 1
|
||||
#define PPC_I_CACHE 0
|
||||
#define PPC_D_CACHE 32768
|
||||
|
||||
#define PPC_DEBUG_MODEL PPC_DEBUG_MODEL_SINGLE_STEP_ONLY
|
||||
|
||||
#elif defined(ppc602)
|
||||
/*
|
||||
* Submitted with original port -- book checked only.
|
||||
*/
|
||||
|
||||
#define CPU_MODEL_NAME "PowerPC 602"
|
||||
|
||||
#define PPC_ALIGNMENT 4
|
||||
#define PPC_HAS_DOUBLE 0
|
||||
#define PPC_I_CACHE 4096
|
||||
#define PPC_D_CACHE 4096
|
||||
|
||||
#elif defined(ppc603)
|
||||
/*
|
||||
* Submitted with original port -- book checked only.
|
||||
*/
|
||||
|
||||
#define CPU_MODEL_NAME "PowerPC 603"
|
||||
|
||||
#define PPC_ALIGNMENT 8
|
||||
#define PPC_I_CACHE 8192
|
||||
#define PPC_D_CACHE 8192
|
||||
|
||||
#elif defined(ppc603e)
|
||||
|
||||
#define CPU_MODEL_NAME "PowerPC 603e"
|
||||
/*
|
||||
* Submitted with original port.
|
||||
*
|
||||
* Known to work on real hardware.
|
||||
*/
|
||||
|
||||
#define PPC_ALIGNMENT 8
|
||||
#define PPC_I_CACHE 16384
|
||||
#define PPC_D_CACHE 16384
|
||||
|
||||
#define PPC_LOW_POWER_MODE PPC_LOW_POWER_MODE_STANDARD
|
||||
|
||||
#elif defined(ppc604)
|
||||
/*
|
||||
* Submitted with original port -- book checked only.
|
||||
*/
|
||||
|
||||
#define CPU_MODEL_NAME "PowerPC 604"
|
||||
|
||||
#define PPC_ALIGNMENT 8
|
||||
#define PPC_I_CACHE 16384
|
||||
#define PPC_D_CACHE 16384
|
||||
|
||||
#elif defined(mpc860)
|
||||
/*
|
||||
* Added by Jay Monkman (jmonkman@frasca.com) 6/28/98
|
||||
*/
|
||||
#define CPU_MODEL_NAME "PowerPC MPC860"
|
||||
|
||||
#define PPC_ALIGNMENT 4
|
||||
#define PPC_I_CACHE 4096
|
||||
#define PPC_D_CACHE 4096
|
||||
#define PPC_CACHE_ALIGNMENT 16
|
||||
#define PPC_INTERRUPT_MAX 71
|
||||
#define PPC_HAS_FPU 0
|
||||
#define PPC_HAS_DOUBLE 0
|
||||
#define PPC_USE_MULTIPLE 1
|
||||
#define PPC_USE_SPRG 1
|
||||
|
||||
#define PPC_MSR_0 0x00009000
|
||||
#define PPC_MSR_1 0x00001000
|
||||
#define PPC_MSR_2 0x00001000
|
||||
#define PPC_MSR_3 0x00000000
|
||||
|
||||
#elif defined(mpc821)
|
||||
/*
|
||||
* Added by Andrew Bray <andy@chaos.org.uk> 6/April/1999
|
||||
*/
|
||||
#define CPU_MODEL_NAME "PowerPC MPC821"
|
||||
|
||||
#define PPC_ALIGNMENT 4
|
||||
#define PPC_I_CACHE 4096
|
||||
#define PPC_D_CACHE 4096
|
||||
#define PPC_CACHE_ALIGNMENT 16
|
||||
#define PPC_INTERRUPT_MAX 71
|
||||
#define PPC_HAS_FPU 0
|
||||
#define PPC_HAS_DOUBLE 0
|
||||
|
||||
#define PPC_MSR_0 0x00009000
|
||||
#define PPC_MSR_1 0x00001000
|
||||
#define PPC_MSR_2 0x00001000
|
||||
#define PPC_MSR_3 0x00000000
|
||||
|
||||
#elif defined(mpc750)
|
||||
|
||||
#define CPU_MODEL_NAME "PowerPC 750"
|
||||
|
||||
#define PPC_ALIGNMENT 8
|
||||
#define PPC_I_CACHE 16384
|
||||
#define PPC_D_CACHE 16384
|
||||
|
||||
#else
|
||||
|
||||
#error "Unsupported CPU Model"
|
||||
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Application binary interfaces.
|
||||
*
|
||||
* PPC_ABI MUST be defined as one of these.
|
||||
* Only PPC_ABI_POWEROPEN is currently fully supported.
|
||||
* Only EABI will be supported in the end when
|
||||
* the tools are there.
|
||||
* Only big endian is currently supported.
|
||||
*/
|
||||
/*
|
||||
* PowerOpen ABI. This is Andy's hack of the
|
||||
* PowerOpen ABI to ELF. ELF rather than a
|
||||
* XCOFF assembler is used. This may work
|
||||
* if PPC_ASM == PPC_ASM_XCOFF is defined.
|
||||
*/
|
||||
#define PPC_ABI_POWEROPEN 0
|
||||
/*
|
||||
* GCC 2.7.0 munched version of EABI, with
|
||||
* PowerOpen calling convention and stack frames,
|
||||
* but EABI style indirect function calls.
|
||||
*/
|
||||
#define PPC_ABI_GCC27 1
|
||||
/*
|
||||
* SVR4 ABI
|
||||
*/
|
||||
#define PPC_ABI_SVR4 2
|
||||
/*
|
||||
* Embedded ABI
|
||||
*/
|
||||
#define PPC_ABI_EABI 3
|
||||
|
||||
#if (PPC_ABI == PPC_ABI_POWEROPEN)
|
||||
#define PPC_STACK_ALIGNMENT 8
|
||||
#elif (PPC_ABI == PPC_ABI_GCC27)
|
||||
#define PPC_STACK_ALIGNMENT 8
|
||||
#elif (PPC_ABI == PPC_ABI_SVR4)
|
||||
#define PPC_STACK_ALIGNMENT 16
|
||||
#elif (PPC_ABI == PPC_ABI_EABI)
|
||||
#define PPC_STACK_ALIGNMENT 8
|
||||
#else
|
||||
#error "PPC_ABI is not properly defined"
|
||||
#endif
|
||||
#ifndef PPC_ABI
|
||||
#error "PPC_ABI is not properly defined"
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Assemblers.
|
||||
* PPC_ASM MUST be defined as one of these.
|
||||
*
|
||||
* PPC_ASM_ELF: ELF assembler. Currently used for all ABIs.
|
||||
* PPC_ASM_XCOFF: XCOFF assembler. May be needed for PowerOpen ABI.
|
||||
*
|
||||
* NOTE: Only PPC_ABI_ELF is currently fully supported.
|
||||
*/
|
||||
|
||||
#define PPC_ASM_ELF 0
|
||||
#define PPC_ASM_XCOFF 1
|
||||
|
||||
/*
|
||||
* Use the default debug scheme defined in the architectural specification
|
||||
* if another model has not been specified.
|
||||
*/
|
||||
|
||||
#ifndef PPC_DEBUG_MODEL
|
||||
#define PPC_DEBUG_MODEL PPC_DEBUG_MODEL_STANDARD
|
||||
#endif
|
||||
|
||||
/*
|
||||
* If the maximum number of exception sources has not been defined,
|
||||
* then default it to 16.
|
||||
*/
|
||||
|
||||
#ifndef PPC_INTERRUPT_MAX
|
||||
#define PPC_INTERRUPT_MAX 16
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Unless specified otherwise, the cache line size is defaulted to 32.
|
||||
*
|
||||
* The derive the power of 2 the cache line is.
|
||||
*/
|
||||
|
||||
#ifndef PPC_CACHE_ALIGNMENT
|
||||
#define PPC_CACHE_ALIGNMENT 32
|
||||
#endif
|
||||
|
||||
#if (PPC_CACHE_ALIGNMENT == 16)
|
||||
#define PPC_CACHE_ALIGN_POWER 4
|
||||
#elif (PPC_CACHE_ALIGNMENT == 32)
|
||||
#define PPC_CACHE_ALIGN_POWER 5
|
||||
#else
|
||||
#error "Undefined power of 2 for PPC_CACHE_ALIGNMENT"
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Unless otherwise specified, assume the model has an IP/EP bit to
|
||||
* set the exception address prefix.
|
||||
*/
|
||||
|
||||
#ifndef PPC_HAS_EXCEPTION_PREFIX
|
||||
#define PPC_HAS_EXCEPTION_PREFIX 1
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Unless otherwise specified, assume the model does NOT have
|
||||
* 403 style EVPR register to set the exception address prefix.
|
||||
*/
|
||||
|
||||
#ifndef PPC_HAS_EVPR
|
||||
#define PPC_HAS_EVPR 0
|
||||
#endif
|
||||
|
||||
/*
|
||||
* If no low power mode model was specified, then assume there is none.
|
||||
*/
|
||||
|
||||
#ifndef PPC_LOW_POWER_MODE
|
||||
#define PPC_LOW_POWER_MODE PPC_LOW_POWER_MODE_NONE
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Unless specified above, then assume the model has FP support.
|
||||
*/
|
||||
|
||||
#ifndef PPC_HAS_FPU
|
||||
#define PPC_HAS_FPU 1
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Unless specified above, If the model has FP support, it is assumed to
|
||||
* support doubles (8-byte floating point numbers).
|
||||
*
|
||||
* If the model does NOT have FP support, then the model does
|
||||
* NOT have double length FP registers.
|
||||
*/
|
||||
|
||||
#ifndef PPC_HAS_DOUBLE
|
||||
#if (PPC_HAS_FPU)
|
||||
#define PPC_HAS_DOUBLE 1
|
||||
#else
|
||||
#define PPC_HAS_DOUBLE 0
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Unless specified above, then assume the model does NOT have critical
|
||||
* interrupt support.
|
||||
*/
|
||||
|
||||
#ifndef PPC_HAS_RFCI
|
||||
#define PPC_HAS_RFCI 0
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Unless specified above, do not use the load/store multiple instructions
|
||||
* in a context switch.
|
||||
*/
|
||||
|
||||
#ifndef PPC_USE_MULTIPLE
|
||||
#define PPC_USE_MULTIPLE 0
|
||||
#endif
|
||||
|
||||
/*
|
||||
* The following exceptions are not maskable, and are not
|
||||
* necessarily predictable, so cannot be offered to RTEMS:
|
||||
* Alignment exception - handled by the CPU module
|
||||
* Data exceptions.
|
||||
* Instruction exceptions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Base Interrupt vectors supported on all models.
|
||||
*/
|
||||
#define PPC_IRQ_SYSTEM_RESET 0 /* 0x00100 - System reset. */
|
||||
#define PPC_IRQ_MCHECK 1 /* 0x00200 - Machine check */
|
||||
#define PPC_IRQ_PROTECT 2 /* 0x00300 - Protection violation */
|
||||
#define PPC_IRQ_ISI 3 /* 0x00400 - Instruction Fetch error */
|
||||
#define PPC_IRQ_EXTERNAL 4 /* 0x00500 - External interrupt */
|
||||
#define PPC_IRQ_ALIGNMENT 5 /* 0X00600 - Alignment exception */
|
||||
#define PPC_IRQ_PROGRAM 6 /* 0x00700 - Program exception */
|
||||
#define PPC_IRQ_NOFP 7 /* 0x00800 - Floating point unavailable */
|
||||
#define PPC_IRQ_DECREMENTER 8 /* 0x00900 - Decrementer interrupt */
|
||||
#define PPC_IRQ_RESERVED_A 9 /* 0x00a00 - Implementation Reserved */
|
||||
#define PPC_IRQ_RESERVED_B 10 /* 0x00a00 - Implementation Reserved */
|
||||
#define PPC_IRQ_SCALL 11 /* 0x00c00 - System call */
|
||||
#define PPC_IRQ_TRACE 12 /* 0x00d00 - Trace Exception */
|
||||
#define PPC_IRQ_FP_ASST 13 /* ox00e00 - Floating point assist */
|
||||
#define PPC_STD_IRQ_LAST PPC_IRQ_FP_ASST
|
||||
|
||||
#define PPC_IRQ_FIRST PPC_IRQ_SYSTEM_RESET
|
||||
|
||||
#if defined(ppc403)
|
||||
|
||||
#define PPC_IRQ_CRIT PPC_IRQ_SYSTEM_RESET /*0x00100- Critical int. pin */
|
||||
#define PPC_IRQ_PIT (PPC_STD_IRQ_LAST+1) /*0x01000- Pgm interval timer*/
|
||||
#define PPC_IRQ_FIT (PPC_STD_IRQ_LAST+2) /*0x01010- Fixed int. timer */
|
||||
#define PPC_IRQ_WATCHDOG (PPC_STD_IRQ_LAST+3) /*0x01020- Watchdog timer */
|
||||
#define PPC_IRQ_DEBUG (PPC_STD_IRQ_LAST+4) /*0x02000- Debug exceptions */
|
||||
#define PPC_IRQ_LAST PPC_IRQ_DEBUG
|
||||
|
||||
#elif defined(ppc601)
|
||||
#define PPC_IRQ_TRACE (PPC_STD_IRQ_LAST+1) /*0x02000-Run/Trace Exception*/
|
||||
#define PPC_IRQ_LAST PPC_IRQ_TRACE
|
||||
|
||||
#elif defined(ppc602)
|
||||
#define PPC_IRQ_LAST (PPC_STD_IRQ_LAST)
|
||||
|
||||
#elif defined(ppc603)
|
||||
#define PPC_IRQ_TRANS_MISS (PPC_STD_IRQ_LAST+1) /*0x1000-Ins Translation Miss*/
|
||||
#define PPC_IRQ_DATA_LOAD (PPC_STD_IRQ_LAST+2) /*0x1100-Data Load Trans Miss*/
|
||||
#define PPC_IRQ_DATA_STORE (PPC_STD_IRQ_LAST+3) /*0x1200-Data Store Miss */
|
||||
#define PPC_IRQ_ADDR_BRK (PPC_STD_IRQ_LAST+4) /*0x1300-Instruction Bkpoint */
|
||||
#define PPC_IRQ_SYS_MGT (PPC_STD_IRQ_LAST+5) /*0x1400-System Management */
|
||||
#define PPC_IRQ_LAST PPC_IRQ_SYS_MGT
|
||||
|
||||
#elif defined(ppc603e)
|
||||
#define PPC_TLB_INST_MISS (PPC_STD_IRQ_LAST+1) /*0x1000-Instruction TLB Miss*/
|
||||
#define PPC_TLB_LOAD_MISS (PPC_STD_IRQ_LAST+2) /*0x1100-TLB miss on load */
|
||||
#define PPC_TLB_STORE_MISS (PPC_STD_IRQ_LAST+3) /*0x1200-TLB Miss on store */
|
||||
#define PPC_IRQ_ADDRBRK (PPC_STD_IRQ_LAST+4) /*0x1300-Instruct addr break */
|
||||
#define PPC_IRQ_SYS_MGT (PPC_STD_IRQ_LAST+5) /*0x1400-System Management */
|
||||
#define PPC_IRQ_LAST PPC_IRQ_SYS_MGT
|
||||
|
||||
|
||||
#elif defined(ppc604)
|
||||
#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_LAST PPC_IRQ_SYS_MGT
|
||||
|
||||
#elif defined(mpc860) || defined(mpc821)
|
||||
#define PPC_IRQ_EMULATE (PPC_STD_IRQ_LAST+1) /*0x1000-Software emulation */
|
||||
#define PPC_IRQ_INST_MISS (PPC_STD_IRQ_LAST+2) /*0x1100-Instruction TLB miss*/
|
||||
#define PPC_IRQ_DATA_MISS (PPC_STD_IRQ_LAST+3) /*0x1200-Data TLB miss */
|
||||
#define PPC_IRQ_INST_ERR (PPC_STD_IRQ_LAST+4) /*0x1300-Instruction TLB err */
|
||||
#define PPC_IRQ_DATA_ERR (PPC_STD_IRQ_LAST+5) /*0x1400-Data TLB error */
|
||||
#define PPC_IRQ_DATA_BPNT (PPC_STD_IRQ_LAST+6) /*0x1C00-Data breakpoint */
|
||||
#define PPC_IRQ_INST_BPNT (PPC_STD_IRQ_LAST+7) /*0x1D00-Inst breakpoint */
|
||||
#define PPC_IRQ_IO_BPNT (PPC_STD_IRQ_LAST+8) /*0x1E00-Peripheral breakpnt */
|
||||
#define PPC_IRQ_DEV_PORT (PPC_STD_IRQ_LAST+9) /*0x1F00-Development port */
|
||||
#define PPC_IRQ_IRQ0 (PPC_STD_IRQ_LAST + 10)
|
||||
#define PPC_IRQ_LVL0 (PPC_STD_IRQ_LAST + 11)
|
||||
#define PPC_IRQ_IRQ1 (PPC_STD_IRQ_LAST + 12)
|
||||
#define PPC_IRQ_LVL1 (PPC_STD_IRQ_LAST + 13)
|
||||
#define PPC_IRQ_IRQ2 (PPC_STD_IRQ_LAST + 14)
|
||||
#define PPC_IRQ_LVL2 (PPC_STD_IRQ_LAST + 15)
|
||||
#define PPC_IRQ_IRQ3 (PPC_STD_IRQ_LAST + 16)
|
||||
#define PPC_IRQ_LVL3 (PPC_STD_IRQ_LAST + 17)
|
||||
#define PPC_IRQ_IRQ4 (PPC_STD_IRQ_LAST + 18)
|
||||
#define PPC_IRQ_LVL4 (PPC_STD_IRQ_LAST + 19)
|
||||
#define PPC_IRQ_IRQ5 (PPC_STD_IRQ_LAST + 20)
|
||||
#define PPC_IRQ_LVL5 (PPC_STD_IRQ_LAST + 21)
|
||||
#define PPC_IRQ_IRQ6 (PPC_STD_IRQ_LAST + 22)
|
||||
#define PPC_IRQ_LVL6 (PPC_STD_IRQ_LAST + 23)
|
||||
#define PPC_IRQ_IRQ7 (PPC_STD_IRQ_LAST + 24)
|
||||
#define PPC_IRQ_LVL7 (PPC_STD_IRQ_LAST + 25)
|
||||
#define PPC_IRQ_CPM_RESERVED_0 (PPC_STD_IRQ_LAST + 26)
|
||||
#define PPC_IRQ_CPM_PC4 (PPC_STD_IRQ_LAST + 27)
|
||||
#define PPC_IRQ_CPM_PC5 (PPC_STD_IRQ_LAST + 28)
|
||||
#define PPC_IRQ_CPM_SMC2 (PPC_STD_IRQ_LAST + 29)
|
||||
#define PPC_IRQ_CPM_SMC1 (PPC_STD_IRQ_LAST + 30)
|
||||
#define PPC_IRQ_CPM_SPI (PPC_STD_IRQ_LAST + 31)
|
||||
#define PPC_IRQ_CPM_PC6 (PPC_STD_IRQ_LAST + 32)
|
||||
#define PPC_IRQ_CPM_TIMER4 (PPC_STD_IRQ_LAST + 33)
|
||||
#define PPC_IRQ_CPM_RESERVED_8 (PPC_STD_IRQ_LAST + 34)
|
||||
#define PPC_IRQ_CPM_PC7 (PPC_STD_IRQ_LAST + 35)
|
||||
#define PPC_IRQ_CPM_PC8 (PPC_STD_IRQ_LAST + 36)
|
||||
#define PPC_IRQ_CPM_PC9 (PPC_STD_IRQ_LAST + 37)
|
||||
#define PPC_IRQ_CPM_TIMER3 (PPC_STD_IRQ_LAST + 38)
|
||||
#define PPC_IRQ_CPM_RESERVED_D (PPC_STD_IRQ_LAST + 39)
|
||||
#define PPC_IRQ_CPM_PC10 (PPC_STD_IRQ_LAST + 40)
|
||||
#define PPC_IRQ_CPM_PC11 (PPC_STD_IRQ_LAST + 41)
|
||||
#define PPC_IRQ_CPM_I2C (PPC_STD_IRQ_LAST + 42)
|
||||
#define PPC_IRQ_CPM_RISC_TIMER (PPC_STD_IRQ_LAST + 43)
|
||||
#define PPC_IRQ_CPM_TIMER2 (PPC_STD_IRQ_LAST + 44)
|
||||
#define PPC_IRQ_CPM_RESERVED_13 (PPC_STD_IRQ_LAST + 45)
|
||||
#define PPC_IRQ_CPM_IDMA2 (PPC_STD_IRQ_LAST + 46)
|
||||
#define PPC_IRQ_CPM_IDMA1 (PPC_STD_IRQ_LAST + 47)
|
||||
#define PPC_IRQ_CPM_SDMA_ERROR (PPC_STD_IRQ_LAST + 48)
|
||||
#define PPC_IRQ_CPM_PC12 (PPC_STD_IRQ_LAST + 49)
|
||||
#define PPC_IRQ_CPM_PC13 (PPC_STD_IRQ_LAST + 50)
|
||||
#define PPC_IRQ_CPM_TIMER1 (PPC_STD_IRQ_LAST + 51)
|
||||
#define PPC_IRQ_CPM_PC14 (PPC_STD_IRQ_LAST + 52)
|
||||
#define PPC_IRQ_CPM_SCC4 (PPC_STD_IRQ_LAST + 53)
|
||||
#define PPC_IRQ_CPM_SCC3 (PPC_STD_IRQ_LAST + 54)
|
||||
#define PPC_IRQ_CPM_SCC2 (PPC_STD_IRQ_LAST + 55)
|
||||
#define PPC_IRQ_CPM_SCC1 (PPC_STD_IRQ_LAST + 56)
|
||||
#define PPC_IRQ_CPM_PC15 (PPC_STD_IRQ_LAST + 57)
|
||||
|
||||
#define PPC_IRQ_LAST PPC_IRQ_CPM_PC15
|
||||
|
||||
#endif
|
||||
|
||||
/*
|
||||
* If the maximum number of exception sources is too low,
|
||||
* then fix it
|
||||
*/
|
||||
|
||||
#if PPC_INTERRUPT_MAX <= PPC_IRQ_LAST
|
||||
#undef PPC_INTERRUPT_MAX
|
||||
#define PPC_INTERRUPT_MAX ((PPC_IRQ_LAST) + 1)
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Machine Status Register (MSR) Constants Used by RTEMS
|
||||
*/
|
||||
|
||||
/*
|
||||
* Some PPC model manuals refer to the Exception Prefix (EP) bit as
|
||||
* IP for no apparent reason.
|
||||
*/
|
||||
|
||||
#define PPC_MSR_RI 0x000000002 /* bit 30 - recoverable exception */
|
||||
#define PPC_MSR_DR 0x000000010 /* bit 27 - data address translation */
|
||||
#define PPC_MSR_IR 0x000000020 /* bit 26 - instruction addr translation*/
|
||||
|
||||
#if (PPC_HAS_EXCEPTION_PREFIX)
|
||||
#define PPC_MSR_EP 0x000000040 /* bit 25 - exception prefix */
|
||||
#else
|
||||
#define PPC_MSR_EP 0x000000000 /* bit 25 - exception prefix */
|
||||
#endif
|
||||
|
||||
#if (PPC_HAS_FPU)
|
||||
#define PPC_MSR_FP 0x000002000 /* bit 18 - floating point enable */
|
||||
#else
|
||||
#define PPC_MSR_FP 0x000000000 /* bit 18 - floating point enable */
|
||||
#endif
|
||||
|
||||
#if (PPC_LOW_POWER_MODE == PPC_LOW_POWER_MODE_NONE)
|
||||
#define PPC_MSR_POW 0x000000000 /* bit 13 - power management enable */
|
||||
#else
|
||||
#define PPC_MSR_POW 0x000040000 /* bit 13 - power management enable */
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Interrupt/exception MSR bits set as defined on p. 2-20 in "The Programming
|
||||
* Environments" and the manuals for various PPC models.
|
||||
*/
|
||||
|
||||
#if (PPC_DEBUG_MODEL == PPC_DEBUG_MODEL_STANDARD)
|
||||
#define PPC_MSR_DE 0x000000000 /* bit 22 - debug exception enable */
|
||||
#define PPC_MSR_BE 0x000000200 /* bit 22 - branch trace enable */
|
||||
#define PPC_MSR_SE 0x000000400 /* bit 21 - single step trace enable */
|
||||
#elif (PPC_DEBUG_MODEL == PPC_DEBUG_MODEL_SINGLE_STEP_ONLY)
|
||||
#define PPC_MSR_DE 0x000000000 /* bit 22 - debug exception enable */
|
||||
#define PPC_MSR_BE 0x000000200 /* bit 22 - branch trace enable */
|
||||
#define PPC_MSR_SE 0x000000000 /* bit 21 - single step trace enable */
|
||||
#elif (PPC_DEBUG_MODEL == PPC_DEBUG_MODEL_IBM4xx)
|
||||
#define PPC_MSR_DE 0x000000200 /* bit 22 - debug exception enable */
|
||||
#define PPC_MSR_BE 0x000000000 /* bit 22 - branch trace enable */
|
||||
#define PPC_MSR_SE 0x000000000 /* bit 21 - single step trace enable */
|
||||
#else
|
||||
#error "MSR constants -- unknown PPC_DEBUG_MODEL!!"
|
||||
#endif
|
||||
|
||||
#define PPC_MSR_ME 0x000001000 /* bit 19 - machine check enable */
|
||||
#define PPC_MSR_EE 0x000008000 /* bit 16 - external interrupt enable */
|
||||
|
||||
#if (PPC_HAS_RFCI)
|
||||
#define PPC_MSR_CE 0x000020000 /* bit 14 - critical interrupt enable */
|
||||
#else
|
||||
#define PPC_MSR_CE 0x000000000 /* bit 14 - critical interrupt enable */
|
||||
#endif
|
||||
|
||||
#define PPC_MSR_DISABLE_MASK (PPC_MSR_ME|PPC_MSR_EE|PPC_MSR_CE)
|
||||
|
||||
/*
|
||||
* Initial value for the FPSCR register
|
||||
*/
|
||||
|
||||
#define PPC_INIT_FPSCR 0x000000f8
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* ! _INCLUDE_PPC_h */
|
||||
/* end of include file */
|
||||
|
||||
|
||||
73
c/src/exec/score/cpu/powerpc/rtems/score/ppctypes.h
Normal file
73
c/src/exec/score/cpu/powerpc/rtems/score/ppctypes.h
Normal file
@@ -0,0 +1,73 @@
|
||||
/* ppctypes.h
|
||||
*
|
||||
* This include file contains type definitions pertaining to the PowerPC
|
||||
* processor family.
|
||||
*
|
||||
* 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/no_cputypes.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 in
|
||||
* the file LICENSE in this distribution or at
|
||||
* http://www.OARcorp.com/rtems/license.html.
|
||||
*
|
||||
* $Id$
|
||||
*/
|
||||
|
||||
#ifndef __PPC_TYPES_h
|
||||
#define __PPC_TYPES_h
|
||||
|
||||
#ifndef ASM
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*
|
||||
* This section defines the basic types for this processor.
|
||||
*/
|
||||
|
||||
typedef unsigned char unsigned8; /* unsigned 8-bit integer */
|
||||
typedef unsigned short unsigned16; /* unsigned 16-bit integer */
|
||||
typedef unsigned int unsigned32; /* unsigned 32-bit integer */
|
||||
typedef unsigned long long unsigned64; /* unsigned 64-bit integer */
|
||||
|
||||
typedef unsigned32 Priority_Bit_map_control;
|
||||
|
||||
typedef signed char signed8; /* 8-bit signed integer */
|
||||
typedef signed short signed16; /* 16-bit signed integer */
|
||||
typedef signed int signed32; /* 32-bit signed integer */
|
||||
typedef signed long long signed64; /* 64 bit signed integer */
|
||||
|
||||
typedef unsigned32 boolean; /* Boolean value */
|
||||
|
||||
typedef float single_precision; /* single precision float */
|
||||
typedef double double_precision; /* double precision float */
|
||||
|
||||
typedef void ppc_isr;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* !ASM */
|
||||
|
||||
#endif
|
||||
/* end of include file */
|
||||
73
c/src/exec/score/cpu/powerpc/rtems/score/types.h
Normal file
73
c/src/exec/score/cpu/powerpc/rtems/score/types.h
Normal file
@@ -0,0 +1,73 @@
|
||||
/* ppctypes.h
|
||||
*
|
||||
* This include file contains type definitions pertaining to the PowerPC
|
||||
* processor family.
|
||||
*
|
||||
* 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/no_cputypes.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 in
|
||||
* the file LICENSE in this distribution or at
|
||||
* http://www.OARcorp.com/rtems/license.html.
|
||||
*
|
||||
* $Id$
|
||||
*/
|
||||
|
||||
#ifndef __PPC_TYPES_h
|
||||
#define __PPC_TYPES_h
|
||||
|
||||
#ifndef ASM
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*
|
||||
* This section defines the basic types for this processor.
|
||||
*/
|
||||
|
||||
typedef unsigned char unsigned8; /* unsigned 8-bit integer */
|
||||
typedef unsigned short unsigned16; /* unsigned 16-bit integer */
|
||||
typedef unsigned int unsigned32; /* unsigned 32-bit integer */
|
||||
typedef unsigned long long unsigned64; /* unsigned 64-bit integer */
|
||||
|
||||
typedef unsigned32 Priority_Bit_map_control;
|
||||
|
||||
typedef signed char signed8; /* 8-bit signed integer */
|
||||
typedef signed short signed16; /* 16-bit signed integer */
|
||||
typedef signed int signed32; /* 32-bit signed integer */
|
||||
typedef signed long long signed64; /* 64 bit signed integer */
|
||||
|
||||
typedef unsigned32 boolean; /* Boolean value */
|
||||
|
||||
typedef float single_precision; /* single precision float */
|
||||
typedef double double_precision; /* double precision float */
|
||||
|
||||
typedef void ppc_isr;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* !ASM */
|
||||
|
||||
#endif
|
||||
/* end of include file */
|
||||
77
c/src/exec/score/cpu/powerpc/shared/Makefile.in
Normal file
77
c/src/exec/score/cpu/powerpc/shared/Makefile.in
Normal file
@@ -0,0 +1,77 @@
|
||||
#
|
||||
# $Id$
|
||||
#
|
||||
|
||||
@SET_MAKE@
|
||||
srcdir = @srcdir@
|
||||
top_srcdir = @top_srcdir@
|
||||
top_builddir = ../../../../../../..
|
||||
subdir = c/src/exec/score/cpu/powerpc/shared
|
||||
|
||||
INSTALL = @INSTALL@
|
||||
|
||||
RTEMS_ROOT = $(top_srcdir)/@RTEMS_TOPdir@
|
||||
PROJECT_ROOT = @PROJECT_ROOT@
|
||||
|
||||
VPATH = @srcdir@
|
||||
|
||||
RELS=
|
||||
|
||||
# C source names, if any, go here -- minus the .c
|
||||
C_PIECES =
|
||||
C_FILES=$(C_PIECES:%=%.c)
|
||||
C_O_FILES=$(C_PIECES:%=${ARCH}/%.o)
|
||||
|
||||
ROOT_H_PIECES = asm.h
|
||||
ROOT_H_FILES=$(ROOT_H_PIECES:%=$(srcdir)/%)
|
||||
RTEMS_SCORE_H_PIECES=ppc.h ppctypes.h
|
||||
RTEMS_SCORE_H_FILES=$(RTEMS_SCORE_H_PIECES:%=$(srcdir)/%)
|
||||
H_PIECES=$(ROOT_H_PIECES) $(RTEMS_SCORE_H_PIECES)
|
||||
H_FILES=$(H_PIECES%=$(srcdir)/%)
|
||||
|
||||
# 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) $(EXTERNAL_H_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
|
||||
|
||||
#
|
||||
# (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 +=
|
||||
|
||||
all:$(SRCS) preinstall
|
||||
|
||||
# Install the program(s), appending _g or _p as appropriate.
|
||||
# for include files, just use $(INSTALL_CHANGE)
|
||||
install: all
|
||||
|
||||
preinstall: ${ARCH}
|
||||
$(INSTALL_CHANGE) -m 444 ${RTEMS_SCORE_H_FILES} $(PROJECT_INCLUDE)/rtems/score
|
||||
$(INSTALL_CHANGE) -m 444 ${ROOT_H_FILES} $(PROJECT_INCLUDE)
|
||||
|
||||
Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
|
||||
cd $(top_builddir) \
|
||||
&& CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status
|
||||
275
c/src/exec/score/cpu/powerpc/shared/asm.h
Normal file
275
c/src/exec/score/cpu/powerpc/shared/asm.h
Normal file
@@ -0,0 +1,275 @@
|
||||
/* asm.h
|
||||
*
|
||||
* This include file attempts to address the problems
|
||||
* caused by incompatible flavors of assemblers and
|
||||
* toolsets. It primarily addresses variations in the
|
||||
* use of leading underscores on symbols and the requirement
|
||||
* that register names be preceded by a %.
|
||||
*
|
||||
*
|
||||
* NOTE: The spacing in the use of these macros
|
||||
* is critical to them working as advertised.
|
||||
*
|
||||
* COPYRIGHT:
|
||||
*
|
||||
* This file is based on similar code found in newlib available
|
||||
* from ftp.cygnus.com. The file which was used had no copyright
|
||||
* notice. This file is freely distributable as long as the source
|
||||
* of the file is noted. This file is:
|
||||
*
|
||||
* COPYRIGHT (c) 1995.
|
||||
* i-cubed ltd.
|
||||
*
|
||||
* COPYRIGHT (c) 1994.
|
||||
* On-Line Applications Research Corporation (OAR).
|
||||
*
|
||||
* $Id$
|
||||
*/
|
||||
|
||||
#ifndef __PPC_ASM_h
|
||||
#define __PPC_ASM_h
|
||||
|
||||
/*
|
||||
* Indicate we are in an assembly file and get the basic CPU definitions.
|
||||
*/
|
||||
|
||||
#ifndef ASM
|
||||
#define ASM
|
||||
#endif
|
||||
#include <rtems/score/targopts.h>
|
||||
#include <rtems/score/ppc.h>
|
||||
|
||||
/*
|
||||
* Recent versions of GNU cpp define variables which indicate the
|
||||
* need for underscores and percents. If not using GNU cpp or
|
||||
* the version does not support this, then you will obviously
|
||||
* have to define these as appropriate.
|
||||
*/
|
||||
|
||||
#ifndef __USER_LABEL_PREFIX__
|
||||
#define __USER_LABEL_PREFIX__
|
||||
#endif
|
||||
|
||||
#ifndef __REGISTER_PREFIX__
|
||||
#define __REGISTER_PREFIX__
|
||||
#endif
|
||||
|
||||
#ifndef __FLOAT_REGISTER_PREFIX__
|
||||
#define __FLOAT_REGISTER_PREFIX__ __REGISTER_PREFIX__
|
||||
#endif
|
||||
|
||||
#if (PPC_ABI == PPC_ABI_POWEROPEN)
|
||||
#ifndef __PROC_LABEL_PREFIX__
|
||||
#define __PROC_LABEL_PREFIX__ .
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef __PROC_LABEL_PREFIX__
|
||||
#define __PROC_LABEL_PREFIX__ __USER_LABEL_PREFIX__
|
||||
#endif
|
||||
|
||||
/* ANSI concatenation macros. */
|
||||
|
||||
#define CONCAT1(a, b) CONCAT2(a, b)
|
||||
#define CONCAT2(a, b) a ## b
|
||||
|
||||
/* Use the right prefix for global labels. */
|
||||
|
||||
#define SYM(x) CONCAT1 (__USER_LABEL_PREFIX__, x)
|
||||
|
||||
/* Use the right prefix for procedure labels. */
|
||||
|
||||
#define PROC(x) CONCAT1 (__PROC_LABEL_PREFIX__, x)
|
||||
|
||||
/* Use the right prefix for registers. */
|
||||
|
||||
#define REG(x) CONCAT1 (__REGISTER_PREFIX__, x)
|
||||
|
||||
/* Use the right prefix for floating point registers. */
|
||||
|
||||
#define FREG(x) CONCAT1 (__FLOAT_REGISTER_PREFIX__, x)
|
||||
|
||||
/*
|
||||
* define macros for all of the registers on this CPU
|
||||
*
|
||||
* EXAMPLE: #define d0 REG (d0)
|
||||
*/
|
||||
#define r0 REG(0)
|
||||
#define r1 REG(1)
|
||||
#define r2 REG(2)
|
||||
#define r3 REG(3)
|
||||
#define r4 REG(4)
|
||||
#define r5 REG(5)
|
||||
#define r6 REG(6)
|
||||
#define r7 REG(7)
|
||||
#define r8 REG(8)
|
||||
#define r9 REG(9)
|
||||
#define r10 REG(10)
|
||||
#define r11 REG(11)
|
||||
#define r12 REG(12)
|
||||
#define r13 REG(13)
|
||||
#define r14 REG(14)
|
||||
#define r15 REG(15)
|
||||
#define r16 REG(16)
|
||||
#define r17 REG(17)
|
||||
#define r18 REG(18)
|
||||
#define r19 REG(19)
|
||||
#define r20 REG(20)
|
||||
#define r21 REG(21)
|
||||
#define r22 REG(22)
|
||||
#define r23 REG(23)
|
||||
#define r24 REG(24)
|
||||
#define r25 REG(25)
|
||||
#define r26 REG(26)
|
||||
#define r27 REG(27)
|
||||
#define r28 REG(28)
|
||||
#define r29 REG(29)
|
||||
#define r30 REG(30)
|
||||
#define r31 REG(31)
|
||||
#define f0 FREG(0)
|
||||
#define f1 FREG(1)
|
||||
#define f2 FREG(2)
|
||||
#define f3 FREG(3)
|
||||
#define f4 FREG(4)
|
||||
#define f5 FREG(5)
|
||||
#define f6 FREG(6)
|
||||
#define f7 FREG(7)
|
||||
#define f8 FREG(8)
|
||||
#define f9 FREG(9)
|
||||
#define f10 FREG(10)
|
||||
#define f11 FREG(11)
|
||||
#define f12 FREG(12)
|
||||
#define f13 FREG(13)
|
||||
#define f14 FREG(14)
|
||||
#define f15 FREG(15)
|
||||
#define f16 FREG(16)
|
||||
#define f17 FREG(17)
|
||||
#define f18 FREG(18)
|
||||
#define f19 FREG(19)
|
||||
#define f20 FREG(20)
|
||||
#define f21 FREG(21)
|
||||
#define f22 FREG(22)
|
||||
#define f23 FREG(23)
|
||||
#define f24 FREG(24)
|
||||
#define f25 FREG(25)
|
||||
#define f26 FREG(26)
|
||||
#define f27 FREG(27)
|
||||
#define f28 FREG(28)
|
||||
#define f29 FREG(29)
|
||||
#define f30 FREG(30)
|
||||
#define f31 FREG(31)
|
||||
|
||||
/*
|
||||
* Some special purpose registers (SPRs).
|
||||
*/
|
||||
#define srr0 0x01a
|
||||
#define srr1 0x01b
|
||||
#define srr2 0x3de /* IBM 400 series only */
|
||||
#define srr3 0x3df /* IBM 400 series only */
|
||||
#define sprg0 0x110
|
||||
#define sprg1 0x111
|
||||
#define sprg2 0x112
|
||||
#define sprg3 0x113
|
||||
|
||||
|
||||
/* the following SPR/DCR registers exist only in IBM 400 series */
|
||||
#define dear 0x3d5
|
||||
#define evpr 0x3d6 /* SPR: exception vector prefix register */
|
||||
#define iccr 0x3fb /* SPR: instruction cache control reg. */
|
||||
#define dccr 0x3fa /* SPR: data cache control reg. */
|
||||
|
||||
#define exisr 0x040 /* DCR: external interrupt status register */
|
||||
#define exier 0x042 /* DCR: external interrupt enable register */
|
||||
#define br0 0x080 /* DCR: memory bank register 0 */
|
||||
#define br1 0x081 /* DCR: memory bank register 1 */
|
||||
#define br2 0x082 /* DCR: memory bank register 2 */
|
||||
#define br3 0x083 /* DCR: memory bank register 3 */
|
||||
#define br4 0x084 /* DCR: memory bank register 4 */
|
||||
#define br5 0x085 /* DCR: memory bank register 5 */
|
||||
#define br6 0x086 /* DCR: memory bank register 6 */
|
||||
#define br7 0x087 /* DCR: memory bank register 7 */
|
||||
/* end of IBM400 series register definitions */
|
||||
|
||||
/* The following registers are for the MPC8x0 */
|
||||
#define der 0x095 /* Debug Enable Register */
|
||||
/* end of MPC8x0 registers */
|
||||
|
||||
/*
|
||||
* Following must be tailor for a particular flavor of the C compiler.
|
||||
* They may need to put underscores in front of the symbols.
|
||||
*/
|
||||
|
||||
#define PUBLIC_VAR(sym) .globl SYM (sym)
|
||||
#define EXTERN_VAR(sym) .extern SYM (sym)
|
||||
#define PUBLIC_PROC(sym) .globl PROC (sym)
|
||||
#define EXTERN_PROC(sym) .extern PROC (sym)
|
||||
|
||||
/* Other potentially assembler specific operations */
|
||||
#if PPC_ASM == PPC_ASM_ELF
|
||||
#define ALIGN(n,p) .align p
|
||||
#define DESCRIPTOR(x) \
|
||||
.section .descriptors,"aw"; \
|
||||
PUBLIC_VAR (x); \
|
||||
SYM (x):; \
|
||||
.long PROC (x); \
|
||||
.long s.got; \
|
||||
.long 0
|
||||
|
||||
#define EXT_SYM_REF(x) .long x
|
||||
#define EXT_PROC_REF(x) .long x
|
||||
|
||||
/*
|
||||
* Define macros to handle section beginning and ends.
|
||||
*/
|
||||
|
||||
#define BEGIN_CODE_DCL .text
|
||||
#define END_CODE_DCL
|
||||
#define BEGIN_DATA_DCL .data
|
||||
#define END_DATA_DCL
|
||||
#define BEGIN_CODE .text
|
||||
#define END_CODE
|
||||
#define BEGIN_DATA .data
|
||||
#define END_DATA
|
||||
#define BEGIN_BSS .bss
|
||||
#define END_BSS
|
||||
#define END
|
||||
|
||||
#elif PPC_ASM == PPC_ASM_XCOFF
|
||||
#define ALIGN(n,p) .align p
|
||||
#define DESCRIPTOR(x) \
|
||||
.csect x[DS]; \
|
||||
.globl x[DS]; \
|
||||
.long PROC (x)[PR]; \
|
||||
.long TOC[tc0]
|
||||
|
||||
#define EXT_SYM_REF(x) .long x[RW]
|
||||
#define EXT_PROC_REF(x) .long x[DS]
|
||||
|
||||
/*
|
||||
* Define macros to handle section beginning and ends.
|
||||
*/
|
||||
|
||||
#define BEGIN_CODE_DCL .csect .text[PR]
|
||||
#define END_CODE_DCL
|
||||
#define BEGIN_DATA_DCL .csect .data[RW]
|
||||
#define END_DATA_DCL
|
||||
#define BEGIN_CODE .csect .text[PR]
|
||||
#define END_CODE
|
||||
#define BEGIN_DATA .csect .data[RW]
|
||||
#define END_DATA
|
||||
#define BEGIN_BSS .bss
|
||||
#define END_BSS
|
||||
#define END
|
||||
|
||||
#else
|
||||
#error "PPC_ASM_TYPE is not properly defined"
|
||||
#endif
|
||||
#ifndef PPC_ASM
|
||||
#error "PPC_ASM_TYPE is not properly defined"
|
||||
#endif
|
||||
|
||||
|
||||
#endif
|
||||
/* end of include file */
|
||||
|
||||
|
||||
615
c/src/exec/score/cpu/powerpc/shared/ppc.h
Normal file
615
c/src/exec/score/cpu/powerpc/shared/ppc.h
Normal file
@@ -0,0 +1,615 @@
|
||||
/* ppc.h
|
||||
*
|
||||
* This file contains definitions for the IBM/Motorola PowerPC
|
||||
* family members.
|
||||
*
|
||||
* Author: Andrew Bray <andy@i-cubed.co.uk>
|
||||
*
|
||||
* COPYRIGHT (c) 1995 by i-cubed ltd.
|
||||
*
|
||||
* MPC860 support code was added by Jay Monkman <jmonkman@frasca.com>
|
||||
*
|
||||
* 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/no_cpu.h:
|
||||
*
|
||||
* COPYRIGHT (c) 1989-1997.
|
||||
* On-Line Applications Research Corporation (OAR).
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*
|
||||
* Note:
|
||||
* This file is included by both C and assembler code ( -DASM )
|
||||
*
|
||||
* $Id$
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _INCLUDE_PPC_h
|
||||
#define _INCLUDE_PPC_h
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Define the name of the CPU family.
|
||||
*/
|
||||
|
||||
#define CPU_NAME "PowerPC"
|
||||
|
||||
/*
|
||||
* This file contains the information required to build
|
||||
* RTEMS for a particular member of the PowerPC family. It does
|
||||
* this by setting variables to indicate which implementation
|
||||
* dependent features are present in a particular member
|
||||
* of the family.
|
||||
*
|
||||
* The following architectural feature definitions are defaulted
|
||||
* unless specifically set by the model definition:
|
||||
*
|
||||
* + PPC_DEBUG_MODEL - PPC_DEBUG_MODEL_STANDARD
|
||||
* + PPC_INTERRUPT_MAX - 16
|
||||
* + PPC_CACHE_ALIGNMENT - 32
|
||||
* + PPC_LOW_POWER_MODE - PPC_LOW_POWER_MODE_NONE
|
||||
* + PPC_HAS_EXCEPTION_PREFIX - 1
|
||||
* + PPC_HAS_FPU - 1
|
||||
* + PPC_HAS_DOUBLE - 1 if PPC_HAS_FPU,
|
||||
* - 0 otherwise
|
||||
* + PPC_USE_MULTIPLE - 0
|
||||
*/
|
||||
|
||||
/*
|
||||
* Define the debugging assistance models found in the PPC family.
|
||||
*
|
||||
* Standard: single step and branch trace
|
||||
* Single Step Only: single step only
|
||||
* IBM 4xx: debug exception
|
||||
*/
|
||||
|
||||
#define PPC_DEBUG_MODEL_STANDARD 1
|
||||
#define PPC_DEBUG_MODEL_SINGLE_STEP_ONLY 2
|
||||
#define PPC_DEBUG_MODEL_IBM4xx 3
|
||||
|
||||
/*
|
||||
* Define the low power mode models
|
||||
*
|
||||
* Standard: as defined for 603e
|
||||
* Nap Mode: nap mode only (604)
|
||||
* XXX 403GB, 603, 603e, 604, 821
|
||||
*/
|
||||
|
||||
#define PPC_LOW_POWER_MODE_NONE 0
|
||||
#define PPC_LOW_POWER_MODE_STANDARD 1
|
||||
|
||||
#if defined(ppc403)
|
||||
/*
|
||||
* IBM 403
|
||||
*
|
||||
* Developed for 403GA. Book checked for 403GB.
|
||||
*
|
||||
* Does not have user mode.
|
||||
*/
|
||||
|
||||
#define CPU_MODEL_NAME "PowerPC 403"
|
||||
#define PPC_ALIGNMENT 4
|
||||
#define PPC_CACHE_ALIGNMENT 16
|
||||
#define PPC_HAS_RFCI 1
|
||||
#define PPC_HAS_FPU 0
|
||||
#define PPC_USE_MULTIPLE 1
|
||||
#define PPC_I_CACHE 2048
|
||||
#define PPC_D_CACHE 1024
|
||||
|
||||
#define PPC_DEBUG_MODEL PPC_DEBUG_MODEL_IBM4xx
|
||||
#define PPC_HAS_EXCEPTION_PREFIX 0
|
||||
#define PPC_HAS_EVPR 1
|
||||
|
||||
#elif defined(ppc601)
|
||||
/*
|
||||
* Submitted with original port -- book checked only.
|
||||
*/
|
||||
|
||||
#define CPU_MODEL_NAME "PowerPC 601"
|
||||
|
||||
#define PPC_ALIGNMENT 8
|
||||
#define PPC_USE_MULTIPLE 1
|
||||
#define PPC_I_CACHE 0
|
||||
#define PPC_D_CACHE 32768
|
||||
|
||||
#define PPC_DEBUG_MODEL PPC_DEBUG_MODEL_SINGLE_STEP_ONLY
|
||||
|
||||
#elif defined(ppc602)
|
||||
/*
|
||||
* Submitted with original port -- book checked only.
|
||||
*/
|
||||
|
||||
#define CPU_MODEL_NAME "PowerPC 602"
|
||||
|
||||
#define PPC_ALIGNMENT 4
|
||||
#define PPC_HAS_DOUBLE 0
|
||||
#define PPC_I_CACHE 4096
|
||||
#define PPC_D_CACHE 4096
|
||||
|
||||
#elif defined(ppc603)
|
||||
/*
|
||||
* Submitted with original port -- book checked only.
|
||||
*/
|
||||
|
||||
#define CPU_MODEL_NAME "PowerPC 603"
|
||||
|
||||
#define PPC_ALIGNMENT 8
|
||||
#define PPC_I_CACHE 8192
|
||||
#define PPC_D_CACHE 8192
|
||||
|
||||
#elif defined(ppc603e)
|
||||
|
||||
#define CPU_MODEL_NAME "PowerPC 603e"
|
||||
/*
|
||||
* Submitted with original port.
|
||||
*
|
||||
* Known to work on real hardware.
|
||||
*/
|
||||
|
||||
#define PPC_ALIGNMENT 8
|
||||
#define PPC_I_CACHE 16384
|
||||
#define PPC_D_CACHE 16384
|
||||
|
||||
#define PPC_LOW_POWER_MODE PPC_LOW_POWER_MODE_STANDARD
|
||||
|
||||
#elif defined(ppc604)
|
||||
/*
|
||||
* Submitted with original port -- book checked only.
|
||||
*/
|
||||
|
||||
#define CPU_MODEL_NAME "PowerPC 604"
|
||||
|
||||
#define PPC_ALIGNMENT 8
|
||||
#define PPC_I_CACHE 16384
|
||||
#define PPC_D_CACHE 16384
|
||||
|
||||
#elif defined(mpc860)
|
||||
/*
|
||||
* Added by Jay Monkman (jmonkman@frasca.com) 6/28/98
|
||||
*/
|
||||
#define CPU_MODEL_NAME "PowerPC MPC860"
|
||||
|
||||
#define PPC_ALIGNMENT 4
|
||||
#define PPC_I_CACHE 4096
|
||||
#define PPC_D_CACHE 4096
|
||||
#define PPC_CACHE_ALIGNMENT 16
|
||||
#define PPC_INTERRUPT_MAX 71
|
||||
#define PPC_HAS_FPU 0
|
||||
#define PPC_HAS_DOUBLE 0
|
||||
#define PPC_USE_MULTIPLE 1
|
||||
#define PPC_USE_SPRG 1
|
||||
|
||||
#define PPC_MSR_0 0x00009000
|
||||
#define PPC_MSR_1 0x00001000
|
||||
#define PPC_MSR_2 0x00001000
|
||||
#define PPC_MSR_3 0x00000000
|
||||
|
||||
#elif defined(mpc821)
|
||||
/*
|
||||
* Added by Andrew Bray <andy@chaos.org.uk> 6/April/1999
|
||||
*/
|
||||
#define CPU_MODEL_NAME "PowerPC MPC821"
|
||||
|
||||
#define PPC_ALIGNMENT 4
|
||||
#define PPC_I_CACHE 4096
|
||||
#define PPC_D_CACHE 4096
|
||||
#define PPC_CACHE_ALIGNMENT 16
|
||||
#define PPC_INTERRUPT_MAX 71
|
||||
#define PPC_HAS_FPU 0
|
||||
#define PPC_HAS_DOUBLE 0
|
||||
|
||||
#define PPC_MSR_0 0x00009000
|
||||
#define PPC_MSR_1 0x00001000
|
||||
#define PPC_MSR_2 0x00001000
|
||||
#define PPC_MSR_3 0x00000000
|
||||
|
||||
#elif defined(mpc750)
|
||||
|
||||
#define CPU_MODEL_NAME "PowerPC 750"
|
||||
|
||||
#define PPC_ALIGNMENT 8
|
||||
#define PPC_I_CACHE 16384
|
||||
#define PPC_D_CACHE 16384
|
||||
|
||||
#else
|
||||
|
||||
#error "Unsupported CPU Model"
|
||||
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Application binary interfaces.
|
||||
*
|
||||
* PPC_ABI MUST be defined as one of these.
|
||||
* Only PPC_ABI_POWEROPEN is currently fully supported.
|
||||
* Only EABI will be supported in the end when
|
||||
* the tools are there.
|
||||
* Only big endian is currently supported.
|
||||
*/
|
||||
/*
|
||||
* PowerOpen ABI. This is Andy's hack of the
|
||||
* PowerOpen ABI to ELF. ELF rather than a
|
||||
* XCOFF assembler is used. This may work
|
||||
* if PPC_ASM == PPC_ASM_XCOFF is defined.
|
||||
*/
|
||||
#define PPC_ABI_POWEROPEN 0
|
||||
/*
|
||||
* GCC 2.7.0 munched version of EABI, with
|
||||
* PowerOpen calling convention and stack frames,
|
||||
* but EABI style indirect function calls.
|
||||
*/
|
||||
#define PPC_ABI_GCC27 1
|
||||
/*
|
||||
* SVR4 ABI
|
||||
*/
|
||||
#define PPC_ABI_SVR4 2
|
||||
/*
|
||||
* Embedded ABI
|
||||
*/
|
||||
#define PPC_ABI_EABI 3
|
||||
|
||||
#if (PPC_ABI == PPC_ABI_POWEROPEN)
|
||||
#define PPC_STACK_ALIGNMENT 8
|
||||
#elif (PPC_ABI == PPC_ABI_GCC27)
|
||||
#define PPC_STACK_ALIGNMENT 8
|
||||
#elif (PPC_ABI == PPC_ABI_SVR4)
|
||||
#define PPC_STACK_ALIGNMENT 16
|
||||
#elif (PPC_ABI == PPC_ABI_EABI)
|
||||
#define PPC_STACK_ALIGNMENT 8
|
||||
#else
|
||||
#error "PPC_ABI is not properly defined"
|
||||
#endif
|
||||
#ifndef PPC_ABI
|
||||
#error "PPC_ABI is not properly defined"
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Assemblers.
|
||||
* PPC_ASM MUST be defined as one of these.
|
||||
*
|
||||
* PPC_ASM_ELF: ELF assembler. Currently used for all ABIs.
|
||||
* PPC_ASM_XCOFF: XCOFF assembler. May be needed for PowerOpen ABI.
|
||||
*
|
||||
* NOTE: Only PPC_ABI_ELF is currently fully supported.
|
||||
*/
|
||||
|
||||
#define PPC_ASM_ELF 0
|
||||
#define PPC_ASM_XCOFF 1
|
||||
|
||||
/*
|
||||
* Use the default debug scheme defined in the architectural specification
|
||||
* if another model has not been specified.
|
||||
*/
|
||||
|
||||
#ifndef PPC_DEBUG_MODEL
|
||||
#define PPC_DEBUG_MODEL PPC_DEBUG_MODEL_STANDARD
|
||||
#endif
|
||||
|
||||
/*
|
||||
* If the maximum number of exception sources has not been defined,
|
||||
* then default it to 16.
|
||||
*/
|
||||
|
||||
#ifndef PPC_INTERRUPT_MAX
|
||||
#define PPC_INTERRUPT_MAX 16
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Unless specified otherwise, the cache line size is defaulted to 32.
|
||||
*
|
||||
* The derive the power of 2 the cache line is.
|
||||
*/
|
||||
|
||||
#ifndef PPC_CACHE_ALIGNMENT
|
||||
#define PPC_CACHE_ALIGNMENT 32
|
||||
#endif
|
||||
|
||||
#if (PPC_CACHE_ALIGNMENT == 16)
|
||||
#define PPC_CACHE_ALIGN_POWER 4
|
||||
#elif (PPC_CACHE_ALIGNMENT == 32)
|
||||
#define PPC_CACHE_ALIGN_POWER 5
|
||||
#else
|
||||
#error "Undefined power of 2 for PPC_CACHE_ALIGNMENT"
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Unless otherwise specified, assume the model has an IP/EP bit to
|
||||
* set the exception address prefix.
|
||||
*/
|
||||
|
||||
#ifndef PPC_HAS_EXCEPTION_PREFIX
|
||||
#define PPC_HAS_EXCEPTION_PREFIX 1
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Unless otherwise specified, assume the model does NOT have
|
||||
* 403 style EVPR register to set the exception address prefix.
|
||||
*/
|
||||
|
||||
#ifndef PPC_HAS_EVPR
|
||||
#define PPC_HAS_EVPR 0
|
||||
#endif
|
||||
|
||||
/*
|
||||
* If no low power mode model was specified, then assume there is none.
|
||||
*/
|
||||
|
||||
#ifndef PPC_LOW_POWER_MODE
|
||||
#define PPC_LOW_POWER_MODE PPC_LOW_POWER_MODE_NONE
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Unless specified above, then assume the model has FP support.
|
||||
*/
|
||||
|
||||
#ifndef PPC_HAS_FPU
|
||||
#define PPC_HAS_FPU 1
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Unless specified above, If the model has FP support, it is assumed to
|
||||
* support doubles (8-byte floating point numbers).
|
||||
*
|
||||
* If the model does NOT have FP support, then the model does
|
||||
* NOT have double length FP registers.
|
||||
*/
|
||||
|
||||
#ifndef PPC_HAS_DOUBLE
|
||||
#if (PPC_HAS_FPU)
|
||||
#define PPC_HAS_DOUBLE 1
|
||||
#else
|
||||
#define PPC_HAS_DOUBLE 0
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Unless specified above, then assume the model does NOT have critical
|
||||
* interrupt support.
|
||||
*/
|
||||
|
||||
#ifndef PPC_HAS_RFCI
|
||||
#define PPC_HAS_RFCI 0
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Unless specified above, do not use the load/store multiple instructions
|
||||
* in a context switch.
|
||||
*/
|
||||
|
||||
#ifndef PPC_USE_MULTIPLE
|
||||
#define PPC_USE_MULTIPLE 0
|
||||
#endif
|
||||
|
||||
/*
|
||||
* The following exceptions are not maskable, and are not
|
||||
* necessarily predictable, so cannot be offered to RTEMS:
|
||||
* Alignment exception - handled by the CPU module
|
||||
* Data exceptions.
|
||||
* Instruction exceptions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Base Interrupt vectors supported on all models.
|
||||
*/
|
||||
#define PPC_IRQ_SYSTEM_RESET 0 /* 0x00100 - System reset. */
|
||||
#define PPC_IRQ_MCHECK 1 /* 0x00200 - Machine check */
|
||||
#define PPC_IRQ_PROTECT 2 /* 0x00300 - Protection violation */
|
||||
#define PPC_IRQ_ISI 3 /* 0x00400 - Instruction Fetch error */
|
||||
#define PPC_IRQ_EXTERNAL 4 /* 0x00500 - External interrupt */
|
||||
#define PPC_IRQ_ALIGNMENT 5 /* 0X00600 - Alignment exception */
|
||||
#define PPC_IRQ_PROGRAM 6 /* 0x00700 - Program exception */
|
||||
#define PPC_IRQ_NOFP 7 /* 0x00800 - Floating point unavailable */
|
||||
#define PPC_IRQ_DECREMENTER 8 /* 0x00900 - Decrementer interrupt */
|
||||
#define PPC_IRQ_RESERVED_A 9 /* 0x00a00 - Implementation Reserved */
|
||||
#define PPC_IRQ_RESERVED_B 10 /* 0x00a00 - Implementation Reserved */
|
||||
#define PPC_IRQ_SCALL 11 /* 0x00c00 - System call */
|
||||
#define PPC_IRQ_TRACE 12 /* 0x00d00 - Trace Exception */
|
||||
#define PPC_IRQ_FP_ASST 13 /* ox00e00 - Floating point assist */
|
||||
#define PPC_STD_IRQ_LAST PPC_IRQ_FP_ASST
|
||||
|
||||
#define PPC_IRQ_FIRST PPC_IRQ_SYSTEM_RESET
|
||||
|
||||
#if defined(ppc403)
|
||||
|
||||
#define PPC_IRQ_CRIT PPC_IRQ_SYSTEM_RESET /*0x00100- Critical int. pin */
|
||||
#define PPC_IRQ_PIT (PPC_STD_IRQ_LAST+1) /*0x01000- Pgm interval timer*/
|
||||
#define PPC_IRQ_FIT (PPC_STD_IRQ_LAST+2) /*0x01010- Fixed int. timer */
|
||||
#define PPC_IRQ_WATCHDOG (PPC_STD_IRQ_LAST+3) /*0x01020- Watchdog timer */
|
||||
#define PPC_IRQ_DEBUG (PPC_STD_IRQ_LAST+4) /*0x02000- Debug exceptions */
|
||||
#define PPC_IRQ_LAST PPC_IRQ_DEBUG
|
||||
|
||||
#elif defined(ppc601)
|
||||
#define PPC_IRQ_TRACE (PPC_STD_IRQ_LAST+1) /*0x02000-Run/Trace Exception*/
|
||||
#define PPC_IRQ_LAST PPC_IRQ_TRACE
|
||||
|
||||
#elif defined(ppc602)
|
||||
#define PPC_IRQ_LAST (PPC_STD_IRQ_LAST)
|
||||
|
||||
#elif defined(ppc603)
|
||||
#define PPC_IRQ_TRANS_MISS (PPC_STD_IRQ_LAST+1) /*0x1000-Ins Translation Miss*/
|
||||
#define PPC_IRQ_DATA_LOAD (PPC_STD_IRQ_LAST+2) /*0x1100-Data Load Trans Miss*/
|
||||
#define PPC_IRQ_DATA_STORE (PPC_STD_IRQ_LAST+3) /*0x1200-Data Store Miss */
|
||||
#define PPC_IRQ_ADDR_BRK (PPC_STD_IRQ_LAST+4) /*0x1300-Instruction Bkpoint */
|
||||
#define PPC_IRQ_SYS_MGT (PPC_STD_IRQ_LAST+5) /*0x1400-System Management */
|
||||
#define PPC_IRQ_LAST PPC_IRQ_SYS_MGT
|
||||
|
||||
#elif defined(ppc603e)
|
||||
#define PPC_TLB_INST_MISS (PPC_STD_IRQ_LAST+1) /*0x1000-Instruction TLB Miss*/
|
||||
#define PPC_TLB_LOAD_MISS (PPC_STD_IRQ_LAST+2) /*0x1100-TLB miss on load */
|
||||
#define PPC_TLB_STORE_MISS (PPC_STD_IRQ_LAST+3) /*0x1200-TLB Miss on store */
|
||||
#define PPC_IRQ_ADDRBRK (PPC_STD_IRQ_LAST+4) /*0x1300-Instruct addr break */
|
||||
#define PPC_IRQ_SYS_MGT (PPC_STD_IRQ_LAST+5) /*0x1400-System Management */
|
||||
#define PPC_IRQ_LAST PPC_IRQ_SYS_MGT
|
||||
|
||||
|
||||
#elif defined(ppc604)
|
||||
#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_LAST PPC_IRQ_SYS_MGT
|
||||
|
||||
#elif defined(mpc860) || defined(mpc821)
|
||||
#define PPC_IRQ_EMULATE (PPC_STD_IRQ_LAST+1) /*0x1000-Software emulation */
|
||||
#define PPC_IRQ_INST_MISS (PPC_STD_IRQ_LAST+2) /*0x1100-Instruction TLB miss*/
|
||||
#define PPC_IRQ_DATA_MISS (PPC_STD_IRQ_LAST+3) /*0x1200-Data TLB miss */
|
||||
#define PPC_IRQ_INST_ERR (PPC_STD_IRQ_LAST+4) /*0x1300-Instruction TLB err */
|
||||
#define PPC_IRQ_DATA_ERR (PPC_STD_IRQ_LAST+5) /*0x1400-Data TLB error */
|
||||
#define PPC_IRQ_DATA_BPNT (PPC_STD_IRQ_LAST+6) /*0x1C00-Data breakpoint */
|
||||
#define PPC_IRQ_INST_BPNT (PPC_STD_IRQ_LAST+7) /*0x1D00-Inst breakpoint */
|
||||
#define PPC_IRQ_IO_BPNT (PPC_STD_IRQ_LAST+8) /*0x1E00-Peripheral breakpnt */
|
||||
#define PPC_IRQ_DEV_PORT (PPC_STD_IRQ_LAST+9) /*0x1F00-Development port */
|
||||
#define PPC_IRQ_IRQ0 (PPC_STD_IRQ_LAST + 10)
|
||||
#define PPC_IRQ_LVL0 (PPC_STD_IRQ_LAST + 11)
|
||||
#define PPC_IRQ_IRQ1 (PPC_STD_IRQ_LAST + 12)
|
||||
#define PPC_IRQ_LVL1 (PPC_STD_IRQ_LAST + 13)
|
||||
#define PPC_IRQ_IRQ2 (PPC_STD_IRQ_LAST + 14)
|
||||
#define PPC_IRQ_LVL2 (PPC_STD_IRQ_LAST + 15)
|
||||
#define PPC_IRQ_IRQ3 (PPC_STD_IRQ_LAST + 16)
|
||||
#define PPC_IRQ_LVL3 (PPC_STD_IRQ_LAST + 17)
|
||||
#define PPC_IRQ_IRQ4 (PPC_STD_IRQ_LAST + 18)
|
||||
#define PPC_IRQ_LVL4 (PPC_STD_IRQ_LAST + 19)
|
||||
#define PPC_IRQ_IRQ5 (PPC_STD_IRQ_LAST + 20)
|
||||
#define PPC_IRQ_LVL5 (PPC_STD_IRQ_LAST + 21)
|
||||
#define PPC_IRQ_IRQ6 (PPC_STD_IRQ_LAST + 22)
|
||||
#define PPC_IRQ_LVL6 (PPC_STD_IRQ_LAST + 23)
|
||||
#define PPC_IRQ_IRQ7 (PPC_STD_IRQ_LAST + 24)
|
||||
#define PPC_IRQ_LVL7 (PPC_STD_IRQ_LAST + 25)
|
||||
#define PPC_IRQ_CPM_RESERVED_0 (PPC_STD_IRQ_LAST + 26)
|
||||
#define PPC_IRQ_CPM_PC4 (PPC_STD_IRQ_LAST + 27)
|
||||
#define PPC_IRQ_CPM_PC5 (PPC_STD_IRQ_LAST + 28)
|
||||
#define PPC_IRQ_CPM_SMC2 (PPC_STD_IRQ_LAST + 29)
|
||||
#define PPC_IRQ_CPM_SMC1 (PPC_STD_IRQ_LAST + 30)
|
||||
#define PPC_IRQ_CPM_SPI (PPC_STD_IRQ_LAST + 31)
|
||||
#define PPC_IRQ_CPM_PC6 (PPC_STD_IRQ_LAST + 32)
|
||||
#define PPC_IRQ_CPM_TIMER4 (PPC_STD_IRQ_LAST + 33)
|
||||
#define PPC_IRQ_CPM_RESERVED_8 (PPC_STD_IRQ_LAST + 34)
|
||||
#define PPC_IRQ_CPM_PC7 (PPC_STD_IRQ_LAST + 35)
|
||||
#define PPC_IRQ_CPM_PC8 (PPC_STD_IRQ_LAST + 36)
|
||||
#define PPC_IRQ_CPM_PC9 (PPC_STD_IRQ_LAST + 37)
|
||||
#define PPC_IRQ_CPM_TIMER3 (PPC_STD_IRQ_LAST + 38)
|
||||
#define PPC_IRQ_CPM_RESERVED_D (PPC_STD_IRQ_LAST + 39)
|
||||
#define PPC_IRQ_CPM_PC10 (PPC_STD_IRQ_LAST + 40)
|
||||
#define PPC_IRQ_CPM_PC11 (PPC_STD_IRQ_LAST + 41)
|
||||
#define PPC_IRQ_CPM_I2C (PPC_STD_IRQ_LAST + 42)
|
||||
#define PPC_IRQ_CPM_RISC_TIMER (PPC_STD_IRQ_LAST + 43)
|
||||
#define PPC_IRQ_CPM_TIMER2 (PPC_STD_IRQ_LAST + 44)
|
||||
#define PPC_IRQ_CPM_RESERVED_13 (PPC_STD_IRQ_LAST + 45)
|
||||
#define PPC_IRQ_CPM_IDMA2 (PPC_STD_IRQ_LAST + 46)
|
||||
#define PPC_IRQ_CPM_IDMA1 (PPC_STD_IRQ_LAST + 47)
|
||||
#define PPC_IRQ_CPM_SDMA_ERROR (PPC_STD_IRQ_LAST + 48)
|
||||
#define PPC_IRQ_CPM_PC12 (PPC_STD_IRQ_LAST + 49)
|
||||
#define PPC_IRQ_CPM_PC13 (PPC_STD_IRQ_LAST + 50)
|
||||
#define PPC_IRQ_CPM_TIMER1 (PPC_STD_IRQ_LAST + 51)
|
||||
#define PPC_IRQ_CPM_PC14 (PPC_STD_IRQ_LAST + 52)
|
||||
#define PPC_IRQ_CPM_SCC4 (PPC_STD_IRQ_LAST + 53)
|
||||
#define PPC_IRQ_CPM_SCC3 (PPC_STD_IRQ_LAST + 54)
|
||||
#define PPC_IRQ_CPM_SCC2 (PPC_STD_IRQ_LAST + 55)
|
||||
#define PPC_IRQ_CPM_SCC1 (PPC_STD_IRQ_LAST + 56)
|
||||
#define PPC_IRQ_CPM_PC15 (PPC_STD_IRQ_LAST + 57)
|
||||
|
||||
#define PPC_IRQ_LAST PPC_IRQ_CPM_PC15
|
||||
|
||||
#endif
|
||||
|
||||
/*
|
||||
* If the maximum number of exception sources is too low,
|
||||
* then fix it
|
||||
*/
|
||||
|
||||
#if PPC_INTERRUPT_MAX <= PPC_IRQ_LAST
|
||||
#undef PPC_INTERRUPT_MAX
|
||||
#define PPC_INTERRUPT_MAX ((PPC_IRQ_LAST) + 1)
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Machine Status Register (MSR) Constants Used by RTEMS
|
||||
*/
|
||||
|
||||
/*
|
||||
* Some PPC model manuals refer to the Exception Prefix (EP) bit as
|
||||
* IP for no apparent reason.
|
||||
*/
|
||||
|
||||
#define PPC_MSR_RI 0x000000002 /* bit 30 - recoverable exception */
|
||||
#define PPC_MSR_DR 0x000000010 /* bit 27 - data address translation */
|
||||
#define PPC_MSR_IR 0x000000020 /* bit 26 - instruction addr translation*/
|
||||
|
||||
#if (PPC_HAS_EXCEPTION_PREFIX)
|
||||
#define PPC_MSR_EP 0x000000040 /* bit 25 - exception prefix */
|
||||
#else
|
||||
#define PPC_MSR_EP 0x000000000 /* bit 25 - exception prefix */
|
||||
#endif
|
||||
|
||||
#if (PPC_HAS_FPU)
|
||||
#define PPC_MSR_FP 0x000002000 /* bit 18 - floating point enable */
|
||||
#else
|
||||
#define PPC_MSR_FP 0x000000000 /* bit 18 - floating point enable */
|
||||
#endif
|
||||
|
||||
#if (PPC_LOW_POWER_MODE == PPC_LOW_POWER_MODE_NONE)
|
||||
#define PPC_MSR_POW 0x000000000 /* bit 13 - power management enable */
|
||||
#else
|
||||
#define PPC_MSR_POW 0x000040000 /* bit 13 - power management enable */
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Interrupt/exception MSR bits set as defined on p. 2-20 in "The Programming
|
||||
* Environments" and the manuals for various PPC models.
|
||||
*/
|
||||
|
||||
#if (PPC_DEBUG_MODEL == PPC_DEBUG_MODEL_STANDARD)
|
||||
#define PPC_MSR_DE 0x000000000 /* bit 22 - debug exception enable */
|
||||
#define PPC_MSR_BE 0x000000200 /* bit 22 - branch trace enable */
|
||||
#define PPC_MSR_SE 0x000000400 /* bit 21 - single step trace enable */
|
||||
#elif (PPC_DEBUG_MODEL == PPC_DEBUG_MODEL_SINGLE_STEP_ONLY)
|
||||
#define PPC_MSR_DE 0x000000000 /* bit 22 - debug exception enable */
|
||||
#define PPC_MSR_BE 0x000000200 /* bit 22 - branch trace enable */
|
||||
#define PPC_MSR_SE 0x000000000 /* bit 21 - single step trace enable */
|
||||
#elif (PPC_DEBUG_MODEL == PPC_DEBUG_MODEL_IBM4xx)
|
||||
#define PPC_MSR_DE 0x000000200 /* bit 22 - debug exception enable */
|
||||
#define PPC_MSR_BE 0x000000000 /* bit 22 - branch trace enable */
|
||||
#define PPC_MSR_SE 0x000000000 /* bit 21 - single step trace enable */
|
||||
#else
|
||||
#error "MSR constants -- unknown PPC_DEBUG_MODEL!!"
|
||||
#endif
|
||||
|
||||
#define PPC_MSR_ME 0x000001000 /* bit 19 - machine check enable */
|
||||
#define PPC_MSR_EE 0x000008000 /* bit 16 - external interrupt enable */
|
||||
|
||||
#if (PPC_HAS_RFCI)
|
||||
#define PPC_MSR_CE 0x000020000 /* bit 14 - critical interrupt enable */
|
||||
#else
|
||||
#define PPC_MSR_CE 0x000000000 /* bit 14 - critical interrupt enable */
|
||||
#endif
|
||||
|
||||
#define PPC_MSR_DISABLE_MASK (PPC_MSR_ME|PPC_MSR_EE|PPC_MSR_CE)
|
||||
|
||||
/*
|
||||
* Initial value for the FPSCR register
|
||||
*/
|
||||
|
||||
#define PPC_INIT_FPSCR 0x000000f8
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* ! _INCLUDE_PPC_h */
|
||||
/* end of include file */
|
||||
|
||||
|
||||
73
c/src/exec/score/cpu/powerpc/shared/ppctypes.h
Normal file
73
c/src/exec/score/cpu/powerpc/shared/ppctypes.h
Normal file
@@ -0,0 +1,73 @@
|
||||
/* ppctypes.h
|
||||
*
|
||||
* This include file contains type definitions pertaining to the PowerPC
|
||||
* processor family.
|
||||
*
|
||||
* 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/no_cputypes.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 in
|
||||
* the file LICENSE in this distribution or at
|
||||
* http://www.OARcorp.com/rtems/license.html.
|
||||
*
|
||||
* $Id$
|
||||
*/
|
||||
|
||||
#ifndef __PPC_TYPES_h
|
||||
#define __PPC_TYPES_h
|
||||
|
||||
#ifndef ASM
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*
|
||||
* This section defines the basic types for this processor.
|
||||
*/
|
||||
|
||||
typedef unsigned char unsigned8; /* unsigned 8-bit integer */
|
||||
typedef unsigned short unsigned16; /* unsigned 16-bit integer */
|
||||
typedef unsigned int unsigned32; /* unsigned 32-bit integer */
|
||||
typedef unsigned long long unsigned64; /* unsigned 64-bit integer */
|
||||
|
||||
typedef unsigned32 Priority_Bit_map_control;
|
||||
|
||||
typedef signed char signed8; /* 8-bit signed integer */
|
||||
typedef signed short signed16; /* 16-bit signed integer */
|
||||
typedef signed int signed32; /* 32-bit signed integer */
|
||||
typedef signed long long signed64; /* 64 bit signed integer */
|
||||
|
||||
typedef unsigned32 boolean; /* Boolean value */
|
||||
|
||||
typedef float single_precision; /* single precision float */
|
||||
typedef double double_precision; /* double precision float */
|
||||
|
||||
typedef void ppc_isr;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* !ASM */
|
||||
|
||||
#endif
|
||||
/* end of include file */
|
||||
@@ -82,7 +82,7 @@ SCORE_EXTERN boolean _ISR_Signals_to_thread_executing;
|
||||
* When this variable is zero, a thread is executing.
|
||||
*/
|
||||
|
||||
SCORE_EXTERN unsigned32 _ISR_Nest_level;
|
||||
SCORE_EXTERN volatile unsigned32 _ISR_Nest_level;
|
||||
|
||||
/*
|
||||
* The following declares the Vector Table. Application
|
||||
|
||||
@@ -234,7 +234,7 @@ SCORE_EXTERN Context_Control _Thread_BSP_context;
|
||||
* moments.
|
||||
*/
|
||||
|
||||
SCORE_EXTERN unsigned32 _Thread_Dispatch_disable_level;
|
||||
SCORE_EXTERN volatile unsigned32 _Thread_Dispatch_disable_level;
|
||||
|
||||
/*
|
||||
* If this is non-zero, then the post-task switch extension
|
||||
|
||||
@@ -29,10 +29,19 @@
|
||||
* directives available to an interrupt service routine are restricted.
|
||||
*/
|
||||
|
||||
#if defined(powerpc)
|
||||
#define CPU_PROVIDES_ISR_IS_IN_PROGRESS
|
||||
#endif
|
||||
|
||||
#ifndef CPU_PROVIDES_ISR_IS_IN_PROGRESS
|
||||
|
||||
RTEMS_INLINE_ROUTINE boolean _ISR_Is_in_progress( void )
|
||||
{
|
||||
return (_ISR_Nest_level != 0);
|
||||
}
|
||||
#else
|
||||
#include <rtems/score/c_isr.inl>
|
||||
#endif
|
||||
|
||||
/*PAGE
|
||||
*
|
||||
|
||||
@@ -346,7 +346,7 @@ int BSP_rtems_irq_mngt_set(rtems_irq_global_settings* config)
|
||||
}
|
||||
}
|
||||
/*
|
||||
* must disable slave pic anyway
|
||||
* must enable slave pic anyway
|
||||
*/
|
||||
BSP_irq_enable_at_i8259s (2);
|
||||
_CPU_ISR_Enable(level);
|
||||
@@ -374,6 +374,6 @@ void _ThreadProcessSignalsFromIrq (CPU_Exception_frame* ctx)
|
||||
}
|
||||
/*
|
||||
* I plan to process other thread related events here.
|
||||
* This will include DEBUG session requsted from keyboard...
|
||||
* This will include DEBUG session requested from keyboard...
|
||||
*/
|
||||
}
|
||||
|
||||
@@ -93,7 +93,7 @@ static rtems_irq_prio irqPrioTable[BSP_IRQ_LINES_NUMBER]={
|
||||
* 255 means all other interrupts are masked
|
||||
* The second entry has a priority of 255 because
|
||||
* it is the slave pic entry and is should always remain
|
||||
* unamsked.
|
||||
* unmasked.
|
||||
*/
|
||||
0,0,
|
||||
255,
|
||||
|
||||
20
c/src/lib/libbsp/powerpc/mcp750/Makefile.in
Normal file
20
c/src/lib/libbsp/powerpc/mcp750/Makefile.in
Normal file
@@ -0,0 +1,20 @@
|
||||
#
|
||||
# $Id$
|
||||
#
|
||||
|
||||
@SET_MAKE@
|
||||
srcdir = @srcdir@
|
||||
VPATH = @srcdir@
|
||||
RTEMS_ROOT = @top_srcdir@
|
||||
PROJECT_ROOT = @PROJECT_ROOT@
|
||||
|
||||
include $(RTEMS_ROOT)/make/custom/$(RTEMS_BSP).cfg
|
||||
include $(RTEMS_ROOT)/make/directory.cfg
|
||||
|
||||
SRCS=README
|
||||
|
||||
all: $(SRCS)
|
||||
|
||||
# wrapup is the one that actually builds and installs the library
|
||||
# from the individual .rel files built in other directories
|
||||
SUB_DIRS= console include pci residual openpic irq vectors start startup bootloader wrapup
|
||||
48
c/src/lib/libbsp/powerpc/mcp750/README
Normal file
48
c/src/lib/libbsp/powerpc/mcp750/README
Normal file
@@ -0,0 +1,48 @@
|
||||
#
|
||||
# $Id$
|
||||
#
|
||||
|
||||
BSP NAME: MCP750
|
||||
BOARD: MCP750 from motorola
|
||||
BUS: PCI
|
||||
CPU FAMILY: ppc
|
||||
CPU: PowerPC 750
|
||||
COPROCESSORS: N/A
|
||||
MODE: 32 bit mode
|
||||
|
||||
DEBUG MONITOR: PPCBUG mode
|
||||
|
||||
PERIPHERALS
|
||||
===========
|
||||
TIMERS: PPC internal Timebase register
|
||||
RESOLUTION: ???
|
||||
SERIAL PORTS: simulated via bug
|
||||
REAL-TIME CLOCK: PPC internal Decrementer register
|
||||
DMA: none
|
||||
VIDEO: none
|
||||
SCSI: none
|
||||
NETWORKING: DEC21140
|
||||
|
||||
DRIVER INFORMATION
|
||||
==================
|
||||
CLOCK DRIVER: PPC internal
|
||||
IOSUPP DRIVER: N/A
|
||||
SHMSUPP: N/A
|
||||
TIMER DRIVER: PPC internal
|
||||
TTY DRIVER: PPC internal
|
||||
|
||||
STDIO
|
||||
=====
|
||||
PORT: Console port 0
|
||||
ELECTRICAL: na
|
||||
BAUD: na
|
||||
BITS PER CHARACTER: na
|
||||
PARITY: na
|
||||
STOP BITS: na
|
||||
|
||||
Notes
|
||||
=====
|
||||
|
||||
Based on papyrus bsp which only really supports
|
||||
the PowerOpen ABI with an ELF assembler.
|
||||
|
||||
84
c/src/lib/libbsp/powerpc/mcp750/bootloader/Makefile.in
Normal file
84
c/src/lib/libbsp/powerpc/mcp750/bootloader/Makefile.in
Normal file
@@ -0,0 +1,84 @@
|
||||
#
|
||||
# $Id:
|
||||
#
|
||||
|
||||
@SET_MAKE@
|
||||
srcdir = @srcdir@
|
||||
VPATH = @srcdir@:@srcdir@/../../../shared:@srcdir@/../console
|
||||
RTEMS_ROOT = @top_srcdir@
|
||||
PROJECT_ROOT = @PROJECT_ROOT@
|
||||
|
||||
# C source names, if any, go here -- minus the .c
|
||||
C_PIECES=misc pci zlib mm em86 polled_io
|
||||
C_FILES=$(C_PIECES:%=%.c)
|
||||
C_O_FILES=$(C_PIECES:%=${ARCH}/%.o)
|
||||
|
||||
H_FILES=bootldr.h zlib.h pci.h
|
||||
|
||||
# Assembly source names, if any, go here -- minus the .s
|
||||
S_PIECES=head exception em86real consoleLib
|
||||
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
|
||||
|
||||
CC_PIECES=
|
||||
CC_FILES=$(CC_PIECES:%=%.cc)
|
||||
CC_O_FILES=$(CC_PIECES:%=${ARCH}/%.o)
|
||||
|
||||
|
||||
#
|
||||
# (OPTIONAL) Add local stuff here using +=
|
||||
#
|
||||
|
||||
DEFINES +=
|
||||
CPPFLAGS += -D__BOOT__ -DDEBUG
|
||||
CFLAGS += -msoft-float -mstrict-align -fno-builtin -Wall -mmultiple -mstring \
|
||||
-O2 -fomit-frame-pointer -mrelocatable -ffixed-r13 \
|
||||
-mno-sdata -D__BOOT__ -DDEBUG
|
||||
|
||||
ASFLAGS += -mrelocatable
|
||||
|
||||
LD_PATHS +=
|
||||
LD_LIBS +=
|
||||
LDFLAGS +=
|
||||
|
||||
IMAGES := rtems.gz
|
||||
|
||||
#
|
||||
# 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 += bootloader
|
||||
CLOBBER_ADDITIONS += $(IMAGES)
|
||||
|
||||
bootloader : ${OBJS} $(IMAGES) $(BINARY_LOADED) ppcboot.lds
|
||||
$(LD) -o bootloader $(OBJS) --just-symbols=$(BINARY_LOADED) \
|
||||
-b binary $(IMAGES) -T @srcdir@/ppcboot.lds \
|
||||
-Map bootloader.map
|
||||
|
||||
rtems.gz: $(BINARY_LOADED)
|
||||
$(OBJCOPY) $(BINARY_LOADED) rtems -O binary -R .comment -S
|
||||
gzip -vf9 rtems
|
||||
rm -f rtems
|
||||
|
||||
|
||||
all: ${ARCH} $(SRCS) ${OBJ}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
251
c/src/lib/libbsp/powerpc/mcp750/bootloader/bootldr.h
Normal file
251
c/src/lib/libbsp/powerpc/mcp750/bootloader/bootldr.h
Normal file
@@ -0,0 +1,251 @@
|
||||
/*
|
||||
* include/asm-ppc/bloader.h -- Include file for bootloader.
|
||||
*
|
||||
* Copyright (C) 1998 Gabriel Paubert, paubert@iram.es
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#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
|
||||
|
||||
|
||||
|
||||
563
c/src/lib/libbsp/powerpc/mcp750/bootloader/em86.c
Normal file
563
c/src/lib/libbsp/powerpc/mcp750/bootloader/em86.c
Normal file
@@ -0,0 +1,563 @@
|
||||
/*****************************************************************************
|
||||
*
|
||||
* 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);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
4554
c/src/lib/libbsp/powerpc/mcp750/bootloader/em86real.S
Normal file
4554
c/src/lib/libbsp/powerpc/mcp750/bootloader/em86real.S
Normal file
File diff suppressed because it is too large
Load Diff
466
c/src/lib/libbsp/powerpc/mcp750/bootloader/exception.S
Normal file
466
c/src/lib/libbsp/powerpc/mcp750/bootloader/exception.S
Normal file
@@ -0,0 +1,466 @@
|
||||
/*
|
||||
* arch/ppc/loader/exceotion.S -- Exception handlers for early boot.
|
||||
*
|
||||
* Copyright (C) 1998 Gabriel Paubert, paubert@iram.es
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/* 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
|
||||
379
c/src/lib/libbsp/powerpc/mcp750/bootloader/head.S
Normal file
379
c/src/lib/libbsp/powerpc/mcp750/bootloader/head.S
Normal file
@@ -0,0 +1,379 @@
|
||||
/*
|
||||
* $Id$
|
||||
*
|
||||
* This code is loaded by the ROM loader at some arbitrary location.
|
||||
* Move it to high memory so that it can load the kernel at 0x0000.
|
||||
*
|
||||
*/
|
||||
|
||||
#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
|
||||
|
||||
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: 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
|
||||
1: mfmsr r10
|
||||
ori r10,r10,MSR_IP
|
||||
mtmsr r10
|
||||
li r10,0x63
|
||||
sc
|
||||
#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
|
||||
/* A few utility functions, some copied from arch/ppc/lib/string.S */
|
||||
|
||||
#if 0
|
||||
.globl strnlen
|
||||
.type strnlen,@function
|
||||
strnlen:
|
||||
addi r4,r4,1
|
||||
mtctr r4
|
||||
addi r4,r3,-1
|
||||
1: lbzu r0,1(r4)
|
||||
cmpwi 0,r0,0
|
||||
bdnzf eq,1b
|
||||
subf r3,r3,r4
|
||||
blr
|
||||
#endif
|
||||
.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
|
||||
525
c/src/lib/libbsp/powerpc/mcp750/bootloader/misc.c
Normal file
525
c/src/lib/libbsp/powerpc/mcp750/bootloader/misc.c
Normal file
@@ -0,0 +1,525 @@
|
||||
/*
|
||||
* arch/ppc/prepboot/misc.c
|
||||
*
|
||||
* Copyright (C) 1998 Gabriel Paubert, paubert@iram.es
|
||||
*
|
||||
* This file is based on arch/ppc/boot misc.c in previous versions of
|
||||
* Linux/PPC but has been so extensively changed that only a few lines
|
||||
* remain from the original.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#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);
|
||||
}
|
||||
975
c/src/lib/libbsp/powerpc/mcp750/bootloader/mm.c
Normal file
975
c/src/lib/libbsp/powerpc/mcp750/bootloader/mm.c
Normal file
@@ -0,0 +1,975 @@
|
||||
/*
|
||||
* arch/ppc/prepboot/mm.c -- Crude memory management for early boot.
|
||||
*
|
||||
* Copyright (C) 1998 Gabriel Paubert, paubert@iram.es
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/* 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
|
||||
928
c/src/lib/libbsp/powerpc/mcp750/bootloader/pci.c
Normal file
928
c/src/lib/libbsp/powerpc/mcp750/bootloader/pci.c
Normal file
@@ -0,0 +1,928 @@
|
||||
/*
|
||||
* arch/ppc/prepboot/pci.c -- Crude pci handling for early boot.
|
||||
*
|
||||
* Copyright (C) 1998 Gabriel Paubert, paubert@iram.es
|
||||
*
|
||||
* The pci_scan_bus and pci_read_bases functions are slightly modified
|
||||
* versions of functions with the same name in linux/drivers/pci.c by
|
||||
* Martin Mares (mj@ucw.cz) and others (taken around linux-2.1.120).
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
|
||||
#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");
|
||||
}
|
||||
|
||||
1159
c/src/lib/libbsp/powerpc/mcp750/bootloader/pci.h
Normal file
1159
c/src/lib/libbsp/powerpc/mcp750/bootloader/pci.h
Normal file
File diff suppressed because it is too large
Load Diff
94
c/src/lib/libbsp/powerpc/mcp750/bootloader/ppcboot.lds
Normal file
94
c/src/lib/libbsp/powerpc/mcp750/bootloader/ppcboot.lds
Normal 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)
|
||||
}
|
||||
}
|
||||
|
||||
2143
c/src/lib/libbsp/powerpc/mcp750/bootloader/zlib.c
Normal file
2143
c/src/lib/libbsp/powerpc/mcp750/bootloader/zlib.c
Normal file
File diff suppressed because it is too large
Load Diff
438
c/src/lib/libbsp/powerpc/mcp750/bootloader/zlib.h
Normal file
438
c/src/lib/libbsp/powerpc/mcp750/bootloader/zlib.h
Normal 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 */
|
||||
23
c/src/lib/libbsp/powerpc/mcp750/bsp_specs
Normal file
23
c/src/lib/libbsp/powerpc/mcp750/bsp_specs
Normal file
@@ -0,0 +1,23 @@
|
||||
%rename cpp old_cpp
|
||||
%rename lib old_lib
|
||||
%rename endfile old_endfile
|
||||
%rename startfile old_startfile
|
||||
%rename link old_link
|
||||
|
||||
*cpp:
|
||||
%(old_cpp) %{qrtems: -D__embedded__} -Asystem(embedded)
|
||||
|
||||
*lib:
|
||||
%{!qrtems: %(old_lib)} %{qrtems: --start-group \
|
||||
%{!qrtems_debug: -lrtemsall} %{qrtems_debug: -lrtemsall_g} \
|
||||
-lc -lgcc --end-group ecrtn%O%s \
|
||||
%{!qnolinkcmds: -T linkcmds%s}}
|
||||
|
||||
*startfile:
|
||||
%{!qrtems: %(old_startfile)} %{qrtems: ecrti%O%s \
|
||||
%{!qrtems_debug: start.o%s} \
|
||||
%{qrtems_debug: start_g.o%s}}
|
||||
|
||||
*link:
|
||||
%{!qrtems: %(old_link)} %{qrtems: -Qy -dp -Bstatic -T linkcmds%s -e __rtems_entry_point -u __vectors}
|
||||
|
||||
63
c/src/lib/libbsp/powerpc/mcp750/console/Makefile.in
Normal file
63
c/src/lib/libbsp/powerpc/mcp750/console/Makefile.in
Normal file
@@ -0,0 +1,63 @@
|
||||
#
|
||||
# $Id:
|
||||
#
|
||||
|
||||
@SET_MAKE@
|
||||
srcdir = @srcdir@
|
||||
VPATH = @srcdir@:@srcdir@/../../../shared
|
||||
RTEMS_ROOT = @top_srcdir@
|
||||
PROJECT_ROOT = @PROJECT_ROOT@
|
||||
|
||||
INSTALL = @INSTALL@
|
||||
|
||||
# C source names, if any, go here -- minus the .c
|
||||
C_PIECES=polled_io uart console inch
|
||||
C_FILES=$(C_PIECES:%=%.c)
|
||||
C_O_FILES=$(C_PIECES:%=${ARCH}/%.o)
|
||||
|
||||
H_FILES=$(srcdir)/consoleIo.h $(srcdir)/keyboard.h $(srcdir)/uart.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
|
||||
|
||||
CC_PIECES=
|
||||
CC_FILES=$(CC_PIECES:%=%.cc)
|
||||
CC_O_FILES=$(CC_PIECES:%=${ARCH}/%.o)
|
||||
|
||||
|
||||
#
|
||||
# (OPTIONAL) Add local stuff here using +=
|
||||
#
|
||||
|
||||
CPPFLAGS += -DSTATIC_LOG_ALLOC
|
||||
#
|
||||
# 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:
|
||||
$(MKDIR) $(PROJECT_INCLUDE)/bsp
|
||||
$(INSTALL_CHANGE) -m 444 $(H_FILES) $(PROJECT_INCLUDE)/bsp
|
||||
|
||||
all: ${ARCH} $(SRCS) preinstall ${OBJS}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
398
c/src/lib/libbsp/powerpc/mcp750/console/console.c
Normal file
398
c/src/lib/libbsp/powerpc/mcp750/console/console.c
Normal file
@@ -0,0 +1,398 @@
|
||||
/*-------------------------------------------------------------------------+
|
||||
| console.c v1.1 - PC386 BSP - 1997/08/07
|
||||
+--------------------------------------------------------------------------+
|
||||
| This file contains the PC386 console I/O package.
|
||||
+--------------------------------------------------------------------------+
|
||||
| (C) Copyright 1997 -
|
||||
| - NavIST Group - Real-Time Distributed Systems and Industrial Automation
|
||||
|
|
||||
| http://pandora.ist.utl.pt
|
||||
|
|
||||
| Instituto Superior Tecnico * Lisboa * PORTUGAL
|
||||
+--------------------------------------------------------------------------+
|
||||
| Disclaimer:
|
||||
|
|
||||
| This file is provided "AS IS" without warranty of any kind, either
|
||||
| expressed or implied.
|
||||
+--------------------------------------------------------------------------+
|
||||
| This code is based on:
|
||||
| console.c,v 1.4 1995/12/19 20:07:23 joel Exp - go32 BSP
|
||||
| With the following copyright notice:
|
||||
| **************************************************************************
|
||||
| * COPYRIGHT (c) 1989-1998.
|
||||
| * 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 found in the file LICENSE in this distribution or at
|
||||
| * http://www.OARcorp.com/rtems/license.html.
|
||||
| **************************************************************************
|
||||
|
|
||||
| $Id$
|
||||
+--------------------------------------------------------------------------*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
#undef __assert
|
||||
void __assert (const char *file, int line, const char *msg);
|
||||
|
||||
#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;
|
||||
|
||||
/*-------------------------------------------------------------------------+
|
||||
| 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_open_count = 0;
|
||||
|
||||
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)
|
||||
{
|
||||
rtems_libio_rw_args_t *rw_args = (rtems_libio_rw_args_t *)arg;
|
||||
char *buffer = rw_args->buffer;
|
||||
int count, maximum = rw_args->count;
|
||||
|
||||
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)
|
||||
{
|
||||
rtems_libio_rw_args_t *rw_args = (rtems_libio_rw_args_t *)arg;
|
||||
char *buffer = rw_args->buffer;
|
||||
int count, maximum = rw_args->count;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
33
c/src/lib/libbsp/powerpc/mcp750/console/consoleIo.h
Normal file
33
c/src/lib/libbsp/powerpc/mcp750/console/consoleIo.h
Normal file
@@ -0,0 +1,33 @@
|
||||
#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
|
||||
23
c/src/lib/libbsp/powerpc/mcp750/console/consoleLib.S
Normal file
23
c/src/lib/libbsp/powerpc/mcp750/console/consoleLib.S
Normal file
@@ -0,0 +1,23 @@
|
||||
/*
|
||||
* $Id$
|
||||
*
|
||||
* This code is loaded by the ROM loader at some arbitrary location.
|
||||
* Move it to high memory so that it can load the kernel at 0x0000.
|
||||
*
|
||||
*/
|
||||
/* A few utility functions, some copied from arch/ppc/lib/string.S */
|
||||
#include <libcpu/cpu.h>
|
||||
#include <rtems/score/targopts.h>
|
||||
#include "asm.h"
|
||||
|
||||
.text
|
||||
|
||||
.globl strlen
|
||||
.type strlen,@function
|
||||
strlen:
|
||||
addi r4,r3,-1
|
||||
1: lbzu r0,1(r4)
|
||||
cmpwi 0,r0,0
|
||||
bne 1b
|
||||
subf r3,r3,r4
|
||||
blr
|
||||
333
c/src/lib/libbsp/powerpc/mcp750/console/inch.c
Normal file
333
c/src/lib/libbsp/powerpc/mcp750/console/inch.c
Normal file
@@ -0,0 +1,333 @@
|
||||
/*-------------------------------------------------------------------------+
|
||||
| inch.c v1.1 - PC386 BSP - 1997/08/07
|
||||
+--------------------------------------------------------------------------+
|
||||
| (C) Copyright 1997 -
|
||||
| - NavIST Group - Real-Time Distributed Systems and Industrial Automation
|
||||
|
|
||||
| http://pandora.ist.utl.pt
|
||||
|
|
||||
| Instituto Superior Tecnico * Lisboa * PORTUGAL
|
||||
+--------------------------------------------------------------------------+
|
||||
| Disclaimer:
|
||||
|
|
||||
| This file is provided "AS IS" without warranty of any kind, either
|
||||
| expressed or implied.
|
||||
+--------------------------------------------------------------------------+
|
||||
| This code is based on:
|
||||
| inch.c,v 1.3 1995/12/19 20:07:25 joel Exp - go32 BSP
|
||||
| With the following copyright notice:
|
||||
| With the following copyright notice:
|
||||
| **************************************************************************
|
||||
| * COPYRIGHT (c) 1989-1998.
|
||||
| * 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 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)
|
||||
{
|
||||
/* FIX ME!!! It doesn't work without something like the following line.
|
||||
Find out why! */
|
||||
printk("");
|
||||
|
||||
/* 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 */
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
421
c/src/lib/libbsp/powerpc/mcp750/console/keyboard.h
Normal file
421
c/src/lib/libbsp/powerpc/mcp750/console/keyboard.h
Normal file
@@ -0,0 +1,421 @@
|
||||
#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
|
||||
1098
c/src/lib/libbsp/powerpc/mcp750/console/polled_io.c
Normal file
1098
c/src/lib/libbsp/powerpc/mcp750/console/polled_io.c
Normal file
File diff suppressed because it is too large
Load Diff
778
c/src/lib/libbsp/powerpc/mcp750/console/uart.c
Normal file
778
c/src/lib/libbsp/powerpc/mcp750/console/uart.c
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
169
c/src/lib/libbsp/powerpc/mcp750/console/uart.h
Normal file
169
c/src/lib/libbsp/powerpc/mcp750/console/uart.h
Normal 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 */
|
||||
|
||||
|
||||
|
||||
35
c/src/lib/libbsp/powerpc/mcp750/include/Makefile.in
Normal file
35
c/src/lib/libbsp/powerpc/mcp750/include/Makefile.in
Normal file
@@ -0,0 +1,35 @@
|
||||
#
|
||||
# $Id$
|
||||
#
|
||||
|
||||
@SET_MAKE@
|
||||
srcdir = @srcdir@
|
||||
VPATH = @srcdir@
|
||||
RTEMS_ROOT = @top_srcdir@
|
||||
PROJECT_ROOT = @PROJECT_ROOT@
|
||||
|
||||
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
|
||||
|
||||
CLEAN_ADDITIONS +=
|
||||
CLOBBER_ADDITIONS +=
|
||||
|
||||
preinstall:
|
||||
$(MKDIR) $(PROJECT_INCLUDE)/bsp
|
||||
$(INSTALL_CHANGE) -m 444 $(H_FILES) $(PROJECT_INCLUDE)
|
||||
|
||||
all: $(SRCS) preinstall
|
||||
45
c/src/lib/libbsp/powerpc/mcp750/include/bsp.h
Normal file
45
c/src/lib/libbsp/powerpc/mcp750/include/bsp.h
Normal file
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* empty file. Just because referenced by portable application layer.
|
||||
*/
|
||||
#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>
|
||||
|
||||
#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 int printk(const char *, ...) __attribute__((format(printf, 1, 2)));
|
||||
#endif
|
||||
|
||||
#endif
|
||||
166
c/src/lib/libbsp/powerpc/mcp750/include/nvram.h
Normal file
166
c/src/lib/libbsp/powerpc/mcp750/include/nvram.h
Normal file
@@ -0,0 +1,166 @@
|
||||
/*
|
||||
* PreP compliant NVRAM access
|
||||
*/
|
||||
|
||||
#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 */
|
||||
59
c/src/lib/libbsp/powerpc/mcp750/irq/Makefile.in
Normal file
59
c/src/lib/libbsp/powerpc/mcp750/irq/Makefile.in
Normal file
@@ -0,0 +1,59 @@
|
||||
#
|
||||
# $Id$
|
||||
#
|
||||
|
||||
@SET_MAKE@
|
||||
srcdir = @srcdir@
|
||||
VPATH = @srcdir@
|
||||
RTEMS_ROOT = @top_srcdir@
|
||||
PROJECT_ROOT = @PROJECT_ROOT@
|
||||
|
||||
INSTALL = @INSTALL@
|
||||
|
||||
# C source names, if any, go here -- minus the .c
|
||||
C_PIECES=irq_init i8259 irq
|
||||
C_FILES=$(C_PIECES:%=%.c)
|
||||
C_O_FILES=$(C_PIECES:%=${ARCH}/%.o)
|
||||
|
||||
H_FILES=$(srcdir)/irq.h
|
||||
|
||||
# Assembly source names, if any, go here -- minus the .s
|
||||
S_PIECES=irq_asm
|
||||
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) $(CC_O_FILES)
|
||||
|
||||
include $(RTEMS_ROOT)/make/custom/$(RTEMS_BSP).cfg
|
||||
include $(RTEMS_ROOT)/make/leaf.cfg
|
||||
|
||||
#
|
||||
# (OPTIONAL) Add local stuff here using +=
|
||||
#
|
||||
|
||||
DEFINES +=
|
||||
CPPFLAGS +=
|
||||
CFLAGS +=
|
||||
|
||||
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 +=
|
||||
|
||||
preinstall:
|
||||
$(MKDIR) $(PROJECT_INCLUDE)/bsp
|
||||
$(INSTALL_CHANGE) -m 444 $(H_FILES) $(PROJECT_INCLUDE)/bsp
|
||||
|
||||
all: ${ARCH} $(SRCS) preinstall ${OBJS}
|
||||
|
||||
install: all
|
||||
152
c/src/lib/libbsp/powerpc/mcp750/irq/i8259.c
Normal file
152
c/src/lib/libbsp/powerpc/mcp750/irq/i8259.c
Normal file
@@ -0,0 +1,152 @@
|
||||
/* i8259.c
|
||||
*
|
||||
* This file contains the implementation of the function described in irq.h
|
||||
* related to Intel 8259 Programmable Interrupt controller.
|
||||
*
|
||||
* CopyRight (C) 1998 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.
|
||||
* This cache is initialized in ldseg.s
|
||||
*/
|
||||
volatile rtems_i8259_masks i8259s_cache;
|
||||
|
||||
/*-------------------------------------------------------------------------+
|
||||
| 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_SLAVE_COMMAND_IO_PORT, PIC_EOI);
|
||||
}
|
||||
outport_byte(PIC_MASTER_COMMAND_IO_PORT, PIC_EOI);
|
||||
|
||||
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 */
|
||||
|
||||
i8259s_cache = 0xFFFB;
|
||||
}
|
||||
|
||||
399
c/src/lib/libbsp/powerpc/mcp750/irq/irq.c
Normal file
399
c/src/lib/libbsp/powerpc/mcp750/irq/irq.c
Normal file
@@ -0,0 +1,399 @@
|
||||
/* irq.c
|
||||
*
|
||||
* This file contains the implementation of the function described in irq.h
|
||||
*
|
||||
* CopyRight (C) 1998 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/processor.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 (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...
|
||||
*/
|
||||
}
|
||||
318
c/src/lib/libbsp/powerpc/mcp750/irq/irq.h
Normal file
318
c/src/lib/libbsp/powerpc/mcp750/irq/irq.h
Normal file
@@ -0,0 +1,318 @@
|
||||
/* 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 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
|
||||
308
c/src/lib/libbsp/powerpc/mcp750/irq/irq_asm.S
Normal file
308
c/src/lib/libbsp/powerpc/mcp750/irq/irq_asm.S
Normal file
@@ -0,0 +1,308 @@
|
||||
/*
|
||||
* (c) 1999, Eric Valette valette@crf.canon.fr
|
||||
*
|
||||
*
|
||||
* This file contains the assembly code for the PowerPC
|
||||
* IRQ veneers for RTEMS.
|
||||
*
|
||||
* $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
|
||||
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
|
||||
|
||||
288
c/src/lib/libbsp/powerpc/mcp750/irq/irq_init.c
Normal file
288
c/src/lib/libbsp/powerpc/mcp750/irq/irq_init.c
Normal file
@@ -0,0 +1,288 @@
|
||||
/* 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>
|
||||
|
||||
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 isa_bridge_interrupts_setup(void)
|
||||
{
|
||||
pci_isa_bridge_device pci_dev;
|
||||
unsigned long 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;
|
||||
/*
|
||||
* 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);
|
||||
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)) {
|
||||
printk("This is a second generation MCP750 board\n");
|
||||
printk("We must reprogram the PCI/ISA bridge...\n");
|
||||
pci_read_config_byte(via_82c586->bus, via_82c586->device, via_82c586->function,
|
||||
0x47, &tmp);
|
||||
printk(" PCI ISA bridge control2 = %x\n", (unsigned) tmp);
|
||||
/*
|
||||
* 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);
|
||||
printk(" PCI ISA bridge PCI/IRQ Edge/Level Select = %x\n", (unsigned) tmp);
|
||||
tmp = 0;
|
||||
pci_write_config_byte(via_82c586->bus, via_82c586->device, via_82c586->function,
|
||||
0x54, tmp);
|
||||
}
|
||||
else {
|
||||
printk("This is a first generation MCP750 board\n");
|
||||
printk("We just show the actual value used by PCI/ISA bridge\n");
|
||||
pci_read_config_byte(via_82c586->bus, via_82c586->device, via_82c586->function,
|
||||
0x47, &tmp);
|
||||
printk(" PCI ISA bridge control2 = %x\n", (unsigned) tmp);
|
||||
/*
|
||||
* 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);
|
||||
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);
|
||||
/*
|
||||
* 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);
|
||||
printk(" PCI ISA bridge PCI/IRQ Edge/Level Select = %x\n", (unsigned) tmp);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* 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 this means the
|
||||
* decrementer exception and the external exception.
|
||||
*/
|
||||
void BSP_rtems_irq_mng_init(unsigned cpuId)
|
||||
{
|
||||
rtems_raw_except_connect_data vectorDesc;
|
||||
int i;
|
||||
register unsigned int msr;
|
||||
|
||||
/*
|
||||
* First initialize the Interrupt management hardware
|
||||
*/
|
||||
OpenPIC_InitSenses = mcp750_openpic_initsenses;
|
||||
OpenPIC_NumInitSenses = sizeof(mcp750_openpic_initsenses) / sizeof(char);
|
||||
printk("Going to initialize raven interrupt controller (openpic compliant)\n");
|
||||
openpic_init(1);
|
||||
printk("Going to initialize the PCI/ISA bridge IRQ related setting (VIA 82C586)\n");
|
||||
isa_bridge_interrupts_setup();
|
||||
printk("Going to initialize the ISA PC legacy IRQ management hardware\n");
|
||||
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 = &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 = &external_exception_vector_prolog_code_size;
|
||||
if (!mpc60x_set_exception (&vectorDesc)) {
|
||||
BSP_panic("Unable to initialize RTEMS external raw exception\n");
|
||||
}
|
||||
printk("RTEMS IRQ management is now operationnal\n");
|
||||
printk("Going to enable interrupts at processor level\n");
|
||||
_CPU_MSR_GET(msr);
|
||||
msr = msr |= MSR_EE;
|
||||
_CPU_MSR_SET(msr);
|
||||
printk("Interrupts enabled\n");
|
||||
}
|
||||
|
||||
62
c/src/lib/libbsp/powerpc/mcp750/openpic/Makefile.in
Normal file
62
c/src/lib/libbsp/powerpc/mcp750/openpic/Makefile.in
Normal file
@@ -0,0 +1,62 @@
|
||||
#
|
||||
# $Id$
|
||||
#
|
||||
|
||||
@SET_MAKE@
|
||||
srcdir = @srcdir@
|
||||
VPATH = @srcdir@
|
||||
RTEMS_ROOT = @top_srcdir@
|
||||
PROJECT_ROOT = @PROJECT_ROOT@
|
||||
|
||||
INSTALL = @INSTALL@
|
||||
|
||||
PGM=${ARCH}/openpic.rel
|
||||
|
||||
# C source names, if any, go here -- minus the .c
|
||||
C_PIECES=$(OPENPIC_PIECES)
|
||||
C_FILES=$(C_PIECES:%=%.c)
|
||||
C_O_FILES=$(C_PIECES:%=${ARCH}/%.o)
|
||||
|
||||
H_FILES=$(srcdir)/openpic.h
|
||||
|
||||
SRCS=$(C_FILES) $(H_FILES)
|
||||
OBJS=$(C_O_FILES)
|
||||
|
||||
include $(RTEMS_ROOT)/make/custom/$(RTEMS_BSP).cfg
|
||||
include $(RTEMS_ROOT)/make/leaf.cfg
|
||||
|
||||
OPENPIC_PIECES=openpic
|
||||
|
||||
#
|
||||
# (OPTIONAL) Add local stuff here using +=
|
||||
#
|
||||
|
||||
DEFINES +=
|
||||
CPPFLAGS +=
|
||||
CFLAGS +=
|
||||
|
||||
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 +=
|
||||
|
||||
${PGM}: ${SRCS} ${OBJS}
|
||||
$(make-rel)
|
||||
|
||||
preinstall:
|
||||
$(MKDIR) $(PROJECT_INCLUDE)/bsp
|
||||
$(INSTALL_CHANGE) -m 444 $(H_FILES) $(PROJECT_INCLUDE)/bsp
|
||||
|
||||
all: ${ARCH} $(SRCS) preinstall $(PGM)
|
||||
|
||||
# the .rel file built here will be put into libbsp.a by ../wrapup/Makefile
|
||||
install: all
|
||||
504
c/src/lib/libbsp/powerpc/mcp750/openpic/openpic.c
Normal file
504
c/src/lib/libbsp/powerpc/mcp750/openpic/openpic.c
Normal file
@@ -0,0 +1,504 @@
|
||||
/*
|
||||
* arch/ppc/kernel/openpic.c -- OpenPIC Interrupt Handling
|
||||
*
|
||||
* Copyright (C) 1997 Geert Uytterhoeven
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* 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 <asm/irq.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));
|
||||
}
|
||||
329
c/src/lib/libbsp/powerpc/mcp750/openpic/openpic.h
Normal file
329
c/src/lib/libbsp/powerpc/mcp750/openpic/openpic.h
Normal file
@@ -0,0 +1,329 @@
|
||||
/*
|
||||
* linux/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.
|
||||
*/
|
||||
|
||||
#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 */
|
||||
62
c/src/lib/libbsp/powerpc/mcp750/pci/Makefile.in
Normal file
62
c/src/lib/libbsp/powerpc/mcp750/pci/Makefile.in
Normal file
@@ -0,0 +1,62 @@
|
||||
#
|
||||
# $Id$
|
||||
#
|
||||
|
||||
@SET_MAKE@
|
||||
srcdir = @srcdir@
|
||||
VPATH = @srcdir@
|
||||
RTEMS_ROOT = @top_srcdir@
|
||||
PROJECT_ROOT = @PROJECT_ROOT@
|
||||
|
||||
INSTALL = @INSTALL@
|
||||
|
||||
PGM=${ARCH}/pci.rel
|
||||
|
||||
# C source names, if any, go here -- minus the .c
|
||||
C_PIECES=$(PCI_PIECES)
|
||||
C_FILES=$(C_PIECES:%=%.c)
|
||||
C_O_FILES=$(C_PIECES:%=${ARCH}/%.o)
|
||||
|
||||
H_FILES=$(srcdir)/pci.h
|
||||
|
||||
SRCS=$(C_FILES) $(H_FILES)
|
||||
OBJS=$(C_O_FILES)
|
||||
|
||||
include $(RTEMS_ROOT)/make/custom/$(RTEMS_BSP).cfg
|
||||
include $(RTEMS_ROOT)/make/leaf.cfg
|
||||
|
||||
PCI_PIECES=pci
|
||||
|
||||
#
|
||||
# (OPTIONAL) Add local stuff here using +=
|
||||
#
|
||||
|
||||
DEFINES +=
|
||||
CPPFLAGS +=
|
||||
CFLAGS +=
|
||||
|
||||
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 +=
|
||||
|
||||
${PGM}: ${SRCS} ${OBJS}
|
||||
$(make-rel)
|
||||
|
||||
preinstall:
|
||||
$(MKDIR) $(PROJECT_INCLUDE)/bsp
|
||||
$(INSTALL_CHANGE) -m 444 $(H_FILES) $(PROJECT_INCLUDE)/bsp
|
||||
|
||||
all: ${ARCH} $(SRCS) preinstall $(PGM)
|
||||
|
||||
# the .rel file built here will be put into libbsp.a by ../wrapup/Makefile
|
||||
install: all
|
||||
361
c/src/lib/libbsp/powerpc/mcp750/pci/pci.c
Normal file
361
c/src/lib/libbsp/powerpc/mcp750/pci/pci.c
Normal file
@@ -0,0 +1,361 @@
|
||||
#include <bsp/consoleIo.h>
|
||||
#include <libcpu/io.h>
|
||||
#include <bsp/pci.h>
|
||||
#include <bsp/residual.h>
|
||||
#include <bsp/openpic.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);
|
||||
printk("RAVEN PCI command register = %x\n",id0);
|
||||
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);
|
||||
printk("After error clearing RAVEN PCI command register = %x\n",id0);
|
||||
|
||||
if (id0 & RAVEN_MPIC_IOSPACE_ENABLE) {
|
||||
pci_read_config_dword(0, 0, 0,PCI_BASE_ADDRESS_0, &tmp);
|
||||
printk("Raven MPIC is accessed via IO Space Access at address : %x\n",(tmp & ~0x1));
|
||||
}
|
||||
if (id0 & RAVEN_MPIC_MEMSPACE_ENABLE) {
|
||||
pci_read_config_dword(0, 0, 0,PCI_BASE_ADDRESS_1, &tmp);
|
||||
printk("Raven MPIC is accessed via memory Space Access at address : %x\n", tmp);
|
||||
OpenPIC=(volatile struct OpenPIC *) (tmp + PREP_ISA_MEM_BASE);
|
||||
printk("OpenPIC found at %p.\n",
|
||||
OpenPIC);
|
||||
}
|
||||
}
|
||||
else {
|
||||
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);
|
||||
}
|
||||
1150
c/src/lib/libbsp/powerpc/mcp750/pci/pci.h
Normal file
1150
c/src/lib/libbsp/powerpc/mcp750/pci/pci.h
Normal file
File diff suppressed because it is too large
Load Diff
62
c/src/lib/libbsp/powerpc/mcp750/residual/Makefile.in
Normal file
62
c/src/lib/libbsp/powerpc/mcp750/residual/Makefile.in
Normal file
@@ -0,0 +1,62 @@
|
||||
#
|
||||
# $Id$
|
||||
#
|
||||
|
||||
@SET_MAKE@
|
||||
srcdir = @srcdir@
|
||||
VPATH = @srcdir@
|
||||
RTEMS_ROOT = @top_srcdir@
|
||||
PROJECT_ROOT = @PROJECT_ROOT@
|
||||
|
||||
INSTALL = @INSTALL@
|
||||
|
||||
PGM=${ARCH}/residual.rel
|
||||
|
||||
# C source names, if any, go here -- minus the .c
|
||||
C_PIECES=$(RESIDUAL_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
|
||||
|
||||
RESIDUAL_PIECES=residual
|
||||
|
||||
#
|
||||
# (OPTIONAL) Add local stuff here using +=
|
||||
#
|
||||
|
||||
DEFINES +=
|
||||
CPPFLAGS +=
|
||||
CFLAGS +=
|
||||
|
||||
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 +=
|
||||
|
||||
preinstall:
|
||||
$(MKDIR) $(PROJECT_INCLUDE)/bsp
|
||||
$(INSTALL_CHANGE) -m 444 $(H_FILES) $(PROJECT_INCLUDE)/bsp
|
||||
|
||||
${PGM}: ${SRCS} ${OBJS}
|
||||
$(make-rel)
|
||||
|
||||
all: ${ARCH} $(SRCS) preinstall $(PGM)
|
||||
|
||||
# the .rel file built here will be put into libbsp.a by ../wrapup/Makefile
|
||||
install: all
|
||||
643
c/src/lib/libbsp/powerpc/mcp750/residual/pnp.h
Normal file
643
c/src/lib/libbsp/powerpc/mcp750/residual/pnp.h
Normal file
@@ -0,0 +1,643 @@
|
||||
/* 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 */
|
||||
|
||||
#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_ */
|
||||
91
c/src/lib/libbsp/powerpc/mcp750/residual/residual.c
Normal file
91
c/src/lib/libbsp/powerpc/mcp750/residual/residual.c
Normal file
@@ -0,0 +1,91 @@
|
||||
#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 */
|
||||
}
|
||||
|
||||
342
c/src/lib/libbsp/powerpc/mcp750/residual/residual.h
Normal file
342
c/src/lib/libbsp/powerpc/mcp750/residual/residual.h
Normal file
@@ -0,0 +1,342 @@
|
||||
/* 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. */
|
||||
|
||||
#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 "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_ */
|
||||
|
||||
@@ -5,8 +5,8 @@
|
||||
@SET_MAKE@
|
||||
srcdir = @srcdir@
|
||||
top_srcdir = @top_srcdir@
|
||||
top_builddir = ../../../../../../../..
|
||||
subdir = c/src/exec/score/cpu/powerpc/rtems/score
|
||||
top_builddir = ../../../../../../..
|
||||
subdir = c/src/lib/libbsp/powerpc/mcp750/start
|
||||
|
||||
INSTALL = @INSTALL@
|
||||
|
||||
@@ -15,16 +15,17 @@ PROJECT_ROOT = @PROJECT_ROOT@
|
||||
|
||||
VPATH = @srcdir@
|
||||
|
||||
PGM=${ARCH}/start.o
|
||||
|
||||
# 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_PIECES=cpu.h ppc.h ppctypes.h
|
||||
H_FILES=$(H_PIECES:%=$(srcdir)/%)
|
||||
H_FILES=
|
||||
|
||||
# Assembly source names, if any, go here -- minus the .S
|
||||
S_PIECES=
|
||||
S_PIECES=start
|
||||
S_FILES=$(S_PIECES:%=%.S)
|
||||
S_O_FILES=$(S_FILES:%.S=${ARCH}/%.o)
|
||||
|
||||
@@ -54,16 +55,10 @@ LDFLAGS +=
|
||||
#
|
||||
|
||||
CLEAN_ADDITIONS +=
|
||||
CLOBBER_ADDITIONS += $(BUILT_SOURCES)
|
||||
CLOBBER_ADDITIONS +=
|
||||
|
||||
# Install the program(s), appending _g or _p as appropriate.
|
||||
# for include files, just use $(INSTALL_CHANGE)
|
||||
all: install-headers
|
||||
|
||||
install-headers: ${H_FILES}
|
||||
$(INSTALL_CHANGE) -m 444 ${H_FILES} $(PROJECT_INCLUDE)/rtems/score
|
||||
|
||||
preinstall: install-headers
|
||||
all: ${ARCH} $(SRCS) $(OBJS) $(PGM)
|
||||
$(INSTALL_VARIANT) -m 555 ${PGM} ${PROJECT_RELEASE}/lib
|
||||
|
||||
Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
|
||||
cd $(top_builddir) \
|
||||
149
c/src/lib/libbsp/powerpc/mcp750/start/start.S
Normal file
149
c/src/lib/libbsp/powerpc/mcp750/start/start.S
Normal file
@@ -0,0 +1,149 @@
|
||||
/*
|
||||
* arch/ppc/kernel/head.S
|
||||
*
|
||||
* $Id$
|
||||
*
|
||||
* PowerPC version
|
||||
* Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
|
||||
*
|
||||
* Rewritten by Cort Dougan (cort@cs.nmt.edu) for PReP
|
||||
* Adapted for Power Macintosh by Paul Mackerras.
|
||||
* Low-level exception handlers and MMU support
|
||||
* rewritten by Paul Mackerras.
|
||||
* Copyright (C) 1996 Paul Mackerras.
|
||||
* MPC8xx modifications Copyright (C) 1997 Dan Malek (dmalek@jlc.net).
|
||||
* Amiga/APUS changes by Jesper Skov (jskov@cygnus.co.uk).
|
||||
*
|
||||
* This file contains the low-level support and setup for the
|
||||
* PowerPC platform, including trap and interrupt dispatch.
|
||||
* Also included here is low-level thread/task switch support.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version
|
||||
* 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <libcpu/cpu.h>
|
||||
#include <libcpu/io.h>
|
||||
#include <rtems/score/targopts.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@ha
|
||||
addi r9,r9, __rtems_end+4096@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
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
56
c/src/lib/libbsp/powerpc/mcp750/startup/Makefile.in
Normal file
56
c/src/lib/libbsp/powerpc/mcp750/startup/Makefile.in
Normal file
@@ -0,0 +1,56 @@
|
||||
#
|
||||
# $Id$
|
||||
#
|
||||
|
||||
@SET_MAKE@
|
||||
srcdir = @srcdir@:
|
||||
VPATH = @srcdir@:@srcdir@/../console:@srcdir@/../../../shared:
|
||||
RTEMS_ROOT = @top_srcdir@
|
||||
PROJECT_ROOT = @PROJECT_ROOT@
|
||||
|
||||
# C source names, if any, go here -- minus the .c
|
||||
C_PIECES=main bspstart bsppost bsplibc sbrk bspclean
|
||||
C_FILES=$(C_PIECES:%=%.c)
|
||||
C_O_FILES=$(C_PIECES:%=${ARCH}/%.o)
|
||||
|
||||
H_FILES=
|
||||
|
||||
# Assembly source names, if any, go here -- minus the .s
|
||||
S_PIECES=consoleLib
|
||||
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) $(CC_O_FILES)
|
||||
|
||||
include $(RTEMS_ROOT)/make/custom/$(RTEMS_BSP).cfg
|
||||
include $(RTEMS_ROOT)/make/leaf.cfg
|
||||
|
||||
#
|
||||
# (OPTIONAL) Add local stuff here using +=
|
||||
#
|
||||
|
||||
DEFINES +=
|
||||
CPPFLAGS +=
|
||||
CFLAGS +=
|
||||
|
||||
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 +=
|
||||
|
||||
all: ${ARCH} $(SRCS) $(OBJS)
|
||||
$(INSTALL_VARIANT) -m 555 ${PGM} ${PROJECT_RELEASE}/lib
|
||||
$(INSTALL_CHANGE) @srcdir@/linkcmds ${PROJECT_RELEASE}/lib
|
||||
|
||||
${PROJECT_RELEASE}/lib/libbsp.a:
|
||||
cd ../wrapup; $(MAKE)
|
||||
303
c/src/lib/libbsp/powerpc/mcp750/startup/bspstart.c
Normal file
303
c/src/lib/libbsp/powerpc/mcp750/startup/bspstart.c
Normal file
@@ -0,0 +1,303 @@
|
||||
/*
|
||||
* This routine starts the application. It includes application,
|
||||
* board, and monitor specific initialization and configuration.
|
||||
* The generic CPU dependent initialization has been performed
|
||||
* before this routine is invoked.
|
||||
*
|
||||
* COPYRIGHT (c) 1989-1998.
|
||||
* 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 <bsp.h>
|
||||
#include <rtems/libio.h>
|
||||
#include <libcsupport.h>
|
||||
#include <string.h>
|
||||
#include <bsp/consoleIo.h>
|
||||
#include <libcpu/spr.h>
|
||||
#include <bsp/residual.h>
|
||||
#include <bsp/pci.h>
|
||||
#include <bsp/openpic.h>
|
||||
#include <bsp/irq.h>
|
||||
#include <bsp.h>
|
||||
#include <libcpu/bat.h>
|
||||
#include <bsp/vectors.h>
|
||||
|
||||
extern void _return_to_ppcbug();
|
||||
extern unsigned long __rtems_end;
|
||||
extern unsigned long _end;
|
||||
extern unsigned long __bss_start;
|
||||
extern void L1_caches_enables();
|
||||
extern unsigned get_L2CR();
|
||||
extern void set_L2CR(unsigned);
|
||||
/*
|
||||
* Copy of residuals passed by firmware
|
||||
*/
|
||||
RESIDUAL residualCopy;
|
||||
/*
|
||||
* Copy Additional boot param passed by boot loader
|
||||
*/
|
||||
#define MAX_LOADER_ADD_PARM 80
|
||||
char loaderParam[MAX_LOADER_ADD_PARM];
|
||||
/*
|
||||
* 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;
|
||||
/*
|
||||
* system init stack and soft ir stack size
|
||||
*/
|
||||
#define INIT_STACK_SIZE 0x1000
|
||||
#define INTR_STACK_SIZE 0x4000
|
||||
|
||||
void BSP_panic(char *s)
|
||||
{
|
||||
printk("RTEMS 4.x PANIC %s\n", s);
|
||||
_return_to_ppcbug();
|
||||
}
|
||||
|
||||
void _BSP_Fatal_error(unsigned int v)
|
||||
{
|
||||
printk("RTEMS 4.x PANIC ERROR %x\n", v);
|
||||
_return_to_ppcbug();
|
||||
}
|
||||
|
||||
/*
|
||||
* The original table from the application and our copy of it with
|
||||
* some changes.
|
||||
*/
|
||||
|
||||
extern rtems_configuration_table Configuration;
|
||||
|
||||
rtems_configuration_table BSP_Configuration;
|
||||
|
||||
rtems_cpu_table Cpu_table;
|
||||
|
||||
char *rtems_progname;
|
||||
|
||||
/*
|
||||
* Use the shared implementations of the following routines
|
||||
*/
|
||||
|
||||
void bsp_postdriver_hook(void);
|
||||
void bsp_libc_init( void *, unsigned32, int );
|
||||
|
||||
/*
|
||||
* Function: bsp_pretasking_hook
|
||||
* Created: 95/03/10
|
||||
*
|
||||
* Description:
|
||||
* BSP pretasking hook. Called just before drivers are initialized.
|
||||
* Used to setup libc and install any BSP extensions.
|
||||
*
|
||||
* NOTES:
|
||||
* Must not use libc (to do io) from here, since drivers are
|
||||
* not yet initialized.
|
||||
*
|
||||
*/
|
||||
|
||||
void bsp_pretasking_hook(void)
|
||||
{
|
||||
extern int end;
|
||||
rtems_unsigned32 heap_start;
|
||||
|
||||
heap_start = ((rtems_unsigned32) &__rtems_end) +INIT_STACK_SIZE + INTR_STACK_SIZE;
|
||||
if (heap_start & (CPU_ALIGNMENT-1))
|
||||
heap_start = (heap_start + CPU_ALIGNMENT) & ~(CPU_ALIGNMENT-1);
|
||||
|
||||
bsp_libc_init((void *) heap_start, 64 * 1024, 0);
|
||||
|
||||
#ifdef RTEMS_DEBUG
|
||||
rtems_debug_enable( RTEMS_DEBUG_ALL_MASK );
|
||||
#endif
|
||||
}
|
||||
|
||||
void zero_bss()
|
||||
{
|
||||
memset(&__bss_start, 0, &__rtems_end - &__bss_start);
|
||||
}
|
||||
|
||||
void save_boot_params(RESIDUAL* r3, void *r4, void* r5, char *additional_boot_options)
|
||||
{
|
||||
|
||||
residualCopy = *r3;
|
||||
strncpy(loaderParam, additional_boot_options, MAX_LOADER_ADD_PARM);
|
||||
loaderParam[MAX_LOADER_ADD_PARM - 1] ='\0';
|
||||
}
|
||||
|
||||
/*
|
||||
* bsp_start
|
||||
*
|
||||
* This routine does the bulk of the system initialization.
|
||||
*/
|
||||
|
||||
void bsp_start( void )
|
||||
{
|
||||
int err;
|
||||
unsigned char *stack;
|
||||
unsigned l2cr;
|
||||
register unsigned char* intrStack;
|
||||
register unsigned int intrNestingLevel = 0;
|
||||
unsigned char *work_space_start;
|
||||
|
||||
/*
|
||||
* enables L1 Cache
|
||||
*/
|
||||
L1_caches_enables();
|
||||
/*
|
||||
* Enable L2 Cache
|
||||
*/
|
||||
l2cr = get_L2CR();
|
||||
#ifdef SHOW_LCR2_REGISTER
|
||||
printk("Initial L2CR value = %x\n", l2cr);
|
||||
#endif
|
||||
if (! (l2cr & 0x80000000))
|
||||
set_L2CR(0xb9A14000);
|
||||
/*
|
||||
* the initial stack has aready been set to this value in start.S
|
||||
* so there is no need to set it in r1 again...
|
||||
*/
|
||||
stack = ((unsigned char*) &__rtems_end) + INIT_STACK_SIZE;
|
||||
/*
|
||||
* Initialize the interrupt related settings
|
||||
* SPRG0 = interrupt nesting level count
|
||||
* SPRG1 = software managed IRQ stack
|
||||
*
|
||||
* This could be done latter (e.g in IRQ_INIT) but it helps to understand
|
||||
* some settings below...
|
||||
*/
|
||||
intrStack = ((unsigned char*) &__rtems_end) + INIT_STACK_SIZE + INTR_STACK_SIZE;
|
||||
asm volatile ("mtspr 273, %0" : "=r" (intrStack) : "0" (intrStack));
|
||||
asm volatile ("mtspr 272, %0" : "=r" (intrNestingLevel) : "0" (intrNestingLevel));
|
||||
/*
|
||||
* Initialize default raw exception hanlders. See vectors/vectors_init.c
|
||||
*/
|
||||
initialize_exceptions();
|
||||
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("-----------------------------------------\n");
|
||||
printk("Welcome to RTEMS 4.1.1 on Motorola MCP750\n");
|
||||
printk("-----------------------------------------\n");
|
||||
#ifdef SHOW_MORE_INIT_SETTINGS
|
||||
printk("Residuals are located at %x\n", (unsigned) &residualCopy);
|
||||
printk("Additionnal boot options are %s\n", loaderParam);
|
||||
printk("Initial system stack at %x\n",stack);
|
||||
printk("Software IRQ stack at %x\n",intrStack);
|
||||
printk("-----------------------------------------\n");
|
||||
#endif
|
||||
|
||||
#ifdef TEST_RETURN_TO_PPCBUG
|
||||
printk("Hit <Enter> to return to PPCBUG monitor\n");
|
||||
printk("When Finished hit GO. It should print <Back from monitor>\n");
|
||||
debug_getc();
|
||||
_return_to_ppcbug();
|
||||
printk("Back from monitor\n");
|
||||
_return_to_ppcbug();
|
||||
#endif /* TEST_RETURN_TO_PPCBUG */
|
||||
|
||||
/*
|
||||
* Init MMU block address translation to enable hardware
|
||||
* access
|
||||
*/
|
||||
/*
|
||||
* PC legacy IO space used for inb/outb and all PC
|
||||
* compatible hardware
|
||||
*/
|
||||
setdbat(1, 0x80000000, 0x80000000, 0x10000000, IO_PAGE);
|
||||
/*
|
||||
* PCI devices memory area. Needed to access OPENPIC features
|
||||
* provided by the RAVEN
|
||||
*/
|
||||
setdbat(2, 0xc0000000, 0xc0000000, 0x08000000, IO_PAGE);
|
||||
/*
|
||||
* Must have acces to open pic PCI ACK registers
|
||||
* provided by the RAVEN
|
||||
*/
|
||||
setdbat(3, 0xfeff0000, 0xfeff0000, 0x10000, IO_PAGE);
|
||||
|
||||
printk("Going to start PCI buses scanning and initialization\n");
|
||||
InitializePCI();
|
||||
printk("Number of PCI buses is found : %d\n", BusCountPCI());
|
||||
|
||||
#ifdef TEST_RAW_EXCEPTION_CODE
|
||||
printk("Testing exception handling Part 1\n");
|
||||
/*
|
||||
* Cause a software exception
|
||||
*/
|
||||
__asm__ __volatile ("sc");
|
||||
/*
|
||||
* Check we can still catch exceptions and returned coorectly.
|
||||
*/
|
||||
printk("Testing exception handling Part 2\n");
|
||||
__asm__ __volatile ("sc");
|
||||
#endif
|
||||
|
||||
|
||||
BSP_mem_size = residualCopy.TotalMemory;
|
||||
BSP_bus_frequency = residualCopy.VitalProductData.ProcessorBusHz;
|
||||
BSP_processor_frequency = residualCopy.VitalProductData.ProcessorHz;
|
||||
BSP_time_base_divisor = (residualCopy.VitalProductData.TimeBaseDivisor?
|
||||
residualCopy.VitalProductData.TimeBaseDivisor : 4000);
|
||||
|
||||
/*
|
||||
* Set up our hooks
|
||||
* Make sure libc_init is done before drivers initialized so that
|
||||
* they can use atexit()
|
||||
*/
|
||||
|
||||
Cpu_table.pretasking_hook = bsp_pretasking_hook; /* init libc, etc. */
|
||||
Cpu_table.postdriver_hook = bsp_postdriver_hook;
|
||||
Cpu_table.do_zero_of_workspace = TRUE;
|
||||
Cpu_table.interrupt_stack_size = INTR_STACK_SIZE;
|
||||
Cpu_table.clicks_per_usec = BSP_processor_frequency/(BSP_time_base_divisor * 1000);
|
||||
Cpu_table.exceptions_in_RAM = TRUE;
|
||||
|
||||
printk("BSP_Configuration.work_space_size = %x\n", BSP_Configuration.work_space_size);
|
||||
work_space_start =
|
||||
(unsigned char *)BSP_mem_size - BSP_Configuration.work_space_size;
|
||||
|
||||
if ( work_space_start <= ((unsigned char *)&__rtems_end) + INIT_STACK_SIZE + INTR_STACK_SIZE) {
|
||||
printk( "bspstart: Not enough RAM!!!\n" );
|
||||
bsp_cleanup();
|
||||
}
|
||||
|
||||
BSP_Configuration.work_space_start = work_space_start;
|
||||
|
||||
/*
|
||||
* Account for the console's resources
|
||||
*/
|
||||
|
||||
console_reserve_resources( &BSP_Configuration );
|
||||
/*
|
||||
* Initalize RTEMS IRQ system
|
||||
*/
|
||||
BSP_rtems_irq_mng_init(0);
|
||||
printk("Exit from bspstart\n");
|
||||
}
|
||||
121
c/src/lib/libbsp/powerpc/mcp750/startup/cEntry.c
Normal file
121
c/src/lib/libbsp/powerpc/mcp750/startup/cEntry.c
Normal file
@@ -0,0 +1,121 @@
|
||||
/*
|
||||
*
|
||||
*/
|
||||
#include <bsp/consoleIo.h>
|
||||
#include <libcpu/spr.h>
|
||||
#include <bsp/residual.h>
|
||||
#include <bsp/pci.h>
|
||||
#include <bsp/openpic.h>
|
||||
#include <bsp/irq.h>
|
||||
#include <bsp.h>
|
||||
#include <libcpu/bat.h>
|
||||
|
||||
extern void _return_to_ppcbug();
|
||||
extern unsigned long __rtems_end;
|
||||
|
||||
RESIDUAL residualCopy;
|
||||
#define INIT_STACK_SIZE 0x1000
|
||||
#define INTR_STACK_SIZE 0x4000
|
||||
|
||||
void BSP_panic(char *s)
|
||||
{
|
||||
printk("RTEMS 4.x PANIC %s\n", s);
|
||||
_return_to_ppcbug();
|
||||
}
|
||||
|
||||
void _BSP_Fatal_error(unsigned int v)
|
||||
{
|
||||
printk("RTEMS 4.x PANIC ERROR %x\n", v);
|
||||
_return_to_ppcbug();
|
||||
}
|
||||
|
||||
void
|
||||
boot_card(RESIDUAL* r3, void *r4, void* r5, char *additional_boot_options)
|
||||
{
|
||||
int err;
|
||||
unsigned char *stack;
|
||||
unsigned l2cr;
|
||||
register unsigned char* intrStack;
|
||||
register unsigned int intrNestingLevel = 0;
|
||||
|
||||
L1_caches_enables();
|
||||
stack = ((unsigned char*) &__rtems_end) + INIT_STACK_SIZE;
|
||||
intrStack = ((unsigned char*) &__rtems_end) + INIT_STACK_SIZE + INTR_STACK_SIZE;
|
||||
asm volatile ("mtspr 273, %0" : "=r" (intrStack) : "0" (intrStack));
|
||||
asm volatile ("mtspr 272, %0" : "=r" (intrNestingLevel) : "0" (intrNestingLevel));
|
||||
residualCopy = *r3;
|
||||
#define NO_DYNAMIC_EXCEPTION_VECTOR_INSTALL
|
||||
#undef NO_DYNAMIC_EXCEPTION_VECTOR_INSTALL
|
||||
#ifndef NO_DYNAMIC_EXCEPTION_VECTOR_INSTALL
|
||||
initialize_exceptions();
|
||||
#endif
|
||||
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("Welcome to RTEMS 4.0.2 on Motorola MCP750\n\n\n");
|
||||
printk("-----------------------------------------\n");
|
||||
printk("Residuals are located at %x\n", (unsigned) r3);
|
||||
printk("Additionnal boot options are %s\n", additional_boot_options);
|
||||
printk("-----------------------------------------\n");
|
||||
|
||||
printk("Initial system stack at %x\n",stack);
|
||||
l2cr = get_L2CR();
|
||||
printk("Initial L2CR value = %x\n", l2cr);
|
||||
if (! (l2cr & 0x80000000))
|
||||
set_L2CR(0xb9A14000);
|
||||
#ifdef TEST_RETURN_TO_PPCBUG
|
||||
printk("Hit <Enter> to return to PPCBUG monitor\n");
|
||||
printk("When Finished hit GO. It should print <Back from monitor>\n");
|
||||
debug_getc();
|
||||
_return_to_ppcbug();
|
||||
printk("Back from monitor\n");
|
||||
_return_to_ppcbug();
|
||||
#endif /* TEST_RETURN_TO_PPCBUG */
|
||||
|
||||
/*
|
||||
* Init MMU block address translation to enable hardware
|
||||
* access
|
||||
*/
|
||||
/*
|
||||
* PC legacy IO space used for inb/outb and all PC
|
||||
* compatible hardware
|
||||
*/
|
||||
setdbat(1, 0x80000000, 0x80000000, 0x10000000, IO_PAGE);
|
||||
/*
|
||||
* PCI devices memory area. Needed to access OPENPIC features
|
||||
* provided by the RAVEN
|
||||
*/
|
||||
setdbat(2, 0xc0000000, 0xc0000000, 0x08000000, IO_PAGE);
|
||||
/*
|
||||
* Must have acces to open pic PCI ACK registers
|
||||
* provided by the RAVEN
|
||||
*/
|
||||
setdbat(3, 0xfeff0000, 0xfeff0000, 0x10000, IO_PAGE);
|
||||
|
||||
printk("Going to start PCI buses scanning and initialization\n");
|
||||
InitializePCI();
|
||||
printk("Number of PCI buses is found : %d\n", BusCountPCI());
|
||||
#ifdef TEST_RAW_EXCEPTION_CODE
|
||||
printk("Testing exception handling Part 1\n");
|
||||
/*
|
||||
* Cause a software exception
|
||||
*/
|
||||
__asm__ __volatile ("sc");
|
||||
/*
|
||||
* Check we can still catch exceptions
|
||||
*/
|
||||
printk("Testing exception handling Part 2\n");
|
||||
__asm__ __volatile ("sc");
|
||||
#endif
|
||||
BSP_rtems_irq_mng_init(0);
|
||||
printk("Init done\n");
|
||||
debug_getc();
|
||||
while(1);
|
||||
}
|
||||
|
||||
147
c/src/lib/libbsp/powerpc/mcp750/startup/linkcmds
Normal file
147
c/src/lib/libbsp/powerpc/mcp750/startup/linkcmds
Normal file
@@ -0,0 +1,147 @@
|
||||
OUTPUT_FORMAT("elf32-powerpc", "elf32-powerpc",
|
||||
"elf32-powerpc")
|
||||
OUTPUT_ARCH(powerpc)
|
||||
ENTRY(_start)
|
||||
/* Do we need any of these for elf?
|
||||
__DYNAMIC = 0; */
|
||||
PROVIDE (__stack = 0);
|
||||
MEMORY {
|
||||
VECTORS : ORIGIN = 0x0 , LENGTH = 0x3000
|
||||
CODE : ORIGIN = 0x3000 , LENGTH = 0x100000
|
||||
}
|
||||
SECTIONS
|
||||
{
|
||||
.entry_point_section :
|
||||
{
|
||||
*(.entry_point_section)
|
||||
} > VECTORS
|
||||
|
||||
/*
|
||||
* This section is used only if NO_DYNAMIC_EXCEPTION_VECTOR_INSTALL
|
||||
* is defined in vectors/vectors.S
|
||||
*/
|
||||
.vectors :
|
||||
{
|
||||
*(.vectors)
|
||||
} > VECTORS
|
||||
|
||||
/* Read-only sections, merged into text segment: */
|
||||
.interp : { *(.interp) } > CODE
|
||||
.hash : { *(.hash) } > CODE
|
||||
.dynsym : { *(.dynsym) } > CODE
|
||||
.dynstr : { *(.dynstr) } > CODE
|
||||
.gnu.version : { *(.gnu.version) } > CODE
|
||||
.gnu.version_d : { *(.gnu.version_d) } > CODE
|
||||
.gnu.version_r : { *(.gnu.version_r) } > CODE
|
||||
.rela.text :
|
||||
{ *(.rela.text) *(.rela.gnu.linkonce.t*) } > CODE
|
||||
.rela.data :
|
||||
{ *(.rela.data) *(.rela.gnu.linkonce.d*) } > CODE
|
||||
.rela.rodata :
|
||||
{ *(.rela.rodata) *(.rela.gnu.linkonce.r*) } > CODE
|
||||
.rela.got : { *(.rela.got) } > CODE
|
||||
.rela.got1 : { *(.rela.got1) } > CODE
|
||||
.rela.got2 : { *(.rela.got2) } > CODE
|
||||
.rela.ctors : { *(.rela.ctors) } > CODE
|
||||
.rela.dtors : { *(.rela.dtors) } > CODE
|
||||
.rela.init : { *(.rela.init) } > CODE
|
||||
.rela.fini : { *(.rela.fini) } > CODE
|
||||
.rela.bss : { *(.rela.bss) } > CODE
|
||||
.rela.plt : { *(.rela.plt) } > CODE
|
||||
.rela.sdata : { *(.rela.sdata) } > CODE
|
||||
.rela.sbss : { *(.rela.sbss) } > CODE
|
||||
.rela.sdata2 : { *(.rela.sdata2) } > CODE
|
||||
.rela.sbss2 : { *(.rela.sbss2) } > CODE
|
||||
.text :
|
||||
{
|
||||
*(.text)
|
||||
/* .gnu.warning sections are handled specially by elf32.em. */
|
||||
*(.gnu.warning)
|
||||
*(.gnu.linkonce.t*)
|
||||
} > CODE
|
||||
.init : { *(.init) } > CODE
|
||||
.fini : { *(.fini) } > CODE
|
||||
.rodata : { *(.rodata) *(.gnu.linkonce.r*) } > CODE
|
||||
.rodata1 : { *(.rodata1) } > CODE
|
||||
_etext = .;
|
||||
PROVIDE (etext = .);
|
||||
.sdata2 : { *(.sdata2) } > CODE
|
||||
.sbss2 : { *(.sbss2) } > CODE
|
||||
/* Adjust the address for the data segment. We want to adjust up to
|
||||
the same address within the page on the next page up. It would
|
||||
be more correct to do this:
|
||||
. = ALIGN(0x40000) + (ALIGN(8) & (0x40000 - 1));
|
||||
The current expression does not correctly handle the case of a
|
||||
text segment ending precisely at the end of a page; it causes the
|
||||
data segment to skip a page. The above expression does not have
|
||||
this problem, but it will currently (2/95) cause BFD to allocate
|
||||
a single segment, combining both text and data, for this case.
|
||||
This will prevent the text segment from being shared among
|
||||
multiple executions of the program; I think that is more
|
||||
important than losing a page of the virtual address space (note
|
||||
that no actual memory is lost; the page which is skipped can not
|
||||
be referenced). */
|
||||
. = ALIGN(0x1000);
|
||||
.data :
|
||||
{
|
||||
*(.data)
|
||||
*(.gnu.linkonce.d*)
|
||||
CONSTRUCTORS
|
||||
} > CODE
|
||||
.data1 : { *(.data1) } > CODE
|
||||
PROVIDE (__EXCEPT_START__ = .);
|
||||
.gcc_except_table : { *(.gcc_except_table) } > CODE
|
||||
PROVIDE (__EXCEPT_END__ = .);
|
||||
.got1 : { *(.got1) } > CODE
|
||||
.dynamic : { *(.dynamic) } > CODE
|
||||
/* Put .ctors and .dtors next to the .got2 section, so that the pointers
|
||||
get relocated with -mrelocatable. Also put in the .fixup pointers.
|
||||
The current compiler no longer needs this, but keep it around for 2.7.2 */
|
||||
PROVIDE (_GOT2_START_ = .);
|
||||
.got2 : { *(.got2) } > CODE
|
||||
PROVIDE (__CTOR_LIST__ = .);
|
||||
.ctors : { *(.ctors) } > CODE
|
||||
PROVIDE (__CTOR_END__ = .);
|
||||
PROVIDE (__DTOR_LIST__ = .);
|
||||
.dtors : { *(.dtors) } > CODE
|
||||
PROVIDE (__DTOR_END__ = .);
|
||||
PROVIDE (_FIXUP_START_ = .);
|
||||
.fixup : { *(.fixup) } > CODE
|
||||
PROVIDE (_FIXUP_END_ = .);
|
||||
PROVIDE (_GOT2_END_ = .);
|
||||
PROVIDE (_GOT_START_ = .);
|
||||
.got : { *(.got) } > CODE
|
||||
.got.plt : { *(.got.plt) } > CODE
|
||||
PROVIDE (_GOT_END_ = .);
|
||||
/* We want the small data sections together, so single-instruction offsets
|
||||
can access them all, and initialized data all before uninitialized, so
|
||||
we can shorten the on-disk segment size. */
|
||||
.sdata : { *(.sdata) } > CODE
|
||||
_edata = .;
|
||||
PROVIDE (edata = .);
|
||||
.sbss :
|
||||
{
|
||||
PROVIDE (__sbss_start = .);
|
||||
*(.sbss)
|
||||
*(.scommon)
|
||||
*(.dynsbss)
|
||||
PROVIDE (__sbss_end = .);
|
||||
} > CODE
|
||||
.plt : { *(.plt) } > CODE
|
||||
.bss :
|
||||
{
|
||||
PROVIDE (__bss_start = .);
|
||||
*(.dynbss)
|
||||
*(.bss)
|
||||
*(COMMON)
|
||||
. = ALIGN(16);
|
||||
} > CODE
|
||||
. = ALIGN(16);
|
||||
_end = . ;
|
||||
__rtems_end = . ;
|
||||
PROVIDE (end = .);
|
||||
/DISCARD/ :
|
||||
{
|
||||
*(.comment)
|
||||
}
|
||||
}
|
||||
64
c/src/lib/libbsp/powerpc/mcp750/vectors/Makefile.in
Normal file
64
c/src/lib/libbsp/powerpc/mcp750/vectors/Makefile.in
Normal file
@@ -0,0 +1,64 @@
|
||||
#
|
||||
# $Id$
|
||||
#
|
||||
|
||||
@SET_MAKE@
|
||||
srcdir = @srcdir@
|
||||
VPATH = @srcdir@:@srcdir@/../console:
|
||||
RTEMS_ROOT = @top_srcdir@
|
||||
PROJECT_ROOT = @PROJECT_ROOT@
|
||||
|
||||
INSTALL = @INSTALL@
|
||||
|
||||
PGM=${ARCH}/vectors.rel
|
||||
|
||||
# C source names, if any, go here -- minus the .c
|
||||
C_PIECES=vectors_init
|
||||
C_FILES=$(C_PIECES:%=%.c)
|
||||
C_O_FILES=$(C_PIECES:%=${ARCH}/%.o)
|
||||
|
||||
H_FILES=$(srcdir)/vectors.h
|
||||
|
||||
# Assembly source names, if any, go here -- minus the .s
|
||||
S_PIECES=vectors
|
||||
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) $(CC_O_FILES)
|
||||
|
||||
include $(RTEMS_ROOT)/make/custom/$(RTEMS_BSP).cfg
|
||||
include $(RTEMS_ROOT)/make/leaf.cfg
|
||||
|
||||
#
|
||||
# (OPTIONAL) Add local stuff here using +=
|
||||
#
|
||||
|
||||
DEFINES +=
|
||||
CPPFLAGS +=
|
||||
CFLAGS +=
|
||||
|
||||
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 +=
|
||||
|
||||
${PGM}: ${SRCS} ${OBJS}
|
||||
$(make-rel)
|
||||
|
||||
preinstall:
|
||||
$(MKDIR) $(PROJECT_INCLUDE)/bsp
|
||||
$(INSTALL_CHANGE) -m 444 $(H_FILES) $(PROJECT_INCLUDE)/bsp
|
||||
|
||||
all: ${ARCH} $(SRCS) preinstall $(OBJS) $(PGM)
|
||||
|
||||
|
||||
142
c/src/lib/libbsp/powerpc/mcp750/vectors/vectors.S
Normal file
142
c/src/lib/libbsp/powerpc/mcp750/vectors/vectors.S
Normal file
@@ -0,0 +1,142 @@
|
||||
/*
|
||||
* (c) 1999, Eric Valette valette@crf.canon.fr
|
||||
*
|
||||
*
|
||||
* This file contains the assembly code for the PowerPC
|
||||
* exception veneers for RTEMS.
|
||||
*
|
||||
* $Id$
|
||||
*/
|
||||
|
||||
|
||||
|
||||
#include <bsp/vectors.h>
|
||||
#include <libcpu/cpu.h>
|
||||
#include <rtems/score/targopts.h>
|
||||
#include "asm.h"
|
||||
|
||||
|
||||
#define SYNC \
|
||||
sync; \
|
||||
isync
|
||||
|
||||
PUBLIC_VAR (__rtems_start)
|
||||
.section .entry_point_section,"awx",@progbits
|
||||
/*
|
||||
* Entry point information used by bootloader code
|
||||
*/
|
||||
SYM (__rtems_start):
|
||||
.long __rtems_entry_point
|
||||
|
||||
/*
|
||||
* end of special Entry point section
|
||||
*/
|
||||
.text
|
||||
.p2align 5
|
||||
|
||||
PUBLIC_VAR(default_exception_vector_code_prolog)
|
||||
SYM (default_exception_vector_code_prolog):
|
||||
/*
|
||||
* let room for exception frame
|
||||
*/
|
||||
stwu r1, - (EXCEPTION_FRAME_END)(r1)
|
||||
stw r3, GPR3_OFFSET(r1)
|
||||
stw r2, GPR2_OFFSET(r1)
|
||||
mflr r2
|
||||
stw r2, EXC_LR_OFFSET(r1)
|
||||
bl 0f
|
||||
0: /*
|
||||
* r3 = exception vector entry point
|
||||
* (256 * vector number) + few instructions
|
||||
*/
|
||||
mflr r3
|
||||
/*
|
||||
* r3 = r3 >> 8 = vector
|
||||
*/
|
||||
srwi r3,r3,8
|
||||
ba push_normalized_frame
|
||||
|
||||
PUBLIC_VAR (default_exception_vector_code_prolog_size)
|
||||
|
||||
default_exception_vector_code_prolog_size= . - default_exception_vector_code_prolog
|
||||
|
||||
.p2align 5
|
||||
PUBLIC_VAR (push_normalized_frame)
|
||||
SYM (push_normalized_frame):
|
||||
stw r3, EXCEPTION_NUMBER_OFFSET(r1)
|
||||
stw r0, GPR0_OFFSET(r1)
|
||||
mfsrr0 r2
|
||||
stw r2, SRR0_FRAME_OFFSET(r1)
|
||||
mfsrr1 r3
|
||||
stw r3, SRR1_FRAME_OFFSET(r1)
|
||||
/*
|
||||
* Save general purpose registers
|
||||
* Already saved in prolog : R1, R2, R3, LR.
|
||||
* Saved a few line above : R0
|
||||
*
|
||||
* Manual says that "stmw" instruction may be slower than
|
||||
* series of individual "stw" but who cares about performance
|
||||
* for the DEFAULT exception handler?
|
||||
*/
|
||||
stmw r4, GPR4_OFFSET(r1) /* save R4->R31 */
|
||||
|
||||
mfcr r31
|
||||
stw r31, EXC_CR_OFFSET(r1)
|
||||
mfctr r30
|
||||
stw r30, EXC_CTR_OFFSET(r1)
|
||||
mfxer r28
|
||||
stw r28, EXC_XER_OFFSET(r1)
|
||||
/*
|
||||
* Enable data and instruction address translation, exception nesting
|
||||
*/
|
||||
mfmsr r3
|
||||
ori r3,r3, MSR_RI | MSR_IR | MSR_DR
|
||||
mtmsr r3
|
||||
SYNC
|
||||
|
||||
/*
|
||||
* Call C exception handler
|
||||
*/
|
||||
addi r3, r1, 0x8
|
||||
bl C_exception_handler
|
||||
/*
|
||||
* Restore registers status
|
||||
*/
|
||||
lwz r31, EXC_CR_OFFSET(r1)
|
||||
mtcr r31
|
||||
lwz r30, EXC_CTR_OFFSET(r1)
|
||||
mtctr r30
|
||||
lwz r29, EXC_LR_OFFSET(r1)
|
||||
mtlr r29
|
||||
lwz r28, EXC_XER_OFFSET(r1)
|
||||
mtxer 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
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
123
c/src/lib/libbsp/powerpc/mcp750/vectors/vectors.h
Normal file
123
c/src/lib/libbsp/powerpc/mcp750/vectors/vectors.h
Normal file
@@ -0,0 +1,123 @@
|
||||
#ifndef LIBBSP_POWERPC_MCP750_VECTORS_H
|
||||
#define LIBBSP_POWERPC_MCP750_VECTORS_H
|
||||
|
||||
/*
|
||||
* The callee (high level exception code written in C)
|
||||
* will store the Link Registers (return address) at entry r1 + 4 !!!.
|
||||
* So let room for it!!!.
|
||||
*/
|
||||
#define LINK_REGISTER_CALLEE_UPDATE_ROOM 4
|
||||
#define SRR0_FRAME_OFFSET 8
|
||||
#define SRR1_FRAME_OFFSET 12
|
||||
#define EXCEPTION_NUMBER_OFFSET 16
|
||||
#define GPR0_OFFSET 20
|
||||
#define GPR1_OFFSET 24
|
||||
#define GPR2_OFFSET 28
|
||||
#define GPR3_OFFSET 32
|
||||
#define GPR4_OFFSET 36
|
||||
#define GPR5_OFFSET 40
|
||||
#define GPR6_OFFSET 44
|
||||
#define GPR7_OFFSET 48
|
||||
#define GPR8_OFFSET 52
|
||||
#define GPR9_OFFSET 56
|
||||
#define GPR10_OFFSET 60
|
||||
#define GPR11_OFFSET 64
|
||||
#define GPR12_OFFSET 68
|
||||
#define GPR13_OFFSET 72
|
||||
#define GPR14_OFFSET 76
|
||||
#define GPR15_OFFSET 80
|
||||
#define GPR16_OFFSET 84
|
||||
#define GPR17_OFFSET 88
|
||||
#define GPR18_OFFSET 92
|
||||
#define GPR19_OFFSET 96
|
||||
#define GPR20_OFFSET 100
|
||||
#define GPR21_OFFSET 104
|
||||
#define GPR22_OFFSET 108
|
||||
#define GPR23_OFFSET 112
|
||||
#define GPR24_OFFSET 116
|
||||
#define GPR25_OFFSET 120
|
||||
#define GPR26_OFFSET 124
|
||||
#define GPR27_OFFSET 128
|
||||
#define GPR28_OFFSET 132
|
||||
#define GPR29_OFFSET 136
|
||||
#define GPR30_OFFSET 140
|
||||
#define GPR31_OFFSET 144
|
||||
#define EXC_CR_OFFSET 148
|
||||
#define EXC_CTR_OFFSET 152
|
||||
#define EXC_XER_OFFSET 156
|
||||
#define EXC_LR_OFFSET 160
|
||||
#define EXC_DAR_OFFSET 164
|
||||
/*
|
||||
* maintain the EABI requested 8 bytes aligment
|
||||
* As SVR4 ABI requires 16, make it 16 (as some
|
||||
* exception may need more registers to be processed...)
|
||||
*/
|
||||
#define EXCEPTION_FRAME_END 176
|
||||
|
||||
#ifndef ASM
|
||||
/*
|
||||
* default raw exception handlers
|
||||
*/
|
||||
|
||||
extern void default_exception_vector_code_prolog();
|
||||
extern int default_exception_vector_code_prolog_size;
|
||||
|
||||
/* 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 *, unsigned int, unsigned long);
|
||||
extern void initialize_exceptions();
|
||||
|
||||
typedef struct {
|
||||
unsigned EXC_SRR0;
|
||||
unsigned EXC_SRR1;
|
||||
unsigned _EXC_number;
|
||||
unsigned GPR0;
|
||||
unsigned GPR1;
|
||||
unsigned GPR2;
|
||||
unsigned GPR3;
|
||||
unsigned GPR4;
|
||||
unsigned GPR5;
|
||||
unsigned GPR6;
|
||||
unsigned GPR7;
|
||||
unsigned GPR8;
|
||||
unsigned GPR9;
|
||||
unsigned GPR10;
|
||||
unsigned GPR11;
|
||||
unsigned GPR12;
|
||||
unsigned GPR13;
|
||||
unsigned GPR14;
|
||||
unsigned GPR15;
|
||||
unsigned GPR16;
|
||||
unsigned GPR17;
|
||||
unsigned GPR18;
|
||||
unsigned GPR19;
|
||||
unsigned GPR20;
|
||||
unsigned GPR21;
|
||||
unsigned GPR22;
|
||||
unsigned GPR23;
|
||||
unsigned GPR24;
|
||||
unsigned GPR25;
|
||||
unsigned GPR26;
|
||||
unsigned GPR27;
|
||||
unsigned GPR28;
|
||||
unsigned GPR29;
|
||||
unsigned GPR30;
|
||||
unsigned GPR31;
|
||||
unsigned EXC_CR;
|
||||
unsigned EXC_CTR;
|
||||
unsigned EXC_XER;
|
||||
unsigned EXC_LR;
|
||||
unsigned EXC_MSR;
|
||||
unsigned EXC_DAR;
|
||||
} exception_frame;
|
||||
|
||||
extern void C_exception_handler(exception_frame* excPtr);
|
||||
|
||||
#endif /* ASM */
|
||||
|
||||
#endif /* LIBBSP_POWERPC_MCP750_VECTORS_H */
|
||||
100
c/src/lib/libbsp/powerpc/mcp750/vectors/vectors_init.c
Normal file
100
c/src/lib/libbsp/powerpc/mcp750/vectors/vectors_init.c
Normal file
@@ -0,0 +1,100 @@
|
||||
/*
|
||||
*
|
||||
*/
|
||||
#include <bsp/vectors.h>
|
||||
#include <libcpu/raw_exception.h>
|
||||
|
||||
static rtems_raw_except_global_settings exception_config;
|
||||
static rtems_raw_except_connect_data exception_table[LAST_VALID_EXC + 1];
|
||||
|
||||
void C_exception_handler(exception_frame* excPtr)
|
||||
{
|
||||
int recoverable = 0;
|
||||
|
||||
printk("exception handler called for exception %d\n", excPtr->_EXC_number);
|
||||
printk("\t Next PC or Address of fault = %x\n", excPtr->EXC_SRR0);
|
||||
printk("\t Saved MSR = %x\n", excPtr->EXC_SRR1);
|
||||
printk("\t R0 = %x\n", excPtr->GPR0);
|
||||
printk("\t R1 = %x\n", excPtr->GPR1);
|
||||
printk("\t R2 = %x\n", excPtr->GPR2);
|
||||
printk("\t R3 = %x\n", excPtr->GPR3);
|
||||
printk("\t R4 = %x\n", excPtr->GPR4);
|
||||
printk("\t R5 = %x\n", excPtr->GPR5);
|
||||
printk("\t R6 = %x\n", excPtr->GPR6);
|
||||
printk("\t R7 = %x\n", excPtr->GPR7);
|
||||
printk("\t R8 = %x\n", excPtr->GPR8);
|
||||
printk("\t R9 = %x\n", excPtr->GPR9);
|
||||
printk("\t R10 = %x\n", excPtr->GPR10);
|
||||
printk("\t R11 = %x\n", excPtr->GPR11);
|
||||
printk("\t R12 = %x\n", excPtr->GPR12);
|
||||
printk("\t R13 = %x\n", excPtr->GPR13);
|
||||
printk("\t R14 = %x\n", excPtr->GPR14);
|
||||
printk("\t R15 = %x\n", excPtr->GPR15);
|
||||
printk("\t R16 = %x\n", excPtr->GPR16);
|
||||
printk("\t R17 = %x\n", excPtr->GPR17);
|
||||
printk("\t R18 = %x\n", excPtr->GPR18);
|
||||
printk("\t R19 = %x\n", excPtr->GPR19);
|
||||
printk("\t R20 = %x\n", excPtr->GPR20);
|
||||
printk("\t R21 = %x\n", excPtr->GPR21);
|
||||
printk("\t R22 = %x\n", excPtr->GPR22);
|
||||
printk("\t R23 = %x\n", excPtr->GPR23);
|
||||
printk("\t R24 = %x\n", excPtr->GPR24);
|
||||
printk("\t R25 = %x\n", excPtr->GPR25);
|
||||
printk("\t R26 = %x\n", excPtr->GPR26);
|
||||
printk("\t R27 = %x\n", excPtr->GPR27);
|
||||
printk("\t R28 = %x\n", excPtr->GPR28);
|
||||
printk("\t R29 = %x\n", excPtr->GPR29);
|
||||
printk("\t R30 = %x\n", excPtr->GPR30);
|
||||
printk("\t R31 = %x\n", excPtr->GPR31);
|
||||
printk("\t CR = %x\n", excPtr->EXC_CR);
|
||||
printk("\t CTR = %x\n", excPtr->EXC_CTR);
|
||||
printk("\t XER = %x\n", excPtr->EXC_XER);
|
||||
printk("\t LR = %x\n", excPtr->EXC_LR);
|
||||
printk("\t MSR = %x\n", excPtr->EXC_MSR);
|
||||
if ( (excPtr->_EXC_number == ASM_DEC_VECTOR) ||
|
||||
(excPtr->_EXC_number == ASM_SYS_VECTOR)
|
||||
)
|
||||
recoverable = 1;
|
||||
if (!recoverable) BSP_panic("unrecoverable exception!!! Push reset button\n");
|
||||
}
|
||||
|
||||
void nop_except_enable(const rtems_raw_except_connect_data* ptr)
|
||||
{
|
||||
}
|
||||
int except_always_enabled(const rtems_raw_except_connect_data* ptr)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
void initialize_exceptions()
|
||||
{
|
||||
int i;
|
||||
|
||||
exception_config.exceptSize = LAST_VALID_EXC + 1;
|
||||
exception_config.rawExceptHdlTbl = &exception_table[0];
|
||||
exception_config.defaultRawEntry.exceptIndex = 0;
|
||||
exception_config.defaultRawEntry.hdl.vector = 0;
|
||||
exception_config.defaultRawEntry.hdl.raw_hdl = default_exception_vector_code_prolog;
|
||||
/*
|
||||
* Note that next line the '&' before default_exception_vector_code_prolog_size
|
||||
* is not a bug as it is defined a .set directly in asm...
|
||||
*/
|
||||
exception_config.defaultRawEntry.hdl.raw_hdl_size = (unsigned) &default_exception_vector_code_prolog_size;
|
||||
for (i=0; i <= exception_config.exceptSize; i++) {
|
||||
if (!mpc750_vector_is_valid (i)) {
|
||||
continue;
|
||||
}
|
||||
exception_table[i].exceptIndex = i;
|
||||
exception_table[i].hdl = exception_config.defaultRawEntry.hdl;
|
||||
exception_table[i].hdl.vector = i;
|
||||
exception_table[i].on = nop_except_enable;
|
||||
exception_table[i].off = nop_except_enable;
|
||||
exception_table[i].isOn = except_always_enabled;
|
||||
}
|
||||
if (!mpc60x_init_exceptions(&exception_config)) {
|
||||
BSP_panic("Exception handling initialization failed\n");
|
||||
}
|
||||
else {
|
||||
printk("Exception handling initialization done\n");
|
||||
}
|
||||
}
|
||||
59
c/src/lib/libbsp/powerpc/mcp750/wrapup/Makefile.in
Normal file
59
c/src/lib/libbsp/powerpc/mcp750/wrapup/Makefile.in
Normal file
@@ -0,0 +1,59 @@
|
||||
#
|
||||
# $Id$
|
||||
#
|
||||
|
||||
@SET_MAKE@
|
||||
srcdir = @srcdir@
|
||||
top_srcdir = @top_srcdir@
|
||||
top_builddir = ../../../../../../..
|
||||
subdir = c/src/lib/libbsp/powerpc/mpc750/wrapup
|
||||
|
||||
INSTALL = @INSTALL@
|
||||
|
||||
RTEMS_ROOT = $(top_srcdir)/@RTEMS_TOPdir@
|
||||
PROJECT_ROOT = @PROJECT_ROOT@
|
||||
|
||||
VPATH = @srcdir@
|
||||
|
||||
BSP_PIECES=console irq openpic pci residual startup vectors
|
||||
GENERIC_PIECES=
|
||||
|
||||
# bummer; have to use $foreach since % pattern subst rules only replace 1x
|
||||
OBJS=$(foreach piece, $(BSP_PIECES), ../$(piece)/$(ARCH)/*.o) \
|
||||
$(foreach piece, $(GENERIC_PIECES), ../../../$(piece)/$(ARCH)/*.o)
|
||||
LIB=$(ARCH)/libbsp.a
|
||||
|
||||
include $(RTEMS_ROOT)/make/custom/${RTEMS_BSP}.cfg
|
||||
include $(RTEMS_ROOT)/make/lib.cfg
|
||||
|
||||
#
|
||||
# (OPTIONAL) Add local stuff here using +=
|
||||
#
|
||||
|
||||
DEFINES +=
|
||||
CPPFLAGS +=
|
||||
CFLAGS +=
|
||||
|
||||
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 +=
|
||||
|
||||
$(LIB): ${OBJS}
|
||||
$(make-library)
|
||||
|
||||
all: ${ARCH} $(SRCS) $(LIB)
|
||||
$(INSTALL_VARIANT) -m 644 $(LIB) ${PROJECT_RELEASE}/lib
|
||||
|
||||
Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
|
||||
cd $(top_builddir) \
|
||||
&& CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status
|
||||
20
c/src/lib/libbsp/powerpc/motorola_powerpc/Makefile.in
Normal file
20
c/src/lib/libbsp/powerpc/motorola_powerpc/Makefile.in
Normal file
@@ -0,0 +1,20 @@
|
||||
#
|
||||
# $Id$
|
||||
#
|
||||
|
||||
@SET_MAKE@
|
||||
srcdir = @srcdir@
|
||||
VPATH = @srcdir@
|
||||
RTEMS_ROOT = @top_srcdir@
|
||||
PROJECT_ROOT = @PROJECT_ROOT@
|
||||
|
||||
include $(RTEMS_ROOT)/make/custom/$(RTEMS_BSP).cfg
|
||||
include $(RTEMS_ROOT)/make/directory.cfg
|
||||
|
||||
SRCS=README
|
||||
|
||||
all: $(SRCS)
|
||||
|
||||
# wrapup is the one that actually builds and installs the library
|
||||
# from the individual .rel files built in other directories
|
||||
SUB_DIRS= console include pci residual openpic irq vectors start startup bootloader wrapup
|
||||
48
c/src/lib/libbsp/powerpc/motorola_powerpc/README
Normal file
48
c/src/lib/libbsp/powerpc/motorola_powerpc/README
Normal file
@@ -0,0 +1,48 @@
|
||||
#
|
||||
# $Id$
|
||||
#
|
||||
|
||||
BSP NAME: MCP750
|
||||
BOARD: MCP750 from motorola
|
||||
BUS: PCI
|
||||
CPU FAMILY: ppc
|
||||
CPU: PowerPC 750
|
||||
COPROCESSORS: N/A
|
||||
MODE: 32 bit mode
|
||||
|
||||
DEBUG MONITOR: PPCBUG mode
|
||||
|
||||
PERIPHERALS
|
||||
===========
|
||||
TIMERS: PPC internal Timebase register
|
||||
RESOLUTION: ???
|
||||
SERIAL PORTS: simulated via bug
|
||||
REAL-TIME CLOCK: PPC internal Decrementer register
|
||||
DMA: none
|
||||
VIDEO: none
|
||||
SCSI: none
|
||||
NETWORKING: DEC21140
|
||||
|
||||
DRIVER INFORMATION
|
||||
==================
|
||||
CLOCK DRIVER: PPC internal
|
||||
IOSUPP DRIVER: N/A
|
||||
SHMSUPP: N/A
|
||||
TIMER DRIVER: PPC internal
|
||||
TTY DRIVER: PPC internal
|
||||
|
||||
STDIO
|
||||
=====
|
||||
PORT: Console port 0
|
||||
ELECTRICAL: na
|
||||
BAUD: na
|
||||
BITS PER CHARACTER: na
|
||||
PARITY: na
|
||||
STOP BITS: na
|
||||
|
||||
Notes
|
||||
=====
|
||||
|
||||
Based on papyrus bsp which only really supports
|
||||
the PowerOpen ABI with an ELF assembler.
|
||||
|
||||
@@ -0,0 +1,84 @@
|
||||
#
|
||||
# $Id:
|
||||
#
|
||||
|
||||
@SET_MAKE@
|
||||
srcdir = @srcdir@
|
||||
VPATH = @srcdir@:@srcdir@/../../../shared:@srcdir@/../console
|
||||
RTEMS_ROOT = @top_srcdir@
|
||||
PROJECT_ROOT = @PROJECT_ROOT@
|
||||
|
||||
# C source names, if any, go here -- minus the .c
|
||||
C_PIECES=misc pci zlib mm em86 polled_io
|
||||
C_FILES=$(C_PIECES:%=%.c)
|
||||
C_O_FILES=$(C_PIECES:%=${ARCH}/%.o)
|
||||
|
||||
H_FILES=bootldr.h zlib.h pci.h
|
||||
|
||||
# Assembly source names, if any, go here -- minus the .s
|
||||
S_PIECES=head exception em86real consoleLib
|
||||
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
|
||||
|
||||
CC_PIECES=
|
||||
CC_FILES=$(CC_PIECES:%=%.cc)
|
||||
CC_O_FILES=$(CC_PIECES:%=${ARCH}/%.o)
|
||||
|
||||
|
||||
#
|
||||
# (OPTIONAL) Add local stuff here using +=
|
||||
#
|
||||
|
||||
DEFINES +=
|
||||
CPPFLAGS += -D__BOOT__ -DDEBUG
|
||||
CFLAGS += -msoft-float -mstrict-align -fno-builtin -Wall -mmultiple -mstring \
|
||||
-O2 -fomit-frame-pointer -mrelocatable -ffixed-r13 \
|
||||
-mno-sdata -D__BOOT__ -DDEBUG
|
||||
|
||||
ASFLAGS += -mrelocatable
|
||||
|
||||
LD_PATHS +=
|
||||
LD_LIBS +=
|
||||
LDFLAGS +=
|
||||
|
||||
IMAGES := rtems.gz
|
||||
|
||||
#
|
||||
# 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 += bootloader
|
||||
CLOBBER_ADDITIONS += $(IMAGES)
|
||||
|
||||
bootloader : ${OBJS} $(IMAGES) $(BINARY_LOADED) ppcboot.lds
|
||||
$(LD) -o bootloader $(OBJS) --just-symbols=$(BINARY_LOADED) \
|
||||
-b binary $(IMAGES) -T @srcdir@/ppcboot.lds \
|
||||
-Map bootloader.map
|
||||
|
||||
rtems.gz: $(BINARY_LOADED)
|
||||
$(OBJCOPY) $(BINARY_LOADED) rtems -O binary -R .comment -S
|
||||
gzip -vf9 rtems
|
||||
rm -f rtems
|
||||
|
||||
|
||||
all: ${ARCH} $(SRCS) ${OBJ}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
251
c/src/lib/libbsp/powerpc/motorola_powerpc/bootloader/bootldr.h
Normal file
251
c/src/lib/libbsp/powerpc/motorola_powerpc/bootloader/bootldr.h
Normal file
@@ -0,0 +1,251 @@
|
||||
/*
|
||||
* include/asm-ppc/bloader.h -- Include file for bootloader.
|
||||
*
|
||||
* Copyright (C) 1998 Gabriel Paubert, paubert@iram.es
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#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
|
||||
|
||||
|
||||
|
||||
563
c/src/lib/libbsp/powerpc/motorola_powerpc/bootloader/em86.c
Normal file
563
c/src/lib/libbsp/powerpc/motorola_powerpc/bootloader/em86.c
Normal file
@@ -0,0 +1,563 @@
|
||||
/*****************************************************************************
|
||||
*
|
||||
* 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);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
4554
c/src/lib/libbsp/powerpc/motorola_powerpc/bootloader/em86real.S
Normal file
4554
c/src/lib/libbsp/powerpc/motorola_powerpc/bootloader/em86real.S
Normal file
File diff suppressed because it is too large
Load Diff
466
c/src/lib/libbsp/powerpc/motorola_powerpc/bootloader/exception.S
Normal file
466
c/src/lib/libbsp/powerpc/motorola_powerpc/bootloader/exception.S
Normal file
@@ -0,0 +1,466 @@
|
||||
/*
|
||||
* arch/ppc/loader/exceotion.S -- Exception handlers for early boot.
|
||||
*
|
||||
* Copyright (C) 1998 Gabriel Paubert, paubert@iram.es
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/* 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
|
||||
379
c/src/lib/libbsp/powerpc/motorola_powerpc/bootloader/head.S
Normal file
379
c/src/lib/libbsp/powerpc/motorola_powerpc/bootloader/head.S
Normal file
@@ -0,0 +1,379 @@
|
||||
/*
|
||||
* $Id$
|
||||
*
|
||||
* This code is loaded by the ROM loader at some arbitrary location.
|
||||
* Move it to high memory so that it can load the kernel at 0x0000.
|
||||
*
|
||||
*/
|
||||
|
||||
#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
|
||||
|
||||
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: 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
|
||||
1: mfmsr r10
|
||||
ori r10,r10,MSR_IP
|
||||
mtmsr r10
|
||||
li r10,0x63
|
||||
sc
|
||||
#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
|
||||
/* A few utility functions, some copied from arch/ppc/lib/string.S */
|
||||
|
||||
#if 0
|
||||
.globl strnlen
|
||||
.type strnlen,@function
|
||||
strnlen:
|
||||
addi r4,r4,1
|
||||
mtctr r4
|
||||
addi r4,r3,-1
|
||||
1: lbzu r0,1(r4)
|
||||
cmpwi 0,r0,0
|
||||
bdnzf eq,1b
|
||||
subf r3,r3,r4
|
||||
blr
|
||||
#endif
|
||||
.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
|
||||
525
c/src/lib/libbsp/powerpc/motorola_powerpc/bootloader/misc.c
Normal file
525
c/src/lib/libbsp/powerpc/motorola_powerpc/bootloader/misc.c
Normal file
@@ -0,0 +1,525 @@
|
||||
/*
|
||||
* arch/ppc/prepboot/misc.c
|
||||
*
|
||||
* Copyright (C) 1998 Gabriel Paubert, paubert@iram.es
|
||||
*
|
||||
* This file is based on arch/ppc/boot misc.c in previous versions of
|
||||
* Linux/PPC but has been so extensively changed that only a few lines
|
||||
* remain from the original.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#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);
|
||||
}
|
||||
975
c/src/lib/libbsp/powerpc/motorola_powerpc/bootloader/mm.c
Normal file
975
c/src/lib/libbsp/powerpc/motorola_powerpc/bootloader/mm.c
Normal file
@@ -0,0 +1,975 @@
|
||||
/*
|
||||
* arch/ppc/prepboot/mm.c -- Crude memory management for early boot.
|
||||
*
|
||||
* Copyright (C) 1998 Gabriel Paubert, paubert@iram.es
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/* 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
|
||||
928
c/src/lib/libbsp/powerpc/motorola_powerpc/bootloader/pci.c
Normal file
928
c/src/lib/libbsp/powerpc/motorola_powerpc/bootloader/pci.c
Normal file
@@ -0,0 +1,928 @@
|
||||
/*
|
||||
* arch/ppc/prepboot/pci.c -- Crude pci handling for early boot.
|
||||
*
|
||||
* Copyright (C) 1998 Gabriel Paubert, paubert@iram.es
|
||||
*
|
||||
* The pci_scan_bus and pci_read_bases functions are slightly modified
|
||||
* versions of functions with the same name in linux/drivers/pci.c by
|
||||
* Martin Mares (mj@ucw.cz) and others (taken around linux-2.1.120).
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
|
||||
#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");
|
||||
}
|
||||
|
||||
1159
c/src/lib/libbsp/powerpc/motorola_powerpc/bootloader/pci.h
Normal file
1159
c/src/lib/libbsp/powerpc/motorola_powerpc/bootloader/pci.h
Normal file
File diff suppressed because it is too large
Load Diff
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
2143
c/src/lib/libbsp/powerpc/motorola_powerpc/bootloader/zlib.c
Normal file
2143
c/src/lib/libbsp/powerpc/motorola_powerpc/bootloader/zlib.c
Normal file
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user