From 2e8d1bc3b6aa0671995860ca8a09c97523f3538d Mon Sep 17 00:00:00 2001 From: Miguel Date: Thu, 11 Oct 2018 19:48:02 +0200 Subject: ported ncurses almost ! ncurses-examples work almost fine now!!! --- README.md | 3 +- ref/README | 1 + ref/ean9-howto-newlib-1.0.html | 3432 ++++++++++++++++++++++++++++++++++++++++ userspace/ncurses/Makefile | 9 +- userspace/ncurses/ncurs.c | 66 +- userspace/sysc.c | 4 + 6 files changed, 3509 insertions(+), 6 deletions(-) create mode 100644 ref/ean9-howto-newlib-1.0.html create mode 100644 userspace/sysc.c diff --git a/README.md b/README.md index 7b3e289..ccf9710 100644 --- a/README.md +++ b/README.md @@ -107,6 +107,7 @@ Todos * TODO: check Kernel Stuff Reentrancy? multicpu? interrupt syscall processing? Cleanup syscalls * TODO: GCC optimizations (break kernel?) / volatile keyword etc? * TODO: gcc-foolos (Porting (ncurses, gcc, binutils, vim, apache...) +* TODO: why do we provide 2 versions of syscalls (underscore and no underscore?) for newlib (non underscore collide with standard!) * EXTRA: fallback to pic/pit @@ -144,7 +145,7 @@ Todos * ref: Cross Porting Software * ncurses: ../ncurses-6.1/configure --host=i686-foolos --without-tests - --with-fallbacks="fool-term" --with-debug --prefix=/usr --with-termlib --without-progs + --with-fallbacks="fool-term" --with-debug --prefix=/usr --with-termlib * ncurses-examples: ../ncurses-examples-20180127/configure --host=i686-foolos --prefix=/usr --with-ncurses make DESTDIR=/home/miguel/temp/foolos/ install diff --git a/ref/README b/ref/README index 70d9e39..ed8a58d 100644 --- a/ref/README +++ b/ref/README @@ -1 +1,2 @@ https://wiki.osdev.org/ +https://www.embecosm.com/appnotes/ean9/ean9-howto-newlib-1.0.html diff --git a/ref/ean9-howto-newlib-1.0.html b/ref/ean9-howto-newlib-1.0.html new file mode 100644 index 0000000..a6a58bf --- /dev/null +++ b/ref/ean9-howto-newlib-1.0.html @@ -0,0 +1,3432 @@ + + +Howto: Porting newlib
+ Services and Modeling for Embedded Software Development +
Embecosm divider strip

+ Howto: Porting newlib +

+ A Simple Guide +

Jeremy Bennett

+ Embecosm +

+ Application Note 9. Issue 1 +

+ July 2010 +


Table of Contents

1. + Introduction +
1.1. + Target Audience +
1.2. + Examples +
1.3. + Further information +
1.4. + About Embecosm Application Notes +
2. + newlib within the GNU Tool Chain +
2.1. + The Unified Source Tree +
2.1.1. + Incorporating Newlib within the Tool Chain Build +
3. + Overview of newlib +
3.1. + The relationship between libgloss and newlib +
3.2. + The C Namespace and Reentrant Functions +
3.3. + Adding a new Target to Newlib +
3.3.1. + Extending configure.host for a New Target +
4. + Modifying newlib +
4.1. + The Machine Directory +
4.1.1. + Updating the Main Machine Directory Configuration files +
4.1.2. + Implementing the setjmp and + longjmp functions. +
4.1.3. + Updating the Target Specific Machine Directory Configuration files +
4.2. + Changing Headers +
4.2.1. + IEEE Floating Point +
4.2.2. + setjmp Buffer Size +
4.2.3. + Miscellaneous System Definitions +
4.2.4. + Overriding Other Header Files +
5. + Modifying libgloss +
5.1. + The Platform Directory +
5.1.1. + Ensuring the Platform Directory is Configured +
5.2. + The C Runtime Initialization, crt0.o +
5.2.1. + Exception vector setup +
5.2.2. + The _start Function and Stack Initialization +
5.2.3. + Cache Initialization +
5.2.4. + Clearing BSS +
5.2.5. + Constructor and Destructor Handling +
5.2.6. + C Initialization Functions +
5.2.7. + Invoking the main program +
5.3. + Standard System Call Implementations +
5.3.1. + Error Handling +
5.3.2. + The Global Environment, environ +
5.3.3. + Exit a program, _exit +
5.3.4. + Closing a file, close +
5.3.5. + Transfer Control to a New Process, execve +
5.3.6. + Create a new process, fork +
5.3.7. + Provide the Status of an Open File, fstat +
5.3.8. + Get the Current Process ID, getpid +
5.3.9. + Determine the Nature of a Stream, isatty +
5.3.10. + Send a Signal, kill +
5.3.11. + Rename an existing file, link +
5.3.12. + Set Position in a File, lseek +
5.3.13. + Open a file, open +
5.3.14. + Read from a File, read +
5.3.15. + Allocate more Heap, sbrk +
5.3.16. + Status of a File (by Name), stat +
5.3.17. + Provide Process Timing Information, times +
5.3.18. + Remove a File's Directory Entry, unlink +
5.3.19. + Wait for a Child Process, wait +
5.3.20. + Write to a File, write +
5.4. + Reentrant System Call Implementations +
5.5. + BSP Configuration and Make file; +
5.5.1. + configure.in for the BSP +
5.5.2. + Makefile.in for the BSP +
5.6. + The Default BSP, libnosys +
6. + Configuring, Building and Installing Newlib and Libgloss +
6.1. + Configuring Newlib and Libgloss +
6.2. + Building Newlib and Libgloss +
6.3. + Testing Newlib and Libgloss +
6.4. + Installing Newlib and Libgloss +
7. + Modifying the GNU Tool Chain +
7.1. + Putting Newlib in a Custom Location +
7.2. + Changes to GCC +
7.2.1. + Adding Machine Specific Options for Newlib +
7.2.2. + Updating Spec Definitions +
7.3. + Changes to the GNU Linker +
8. + Testing Newlib and Libgloss +
8.1. + Testing Newlib +
8.1.1. + Checking Physical Hardware +
8.2. + Testing Libgloss +
9. + Summary Checklist +
+ Glossary +
+ References +

Chapter 1.  + Introduction +

+ Newlib is a C library intended for use on embedded systems. It is a + conglomeration of several library parts, all under free software + licenses that make them easily usable on embedded products. +

1.1.  + Target Audience +

+ Porting newlib is not difficult, but advice for the beginner is thin + on the ground. This application note is intended for software + engineers porting newlib for the first time. +

+ The detail of all the steps needed are covered here, and have been + tested using newlib versions 1.17.0 and 1.18.0 with the + OpenRISC 1000 . +

+ For those who already have some experience, the entire porting process + is summarized in the final chapter, with links back to the main + document (see Chapter 9). It's a + useful checklist when carrying out a new port. +

1.2.  + Examples +

+ This application note includes examples from the port of newlib to + the OpenRISC 1000  architecture, originally by Chris Bower, then of + Imperial College, London, and subsequently extensively updated by + Jeremy Bennett of Embecosm. +

+ The examples are two Board Support Packages + (BSP) for use with the OpenRISC 1000  architectural simulator Or1ksim + by the same two authors. +

+ At the time of writing the OpenRISC 1000  implementation is + not part of the main newlib distribution. It can be downloaded from + OpenCores (www.opencores.org). +

1.3.  + Further information +

+ The main source of information is the newlib website (sourceware.org/newlib). This + includes a FAQ, which has brief instructions on porting newlib and + documentation for libc [1] and libm, the + two libraries making up newlib. The libc documentation is + particularly useful, because it lists the system calls which must be + implemented by any new port, including minimal implementations. +

+ The newlib README is another source of + information. Key header files within the source also contain useful + commenting, notably ieeefp.h and + reent.h. +

+ There is also a mailing list, + where questions can be asked, or new ports submitted. +

+ This application note does not cover the detail of testing newlib + on physical hardware. That subject is well covered by Dan Kegel's + Crosstool project [2]. +

+ This application note has drawn heavily on these sources, and the + author would like to thank the providers of that original information. +

1.4.  + About Embecosm Application Notes +

+ Embecosm is a consultancy specializing in hardware + modeling and open source tool chains for the embedded market. If we + can ever be of help, please get in touch at + . +

+ As part of its commitment to the open source community, Embecosm + publishes a series of free and open source application notes, designed + to help working engineers with practical problems. +

+ Feedback is always welcome, which should be sent to + . +

Chapter 2.  + newlib within the GNU Tool Chain +

+ Newlib is intended for use with the GNU tool chain. If newlib is + included within the build of the GNU tool chain, then all the + libraries will be built and installed in the correct places to be found + by GCC +

2.1.  + The Unified Source Tree +

+ The three separate packages, binutils, GCC and GDB are all taken + from a common source tree. GCC and GDB both use many libraries + from binutils. It is convenient to reassemble that source tree and + make a single build of all the tools together. +

+ The easiest way to achieve this is to link all the top level + directories in each package into a single unified directory, leaving + out any duplicated files or directories. +

+ The following bash script will take unpacked distributions of + binutils GCC and GDB and link them into a single directory, + srcw. +

+#!/bin/bash
+
+component_dirs='binutils-2.18.50 gcc-4.2.2 gdb-6.8'
+unified_src=srcw
+
+cd ${unified_src}
+ignore_list=". .. CVS .svn"
+    
+for srcdir in ${component_dirs}
+do
+    echo "Component: $srcdir"
+    case srcdir
+        in
+        /* | [A-Za-z]:[\\/]*)
+            ;;
+            
+        *)
+            srcdir="../${srcdir}"
+            ;;
+    esac
+        
+    files=`ls -a ${srcdir}`
+        
+    for f in ${files}
+    do
+        found=
+            
+        for i in ${ignore_list}
+        do
+            if [ "$f" = "$i" ]
+            then
+                found=yes
+            fi
+        done
+            
+        if [ -z "${found}" ]
+        then
+            echo "$f            ..linked"
+            ln -s ${srcdir}/$f .
+        fi
+    done
+
+    ignore_list="${ignore_list} ${files}"
+done
+
+cd ..
+	

+ The entire tool chain can then be configured and built in a separate + directory. The configure script understands to + pass on top level arguments to subsidiary configuration scripts. For + example to configure to build a C only tool chain for the 32-bit + OpenRISC 1000  architecture to be installed in + /opt/or32-elf, the following would be + appropriate. +

+mkdir build
+cd build
+../src/configure --target=or32-elf --enable-languages=c --prefix=/opt/or32-elf
+cd ..
+	

+ Each tool can be built with its own specific target within that build + directory +

+cd build
+make all-build all-binutils all-gas all-ld all-gcc all-gdb
+cd ..
+	
[Note]Note

+ The initial make target, all-build is used to + build some of the baseline libraries and tools used throughout the + tool chain. +

+ Similarly the tools can be installed using the following: +

+cd build
+make install-build install-binutils install-gas install-ld install-gcc \
+     install-gdb
+cd ..
+	

2.1.1.  + Incorporating Newlib within the Tool Chain Build +

+ Newlib can be linked into the unified source directory in the same + fashion. All that is needed is to add newlib to the component + directories in the linking script. +

+#!/bin/bash
+
+component_dirs='binutils-2.18.50 gcc-4.2.2 newlib-1.18.0 gdb-6.8'
+unified_src=srcw
+...
+	  

+ The configuration command should also specify that this is a build + using newlib +

+mkdir build
+cd build
+../src/configure --target=or32-elf --enable-languages=c --with-newlib \
+                 --prefix=/opt/or32-elf
+cd ..
+	

+ Two new targets are needed for newlib, one to build newlib itself, + and one to build any board support packages using libgloss (see + Chapter 3 for an explanation of how libgloss + is used with newlib). +

+cd build
+make all-build all-binutils all-gas all-ld all-gcc all-target-newlib \
+     all-target-libgloss all-gdb
+cd ..
+	

+ Similarly additional targets are needed for installation. +

+cd build
+make install-build install-binutils install-gas install-ld install-gcc \
+     install-target-newlib install-target-libgloss install-gdb
+cd ..
+	

Chapter 3.  + Overview of newlib +

+

3.1.  + The relationship between libgloss and newlib +

+ Newlib is now divided into two parts. The main + newlib directory contains the bulk of the code + for the two main libraries, libc and libm, together with any + architecture specific code for particular + targets. +

+ The libgloss directory contains code specific to + particular platforms on which the library will be used, generally + referred to as the Board Support Package + (BSP). Any particular target architecture may have multiple BSPs, + for example for different hardware platforms, for a simulator etc. +

+ The target architecture specific code within the + newlib directory may be very modest - possibly as + little as an implementation of setjmp and a + specification of the IEEE floating point format to use. +

+ The board support package is more complex. It requires an + implementation of eighteen system calls and the definition of one + global data structure, although the implementation of some of those + system calls may be completely trivial. +

[Note]Note

+ The separation of BSP implementation into libgloss is relatively + recent. Consequently the source tree contains a number of older + target implementations where the BSP is entirely within + newlib. When looking for examples, be sure to choose an + architecture which has been implemented through libgloss. The + OpenRISC 1000  implementation is one such architecture. +

3.2.  + The C Namespace and Reentrant Functions +

+ The BSP implements the system calls—functions like + close, write etc. It is + possible for the BSP to implement these directly, but these will + then be defined in the main C namespace. It is perfectly permissible + for the user to replace these functions, and the user versions take + precedence, which requires some care at link time. +

+ Newlib allows the implementer instead to provide namespace clean + versions of these functions by prefixing them with an + underscore. Newlib will ensure that the system calls map to these + namespace clean version (i.e. a call to close + becomes a call to _close) unless the user has + reimplemented that function themselves. +

+ A reentrant function may be safely called from + a second thread, while a first thread of control is executing. In + general a function that modifies no static or global state, will be + reentrant. +

+ Many system calls are trivially reentrant. However for some calls, + reentrancy is not easy to provide automatically, so reentrant versions + are provided. Thus for close, there is the + reentrant version close_r. The reentrant versions + take an extra argument, a reentrancy structure, + which can be used to ensure correct behavior, by providing per-thread + versions of global data structures. +

+ It is worth noting that use of the global error value, + errno is a common source of non-reentrancy. The + standard reentrancy structure includes an entry for a per-thread value + of errno. +

+ For many systems, the issue of reentrancy does not arise. If there is + only ever one thread of control, or if separate threads have their own + address space there is no problem. +

+ However it's worth remembering that even a bare metal system may + encounter issues with reentrancy if event handlers are allowed to use + the system calls. +

+ Newlib gives considerable flexibility, particularly where namespace + clean versions of the basic system calls are implemented. The + implementer can choose to provide implementations of the reentrant + versions of the functions. Alternatively newlib can provide + reentrancy at the library level, but mapping the calls down the system + calls, which are not themselves reentrant. This last can often prove + a practical solution to the problem. +

3.3.  + Adding a new Target to Newlib +

+ Adding a new architecture to newlib requires the following steps. +

  1. + Provide a machine specific directory within the + newlib directory for architecture specific + code, notably the setjmp implementation. +

  2. + Provide a platform directory for BSP implementation(s) within + the libgloss directory. The code implementing + systems calls for each BSP is placed in this directory. +

  3. + Update the configure.host file in the + newlib directory to point to the machine and + platform directories for the new target. +

3.3.1.  + Extending configure.host for a New Target +

+ The configure.host file needs changes in two + places, to identify the architecture specific machine directory and + the platform directory for BSP implementations. +

+ The machine name is specified in a case switch on + the ${host_cpu} early on in the file. Add a new + case entry defining + machine_type for the architecture. Thus for + OpenRISC 1000  32-bit architecture we have: +

+  or32)
+        machine_dir=or32
+        ;;
+	  

+ This specifies that the machine specific code for this architecture + will be found in the directory + newlib/libc/machine/or32. +

+ The platform directory and details are specified in a subsequent + case switch on ${host} + (i.e. the full triplet, not just the CPU type). + For the 32-bit OpenRISC 1000  we have the following. +

+  or32-*-*)
+        syscall_dir=syscalls
+        ;;
+	  

+ This is the simplest option, specifying that the BSPs for all + OpenRISC 1000  32-bit targets will implement namespace clean system calls, + and rely on newlib to map reentrant calls down to them. The + directory name for the BSP implementations will match that of the + machine directory, but within the libgloss + directory. So for OpenRISC 1000  32-bit targets; the BSP implementations + are in libgloss/or32. +

+ There are four common alternatives for specifying how the BSP + will be implemented. +

  1. + The implementer defines reentrant namespace clean versions of + the system calls. In this case, syscall_dir + is set to syscalls as above, but in addition, + -DREENTRANT_SYSCALLS_PROVIDED is added to + newlib_cflags in + configure.host. For the OpenRISC 1000  32-bit + target we could have done this with: +

    +  or32-*-*)
    +        syscall_dir=syscalls
    +        newlib_cflags="${newlib_cflags} -DREENTRANT_SYSCALLS_PROVIDED"
    +        ;;
    +		

    +

    + For convenience, stub versions of the reentrant functions may + be found in the libc/reent directory. These + are in fact the functions used if the reentrant system calls are + not provided, and map to the non-reentrant versions. +

  2. + The implementer defines non-reentrant, but namespace clean + versions of the system calls. This is the approach we have used + with the OpenRISC 1000  and all the implementer needs to do in this case + is to set syscall_dir to + syscalls in + configure.host. newlib will map reentrant + calls down to the non-reentrant versions. +

  3. + The implementer defines non-reentrant, regular + versions of the system calls (i.e. close + rather than _close). The library will + be neither reentrant, not namespace clean, but will work. In + this case, + -DMISSING_SYSCALL_NAMES is + added to newlib_cflags in + configure.host. For the OpenRISC 1000  we could + have done this with: +

    +  or32-*-*)
    +        newlib_cflags="${newlib_cflags} -DMISSING_SYSCALL_NAMES"
    +        ;;
    +		

    +

    + Note in particular that syscall_dir is not + defined in this case. +

  4. + The implementer defines non-reentrant, regular + versions of the system calls (i.e. close + rather than _close). The reentrant system + calls are mapped onto these functions. The library will + not be namespace clean, but will offer reentrancy at the library + level. In + this case, + -DMISSING_SYSCALL_NAMES and + -DREENTRANT_SYSCALLS_PROVIDED are both + added to newlib_cflags in + configure.host. For the OpenRISC 1000  we could + have done this with: +

    +  or32-*-*)
    +        newlib_cflags="${newlib_cflags} -DMISSING_SYSCALL_NAMES"
    +        newlib_cflags="${newlib_cflags} -DREENTRANT_SYSCALLS_PROVIDED"
    +        ;;
    +		

    +

    + Note in particular that syscall_dir is not + defined in this case. +

Chapter 4.  + Modifying newlib +

+ Changes that depend on the architecture, and not the particular platform + being used, are made in the newlib directory. These + comprise changes to standard headers and custom code for the + architecture. +

4.1.  + The Machine Directory +

+ Within the newlib directory, machine specific + code is placed in a target specific directory, + libc/machine/arch. +

+ The only code that has to be there is the implementation of + setjmp and longjmp, since + the implementation of these two functions invariably requires target + specific machine code. However any other target specific code may + also be placed here. +

4.1.1.  + Updating the Main Machine Directory Configuration files +

+ The machine directory uses GNU autoconf and automake for + configuration. There is a configuration template file + (configure.in) and Makefile template + (Makefile.am) in the main machine directory + (libc/machine within the + newlib directory). +

+ configure.ac contains a case + statement configuring the target specific subdirectories. This must + be updated to configure the subdirectory for the new target. Thus + for the OpenRISC 1000  we have the following. +

+if test -n "${machine_dir}"; then
+  case ${machine_dir} in
+        a29k) AC_CONFIG_SUBDIRS(a29k) ;;
+        arm) AC_CONFIG_SUBDIRS(arm) ;;
+
+	<other machines not shown>
+
+        necv70) AC_CONFIG_SUBDIRS(necv70) ;;
+        or32) AC_CONFIG_SUBDIRS(or32) ;;
+        powerpc) AC_CONFIG_SUBDIRS(powerpc) ;;
+
+	<other machines not shown>
+
+        xstormy16) AC_CONFIG_SUBDIRS(xstormy16) ;;
+        z8k) AC_CONFIG_SUBDIRS(z8k) ;;
+  esac;
+fi
+	  

+ Makefile.am is standard and will not need to be + changed. Having changed the configuration template, the + configuration file, configure, will need to be + regenerated. This only requires running autoconf +

+autoconf
+	  

+ Since Makefile.am has not been changed there is + no need to run automake +

4.1.2.  + Implementing the setjmp and + longjmp functions. +

+ setjmp and longjmp are a + pair of C function facilitating cross-procedure transfer of + control. Typically they are used to allow resumption of execution at + a known good point after an error. +

+ Both take as first argument a buffer, which is used to hold the + machine state at the jump destination. When + setjmp is called it populates that buffer with + the current location state (which includes stack and frame pointers + and the return address for the call to setjmp, + and returns zero. +

+ longjmp takes a buffer previously populated by + setjmp. It also takes a (non-zero) second + argument, which will ultimately be the result of the function + call. longjmp restores the machine state from + the buffer. It then jumps to the return address it has just + restored, passing its second argument as the result. That return + address is the return address from the original call to + setjmp, so the effect will be as if + setjmp has just returned with a non-zero + argument. +

+ setjmp and longjmp are + typically used in a top level function in the following way. +

+#include <setjmp.h>
+
+...
+
+  jmp_buf  buf;
+
+  if (0 == setjmp (buf))
+    {
+      normal processing passing in buf
+    }
+  else
+    {
+      error handling code
+    }
+
+...
+	  

+ During normal processing if an error is found, the state held in + buf can be used to return control back to the top + level using longjmp. +

+#include <setjmp.h>
+
+...
+
+  if (error detected)
+    {
+      longjmp (buf, 1);
+    }
+
+...
+	  

+ The program will behave as though the original call to + setjmp had just returned with result 1. +

+ It will be appreciated that this is behavior that cannot usually be + written in C. The OpenRISC 1000  implementation is given as an example. This + processor has 32 registers, r0 through + r31, each of 32-bits. r0 is + always tied to zero, so need not be saved. r11 is + the function result register, which is always set by + setjmp and longjmp, so + also need not be saved. In addition we should save and restore the + machine's 32-bit supervision register, which holds the branch flag. +

+ Thus we need the buffer to be 31 32-bit words long. This is defined + in the setjmp header (see Section 4.2.2). +

+ In the Application Binary Interface (ABI) + for the OpenRISC 1000 , function arguments are passed in registers + r3 through r8 and the function + return address is in r9. +

+ When defining these two functions, in assembler, be aware of any + prefix conventions used by the C compiler. It is common for symbols + defined in C to have an underscore prepended (this is the case for + the OpenRISC 1000 ). Thus in this case the assembler should define + _setjmp and _longjmp. +

+ This is the implementation of setjmp. +

+        .global _setjmp
+_setjmp:
+        l.sw    4(r3),r1                /* Slot 0 saved for flag in future */
+        l.sw    8(r3),r2
+        l.sw    12(r3),r3
+        l.sw    16(r3),r4
+        l.sw    20(r3),r5
+        l.sw    24(r3),r6
+        l.sw    28(r3),r7
+        l.sw    32(r3),r8
+        l.sw    36(r3),r9
+        l.sw    40(r3),r10              /* Skip r11 */
+        l.sw    44(r3),r12
+        l.sw    48(r3),r13
+        l.sw    52(r3),r14
+        l.sw    56(r3),r15
+        l.sw    60(r3),r16
+        l.sw    64(r3),r17
+        l.sw    68(r3),r18
+        l.sw    72(r3),r19
+        l.sw    76(r3),r20
+        l.sw    80(r3),r21
+        l.sw    84(r3),r22
+        l.sw    88(r3),r23
+        l.sw    92(r3),r24
+        l.sw    96(r3),r25
+        l.sw    100(r3),r26
+        l.sw    104(r3),r27
+        l.sw    108(r3),r28
+        l.sw    112(r3),r29
+        l.sw    116(r3),r30
+        l.sw    120(r3),r31
+
+        l.jr    r9
+        l.addi  r11,r0,0                /* Zero result */
+	  

+ In this simplified implementation, the status flags are not + saved—that is a potential future enhancement. All the general + registers, with the exception of r0 (always zero) + and r11 (result register) are saved in the + buffer, which, being the first argument, is pointed to by + r3. +

+ Finally the result register, r11 is set to zero + and the function returns using r9 (the OpenRISC 1000  has + delayed branches, so the setting of r11 is placed + after the branch to return.). +

+ The implementation of longjmp is slightly more + complex, since the second argument will be returned as the effective + result from setjmp, unless + the second argument is zero in which case 1 is used. +

+ The result must be dealt with first and placed in the result + register, r11, because the second argument, in + r4 will be subsequently overwritten when the + machine state is restored. Similarly we must ensure that + r3, which holds the first argument pointing to + the restore buffer must itself be the last register restored. +

+        .global _longjmp
+_longjmp:
+        /* Sort out the return value */
+        l.sfne  r4,r0
+        l.bf    1f
+        l.nop
+
+        l.j     2f
+        l.addi  r11,r0,1                /* 1 as result */
+
+1:      l.addi  r11,r4,0                /* val as result */
+
+        /* Restore all the other registers, leaving r3 to last. */
+2:      l.lwz   r31,120(r3)
+        l.lwz   r30,116(r3)
+        l.lwz   r29,112(r3)
+        l.lwz   r28,108(r3)
+        l.lwz   r27,104(r3)
+        l.lwz   r26,100(r3)
+        l.lwz   r25,96(r3)
+        l.lwz   r24,92(r3)
+        l.lwz   r23,88(r3)
+        l.lwz   r22,84(r3)
+        l.lwz   r21,80(r3)
+        l.lwz   r20,76(r3)
+        l.lwz   r19,72(r3)
+        l.lwz   r18,68(r3)
+        l.lwz   r17,64(r3)
+        l.lwz   r16,60(r3)
+        l.lwz   r15,56(r3)
+        l.lwz   r14,52(r3)
+        l.lwz   r13,48(r3)
+        l.lwz   r12,44(r3)
+        l.lwz   r10,40(r3)              /* Omit r11 */
+        l.lwz   r9,36(r3)
+        l.lwz   r8,32(r3)
+        l.lwz   r7,28(r3)
+        l.lwz   r6,24(r3)
+        l.lwz   r5,20(r3)
+        l.lwz   r4,16(r3)
+        l.lwz   r2,8(r3)                /* Skip r3 */
+        l.lwz   r1,4(r3)                /* Slot 0 saved for flag in future */
+        l.lwz   r3,12(r3)               /* Now safe */
+        
+        /* Result is already in r11. Having restored r9, it will appear as
+           though we have returned from the earlier call to _setjmp. The
+           non-zero result gives it away though. */
+        l.jr    r9
+        l.nop
+	  

+ The return address, stack pointer and frame pointer having been + restored, the return from the function, will place the execution + point immediately after the original call to + setjmp. +

+ The following is a simple test program, which can be used to verify + that setjmp and longjmp + are working correctly. +

+#include <setjmp.h>
+#include <stdio.h>
+
+
+void
+testit (jmp_buf  env,
+        int      prev_res)
+{
+  int  res = (0 == prev_res) ? prev_res : prev_res + 1;
+
+  printf ("Long jumping with result %d\n", res);
+  longjmp (env, res);
+
+}       /* testit () */
+
+
+int
+main (int   argc,
+      char *argv[])
+{
+  jmp_buf  env;
+
+  int  res = setjmp (env);
+
+  printf ("res = 0x%08x\n", res);
+
+  if (res > 1)
+    {
+      return  0;
+    }
+
+  testit (env, res);
+
+  return  256;                  /* We should never actually get here */
+
+}       /* main () */
+	  

4.1.3.  + Updating the Target Specific Machine Directory Configuration files +

+ configure.in and + Makefile.am files also be needed for the target + specific directory (i.e. + libc/machine/target + within the newlib directory). These are + generally quite standard, and the easiest approach is to copy the + versions used for the fr30 architecture. Modern practice is to use + the file name configure.ac rather than + configure.in, but either will be accepted by + autoconf. +

+ Makefile.am should be modified if necessary to + specify the source files (for example setjmp.S + and longjmp.S). More complex implementations + may require modifications to configure.in as + well. +

+ For example the OpenRISC 1000  machine directory + (libc/machine/or32 within the + newlib directory) contains the following. +

+AUTOMAKE_OPTIONS = cygnus
+
+INCLUDES = $(NEWLIB_CFLAGS) $(CROSS_CFLAGS) $(TARGET_CFLAGS)
+
+AM_CCASFLAGS = $(INCLUDES)
+
+noinst_LIBRARIES = lib.a
+
+lib_a_SOURCES = longjmp.S setjmp.S
+lib_a_CCASFLAGS=$(AM_CCASFLAGS)
+lib_a_CFLAGS=$(AM_CFLAGS)
+
+ACLOCAL_AMFLAGS = -I ../../.. -I ../../../..
+CONFIG_STATUS_DEPENDENCIES = $(newlib_basedir)/configure.host
+	  

+ After any changes it will be necessary to run autoconf and/or + automake + to generate new versions of configure and + Makefile.in. autoconf requires a number of + newlib specific macros. These can be generated from the main + newlib include file (acinclude.m4) by running + aclocal. The full set of commands would be. +

+aclocal -I ../../..
+autoconf
+automake --cygnus Makefile
+	  

+ aclocal only need to be run the first time the directory is + created, or when moving the directory to a new release of + newlib. autoconf need only be run each time + configure.in (or + configure.ac) is changed. automake need only + be run each time Makefile.am is changed. +

4.2.  + Changing Headers +

+ There are two places, where header definitions must be modified for a + new target architecture: the specification of the IEEE floating + point format used, and the specification of the + setjmp buffer size. +

4.2.1.  + IEEE Floating Point +

+ The floating point format is specified within the + newlib directory in + libc/include/machine/ieeefp.h. Details of how + the IEEE 754 format is implemented, and variations from the + standard, are specified by defining a number of C macros. +

  • + __IEEE_BIG_ENDIAN +

    + Define this macro if the floating point format is + big endian. +

    [Caution]Caution

    + One, and only one of __IEEE_BIG_ENDIAN + and __IEEE_LITTLE_ENDIAN must be defined. +

  • + __IEEE_LITTLE_ENDIAN +

    + Define this macro if the floating point format is + little endian. +

    [Caution]Caution

    + One, and only one of __IEEE_LITTLE_ENDIAN + and __IEEE_BIG_ENDIAN must be defined. +

  • + __IEEE_BYTES_LITTLE_ENDIAN +

    + Define this macro in addition to + __IEEE_BIG_ENDIAN, where the words of a + multi-word IEEE floating point number are in big endian + order, but the bytes within each word are in little endian + order. +

  • + _DOUBLE_IS_32BITS +

    + Define this if double precision floating point is represented + using the 32-bit IEEE representation. +

  • + _FLOAT_ARG +

    + Floating point arguments are usually promoted to double when + passed as arguments. If this is not the case, then this macro + should be defined to the type actually used to pass floating + point arguments. +

  • + _FLT_LARGEST_EXPONENT_IS_NORMAL +

    + Define this if the floating point format uses the largest + exponent for finite numbers rather than NaN and + infinities. Such a format cannot represent NaNs or infinities, + but it's FLT_MAX is twice the standard IEEE + value. +

  • + _FLT_NO_DENORMALS +

    + Define this if the floating point format does not support IEEE + denormalized numbers. In this case, every floating point number + with a zero exponent is treated as a zero representation. +

[Caution]Caution

+ Two of these macros + (_FLT_LARGEST_EXPONENT_IS_NORMAL and + _FLT_NO_DENORMALS) specify deviations from + IEEE 754. These macros only work with single-precision floating + point and may not work correctly if hardware floating point + support is used (enabled by configuring with + --enable-newlib-hw-fp). +

+ For most targets it is sufficient to define just one of + __IEEE_BIG_ENDIAN or + __IEEE_LITTLE_ENDIAN. The definitions should + always be surrounded by a conditional, so they are only used when + the target architecture is selected. For example the OpenRISC 1000  is + big-endian, so we add the following to the header file. +

+#if defined(__or32__)
+#define __IEEE_BIG_ENDIAN
+#endif
+	  

4.2.2.  + setjmp Buffer Size +

+ The implementation of setjmp and + longjmp made use of a buffer to hold the + machine state. The size of that buffer is architecture dependent and + specified within the newlib directory in + libc/include/machine/setjmp.h. +

+ The header specifies the number of entries in the buffer and the + size of each entry (as a C type). So for the OpenRISC 1000  we use the + following. +

+#if defined(__or32__)
+/* Enough space for all regs except r0 and r11 and the status register */
+#define _JBLEN 31
+#define _JBTYPE unsigned long
+#endif
+	  

+ As before, the definition is within a conditional, so it is only + used when the target is the OpenRISC 1000  32-bit architecture. +

+ The type jmp_buf used with + setjmp and longjmp is then + defined as: +

+typedef	_JBTYPE jmp_buf[_JBLEN];
+	  

4.2.3.  + Miscellaneous System Definitions +

+ Various system wide constants are specified within the + newlib directory in + libc/include/sys/config.h. +

+ Very often the system default values are quite sufficient (this is + the case for the OpenRISC 1000 ). However target specific overrides of these + values can be provided at the end of this file. This file is + included in all other source files, so can be used to redefine any + of the constants used in the system. The existing file gives + numerous examples from different machines. +

[Caution]Caution

+ A number of the constants defined here mirror those in GCC's + limits.h file. They should be kept + consistent. +

4.2.4.  + Overriding Other Header Files +

+ If other headers must be overridden (not usually necessary with a + simple port), then the new versions can be placed in + libc/machine/arch/machine + within the newlib directory. These header files + will be used in preference to those in the standard distribution's + machine header directory. +

Chapter 5.  + Modifying libgloss +

+ Any target architecture may need multiple implementations, suited to + different platforms on which the code may run. The connection between + the library and a specific platform is known as a Board + Support Package (BSP). In recent versions of newlib, + BSPs are separated out into their own library, libgloss, the source + for which is in the top level libgloss directory. +

+ For newlib the BSP within libgloss comprises an implementation of + the C runtime initialization, crt0.o, a definition + of one global data structure, and implementation of eighteen system + calls for each platform. +

[Note]Note

+ libgloss is a relatively new addition to newlib. Some older ports + still have the BSP code within the newlib + directory. +

5.1.  + The Platform Directory +

+ A directory is created in the libgloss directory + corresponding to the machine directory created in the + newlib/libc/machine directory (see Chapter 4). +

+ This directory will hold the source code for the C runtime + initialization (crt0.o) and for the system calls + for each BSP +

5.1.1.  + Ensuring the Platform Directory is Configured +

+ configure.in within the + libgloss directory includes a + case statement configuring the target for each + target platform. This should be extended to add the new platform + directory. The OpenRISC 1000  32-bit target requires the following change. +

+case "${target}" in
+  i[[3456]]86-*-elf* | i[[3456]]86-*-coff*)
+        AC_CONFIG_SUBDIRS([i386])
+        ;;
+  m32r-*-*)
+        AC_CONFIG_SUBDIRS([m32r])
+        ;;
+
+  <Other targets not shown>
+
+  spu-*-elf)
+        AC_CONFIG_SUBDIRS([spu])
+        config_testsuite=false
+        config_libnosys=false
+        ;;
+  or32-*-*)
+        AC_CONFIG_SUBDIRS(or32)
+        ;;
+  iq2000-*-*)
+        AC_CONFIG_SUBDIRS([iq2000])
+        ;;
+esac
+	  

+ After making this change the configure file + should be regenerated by running autoconf. +

5.2.  + The C Runtime Initialization, crt0.o +

+ The C Runtime system must carry out the following tasks. +

  • + Set up the target platform in a consistent state. For example + setting up appropriate exception vectors. +

  • + Initialize the stack and frame pointers +

  • + Invoke the C constructor initialization and ensure destructors + are called on exit. +

  • + Carry out any further platform specific initialization. +

  • + Call the C main function. +

  • + Exit with the return code supplied if the C + main function ever terminates. +

+ The code is invariably assembler, although it may call out to C + functions, and is best illustrated by example from the OpenRISC 1000 . This + is a BSP designed for use with a fast architectural simulator. It + comes in two variants, one providing just standard output to the + console, the other implementing a simulated UART with both + standard input and standard output. The crt0.0 + is common to both BSPs and found in crt0.S. +

5.2.1.  + Exception vector setup +

+ The first requirement is to populate the exception vectors. The + OpenRISC 1000  uses memory from 0x0 to + 0x1fff for exception vectors, with vectors + placed 0x100 bytes apart. Thus a reset + exception will jump to 0x100, a bus error + exception to 0x200 and so on. +

+ In this simple BSP, the vast majority of exceptions are not + supported. If they are received, they print out (using + printf) identification of the exception and + the address which caused it to the simulator console, and then + exit. We provide a macro for that assembly code, since it will be + reused many times. +

+#define UNHANDLED_EXCEPTION(str)                                         \
+        l.addi  r1,r1,-20               /* Standard prologue */         ;\
+        l.sw    16(r1),r2                                               ;\
+        l.addi  r2,r1,20                                                ;\
+        l.sw    12(r1),r9                                               ;\
+                                                                        ;\
+        l.movhi r3,hi(.Lfmt)            /* printf format string */      ;\
+        l.ori   r3,r3,lo(.Lfmt)                                         ;\
+        l.sw    0(r1),r3                                                ;\
+        l.movhi r4,hi(str)              /* Name of exception */         ;\
+        l.ori   r4,r4,lo(str)                                           ;\
+        l.sw    4(r1),r4                                                ;\
+        l.mfspr r5,r0,SPR_EPCR_BASE     /* Source of the interrupt */   ;\
+        l.jal   _printf                                                 ;\
+        l.sw    8(r1),r5                                                ;\
+                                                                        ;\
+        l.ori   r3,r0,0xffff            /* Failure RC */                ;\
+        l.jal   _exit                                                   ;\
+        l.nop                                                           ;\
+                                                                        ;\
+        l.rfe                           /* Never executed we hope */
+	  

+ The call to printf is expected to use a + standard format string (at the label .Lfmt) + which requires two other arguments, an identification string + (labeled by the parameter st to the macro) and + the program counter where the exception occurred (loaded from + Special Purpose Register SPR_EPCR_BASE). Return + from exception is provided as a formality, although the call to + exit means that we should never execute it. +

+ Note that compiled C functions have their names prepended by + underscore on the OpenRISC 1000 . It is these names that must be used from + the assembler code. +

+ The format and identification strings are read only data. +

+        .section .rodata
+.Lfmt:  .string "Unhandled %s exception at address %08p\n"
+.L200:  .string "bus error"
+.L300:  .string "data page fault"
+.L400:  .string "instruction page fault"
+.L500:  .string "timer"
+.L600:  .string "alignment"
+.L700:  .string "illegal instruction"
+.L800:  .string "external interrupt"
+.L900:  .string "data TLB"
+.La00:  .string "instruction TLB"
+.Lb00:  .string "range"
+.Lc00:  .string "syscall"
+.Ld00:  .string "floating point"
+.Le00:  .string "trap"
+.Lf00:  .string "undefined 0xf00"
+.L1000: .string "undefined 0x1000"
+.L1100: .string "undefined 0x1100"
+.L1200: .string "undefined 0x1200"
+.L1300: .string "undefined 0x1300"
+.L1400: .string "undefined 0x1400"
+.L1500: .string "undefined 0x1500"
+.L1600: .string "undefined 0x1600"
+.L1700: .string "undefined 0x1700"
+.L1800: .string "undefined 0x1800"
+.L1900: .string "undefined 0x1900"
+.L1a00: .string "undefined 0x1a00"
+.L1b00: .string "undefined 0x1b00"
+.L1c00: .string "undefined 0x1c00"
+.L1d00: .string "undefined 0x1d00"
+.L1e00: .string "undefined 0x1e00"
+.L1f00: .string "undefined 0x1f00"
+	  

+ The first executable code is for the exception vectors. These must + go first in memory, so are placed in their own section, + .vectors. The linker/loader will ensure this + this code is placed first in memory (see Section 7.3). +

+ The reset vector just jumps to the start code. The code is too + large to sit within the 0x100 bytes of an + exception vector entry, and is placed in the main text space, in + function _start. +

+        .section .vectors,"ax"
+
+        /* 0x100: RESET exception */
+        .org    0x100   
+_reset:
+        /* Jump to program initialisation code */
+        l.movhi r2,hi(_start)
+        l.ori   r2,r2,lo(_start)
+        l.jr    r2
+        l.nop
+	  

+ The second vector, at address 0x200 is the bus + error exception vector. In normal use, like all other exceptions + it it causes exit and uses the + UNHANDLED_EXCEPTION macro. +

+ However during start up, the code tries deliberately to write out + of memory, to determine the end of memory, which will trigger this + bus exception. For this a simple exception handler, which just + skips the offending instruction is required. +

+ The solution is to place this code first, followed by the + unhandled exception code. Once the end of memory has been located, + the initial code can be overwritten by l.nop + opcodes, so the exception will drop through to the + UNHANDLED_EXCEPTOON code. +

+        .org    0x200
+_buserr:
+        l.mfspr r24,r0,SPR_EPCR_BASE
+        l.addi  r24,r24,4               /* Return one instruction on */
+        l.mtspr r0,r24,SPR_EPCR_BASE
+        l.rfe
+
+_buserr_std:
+        UNHANDLED_EXCEPTION (.L200)
+	  

+ No effort is made to save the register (r24) that + is used in the handler. The start up code testing for end of memory + must not use this register. +

+ The next exception, data page fault, at location 0x300, like all + other exceptions is unhandled. +

+        .org    0x300
+        UNHANDLED_EXCEPTION (.L300)
+	  

5.2.2.  + The _start Function and Stack Initialization +

+ The OpenRISC 1000  ABI uses a falling stack. The linker will place code + and static data at the bottom of memory (starting with the + exception vectors). The heap then starts immediately after this, + while the stack grows down from the end of memory. +

+ The linker will supply the address for the start of heap (it is in + the global variable end). However we must find + the stack location by trying to write to memory above the heap to + determine the end of memory. Rather than write to every location, + the code assumes memory is a multiple of 64KB, and tries writing + to the last word of each 64KB block above end + until the value read back fails. +

+ This failure will trigger a bus error exception, which must be + handled (see Section 5.2.1). The address used for + the start of the stack (which is also the last word of memory) is + stored in a global location, _stack (which C + will recognize as stack). +

+        .section .data
+        .global _stack
+_stack: .space  4,0
+	  

+ _start is declared so it looks like a C + function. GDB knows that _start is special, + and this will ensure that backtraces do not wind back further than + main. It is located in ordinary text space, + so will be placed with other code by the linker/loader. +

+        .section .text
+        .global _start
+        .type   _start,@function
+_start: 
+	  

+ The first memory location to test is found by rounding the + end location down to a multiple of 64KB, then + taking the last word of the 64KB above + that. 0xaaaaaaaa is used as the test word to + write to memory and read back. +

+        l.movhi r30,hi(end)
+        l.ori   r30,r30,lo(end)
+        l.srli  r30,r30,16              /* Round down to 64KB boundary */
+        l.slli  r30,r30,16
+
+        l.addi  r28,r0,1                /* Constant 64KB in register */
+        l.slli  r28,r28,16
+
+        l.add   r30,r30,r28
+        l.addi  r30,r30,-4              /* SP one word inside next 64KB? */
+
+        l.movhi r26,0xaaaa              /* Test pattern to store in memory */
+        l.ori   r26,r26,0xaaaa
+	  

+ Each 64KB block is tested by writing the test value and reading + back to see if it matches. +

+.L3:
+        l.sw    0(r30),r26
+        l.lwz   r24,0(r30)
+        l.sfeq  r24,r26
+        l.bnf   .L4
+        l.nop
+        
+        l.j     .L3
+        l.add   r30,r30,r28             /* Try 64KB higher */
+
+.L4:
+	  

+ The previous value is then the location to use for end of stack, + and should be stored in the _stack location. +

+        l.sub   r30,r30,r28             /* Previous value was wanted */
+        l.movhi r26,hi(_stack)
+        l.ori   r26,r26,lo(_stack)
+        l.sw    0(r26),r30
+	  

+ The stack pointer (r1) and frame pointer + (r2) can be initialized with this value. +

+        l.add   r1,r30,r0
+        l.add   r2,r30,r0
+	  

+ Having determined the end of memory, there is no need to handle + bus errors silently. The words of code between + _buserr and _buserr_std can + be replaced by l.nop. +

+        l.movhi r30,hi(_buserr)
+        l.ori   r30,r30,lo(_buserr)
+        l.movhi r28,hi(_buserr_std)
+        l.ori   r28,r28,lo(_buserr_std)
+        l.movhi r26,0x1500              /* l.nop 0 */
+        l.ori   r26,r26,0x0000
+
+.L5:
+        l.sfeq  r28,r30
+        l.bf    .L6
+        l.nop
+
+        l.sw    0(r30),r26              /* Patch the instruction */
+        l.j     .L5
+        l.addi  r30,r30,4               /* Next instruction */
+
+.L6:
+	  
[Note]Note

+ It is essential that this code is before any data or instruction + cache is initialized. Otherwise more complex steps would be + required to enforce data write back and invalidate any + instruction cache entry. +

5.2.3.  + Cache Initialization +

+ The OpenRISC 1000 has optional instruction and data caches. If + these are declared (in the or1ksim-board.h + header), then they must be enabled by setting the appropriate bit + in the supervision register. +

+ This is an example of machine specific initialization. +

+        /* Cache initialisation. Enable IC and/or DC */
+.if IC_ENABLE || DC_ENABLE
+        l.mfspr r10,r0,SPR_SR
+.if IC_ENABLE
+        l.ori   r10,r10,SPR_SR_ICE
+.endif
+.if DC_ENABLE
+        l.ori   r10,r10,SPR_SR_DCE
+.endif
+        l.mtspr r0,r10,SPR_SR
+        l.nop                           /* Flush the pipeline. */
+        l.nop
+        l.nop
+        l.nop
+        l.nop
+.endif
+	  

5.2.4.  + Clearing BSS +

+ BSS is the area of + memory used to hold static variables which must be initialized to + zero. Its start and end are defined by two variables from the + linker/loader, __bss_start and + end respectively. +

+        l.movhi r28,hi(__bss_start)
+        l.ori   r28,r28,lo(__bss_start)
+        l.movhi r30,hi(end)
+        l.ori   r30,r30,lo(end)
+
+.L1:
+        l.sw    (0)(r28),r0
+        l.sfltu r28,r30
+        l.bf    .L1
+        l.addi  r28,r28,4
+	  

5.2.5.  + Constructor and Destructor Handling +

+ GCC may require constructors to be initialized at start up and + destructors to be called on exit. This behavior is captured in the + GCC functions __do_global_ctors and + __do_global_dtors. There is some complexity + associated with this functionality, since there may be separate + lists for the main code and shared libraries that are dynamically + loaded. +

+ It is usual to wrap this functionality in two functions, + init and fini, which are + placed in their own sections, .init and + .fini. The .init section is + loaded before all other text sections and the + .fini section after all other text sections. +

+ The start up code should call init to handle + any constructors. +

+        l.jal   init
+        l.nop
+	  

+ The fini function is passed to the library + function _atexit to ensure it is called on a + normal exit. +

+        l.movhi r3,hi(fini)
+        l.jal   _atexit
+        l.ori   r3,r3,lo(fini)          /* Delay slot */
+	  

5.2.6.  + C Initialization Functions +

+ Now that the C infrastructure is set up, it is appropriate to call + any C functions that are used during initialization. In the OpenRISC 1000  + case this is a function to initialize a UART. Only one version + of the library actually has a UART. However it is easiest to + substitute a dummy version of the initialization function in the + version of the library without a UART, rather than making this + function conditional. +

+        l.jal    __uart_init
+        l.nop
+	  

5.2.7.  + Invoking the main program +

+ The final stage is to call the main program. In this simple + implementation there is no mechanism to pass arguments or + environments to main, so the arguments + argc, argv and + env (in r3, + r4 and r5) are set to + 0, NULL and + NULL respectively. +

+        l.or    r3,r0,r0
+        l.or    r4,r0,r0
+        l.jal   _main
+        l.or    r5,r0,r0                /* Delay slot */
+	  

+ If the main program returns, its result (held in + r11 on the OpenRISC 1000 ) will be a return code from + the program, which we pass to the exit. +

+        l.jal   _exit
+        l.addi  r3,r11,0                /* Delay slot */
+	  

+ exit should not return, but just in case, we + can put the processor in a tight loop at this stage, in order to + ensure consistent behavior. +

+.L2:
+        l.j     .L2
+        l.nop
+	  

5.3.  + Standard System Call Implementations +

+ The simplest way to provide a board support package is to implement + the 18 system calls in non-reentrant fashion. For many bare metal + implementations this is sufficient. +

+ The simplest possible BSP supports just output to standard output + and non input. We give the minimal implementation for such a system. +

+ Where appropriate, we also show the OpenRISC 1000  implementation as a + practical example. +

+ This section duplicates much of the information found in the + newlib libc documentation [1]. It is + included here for completeness. +

5.3.1.  + Error Handling +

+ Many functions set an error code on failure in the global + variable, errno. +

+ There is a slight complication with newlib, because + errno is not implemented as a variable, but a + macro (this make life easier for reentrant functions). +

+ The solution for standard system call implementations, which must + return an error code is to undefine the macro and use the external + variable instead. At the head of such functions use the following. +

+#include <errno.h>
+#undef errno
+extern int errno;
+	  
[Note]Note

+ errno is a global variable, so changing it + will immediately make a function non-reentrant. +

5.3.2.  + The Global Environment, environ +

+ The global variable, environ must point to a + null terminated list of environment variable name-value pairs. +

+ For a minimal implementation it is sufficient to use an empty list + as follows. +

+char *__env[1] = { 0 };
+char **environ = __env;
+	  

5.3.3.  + Exit a program, _exit +

+ Exit a program without any cleanup. +

+ The OpenRISC 1000 s implementation makes use of the + l.nop opcode. This opcode takes a 16-bit + immediate operand. Functionally the operand has no effect on the + processor itself. However a simulator can inspect the operand to + provide additional behavior external to the machine. +

+ When executing on Or1ksim, l.nop 1 causes a + tidy exit of the simulator, using the value in + r3 as the return code. +

+void 
+_exit (int  rc)
+{
+  register int  t1 asm ("r3") = rc;
+
+  asm volatile ("\tl.nop\t%0" : : "K" (NOP_EXIT), "r" (t1));
+
+  while (1)
+    {
+    }
+}       /* _exit () */
+	  

+ Note the use of volatile. Otherwise there is a + strong possibility of an optimizing compiler recognizing that this + opcode does nothing (we are relying on a simulation side-effect) + and removing it. +

[Caution]Caution

+ The name of this function is already namespace clean. If a + namespace clean implementation of the system calls has been + specified in configure.host (see Section 3.3.1), then this function is still + named _exit, not + __exit. +

5.3.4.  + Closing a file, close +

+ For a namespace clean function, implement + _close, otherwise implement + close. The detailed implementation will + depend on the file handling functionality available. +

+ In the minimal implementation, this function always fails, since + there is only standard output, which is not a valid file to + close. This implementation is sufficient for the OpenRISC 1000 . +

+#include <errno.h>
+
+#undef errno
+extern int  errno;
+
+int
+_close (int   file)
+{
+  errno = EBADF;
+  
+  return -1;                    /* Always fails */
+
+}       /* _close () */
+	  

5.3.5.  + Transfer Control to a New Process, execve +

+ For a namespace clean function, implement + _execve, otherwise implement + execve. The implementation of this + functionality will be tightly bound to any operating + infrastructure for handling multiple processes. +

+ A minimal implementation, such as that for bare metal coding, only + offers a single user thread of control. It is thus impossible to + start a new process, so this function always fails. +

+#include <errno.h>
+
+#undef errno;
+extern int  errno;
+
+int
+_execve (char  *name,
+         char **argv,
+         char **env)
+{
+  errno = ENOMEM;
+  return -1;                    /* Always fails */
+
+}       /* _execve () */
+	  

+ The choice of errno is somewhat + arbitrary. However no value for "no processes available" is + provided, and ENOMEM is the closest in meaning + to this. +

5.3.6.  + Create a new process, fork +

+ For a namespace clean function, implement + _fork, otherwise implement + fork. The implementation of this + functionality will be tightly bound to any operating + infrastructure for handling multiple processes. +

+ A minimal implementation, such as that for bare metal coding, only + offers a single user thread of control. It is thus impossible to + start a new process, so this function always fails. +

+#include <errno.h>
+
+#undef errno
+extern int  errno;
+
+int
+_fork ()
+{
+  errno = EAGAIN;
+  return -1;                    /* Always fails */
+
+}       /* _fork () */
+	  

+ The choice of errno is again somewhat + arbitrary. However no value for "no processes available" is + provided, and EAGAIN is the closest in meaning + to this. +

5.3.7.  + Provide the Status of an Open File, fstat +

+ For a namespace clean function, implement + _fstat, otherwise implement + fstat. The detailed implementation will + depend on the file handling functionality available. +

+ A minimal implementation should assume that all files are + character special devices and populate the status data structure + accordingly. +

+#include <sys/stat.h>
+
+int
+_fstat (int          file,
+        struct stat *st)
+{
+  st->st_mode = S_IFCHR;
+  return  0;
+
+}       /* _fstat () */
+	  

+ The OpenRISC 1000  implementation requires two versions of this, one for + the BSP using the console for output and one for the BSP using + a UART and supporting both standard input and standard output. +

+ Without a UART, the implementation still checks that the file + descriptor is one of the two that are supported, and otherwise + returns an error. +

+#include <errno.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#undef errno
+extern int  errno;
+
+int
+_fstat (int          file,
+        struct stat *st)
+{
+  if ((STDOUT_FILENO == file) || (STDERR_FILENO == file))
+    {
+      st->st_mode = S_IFCHR;
+      return  0;
+    }
+  else
+    {
+      errno = EBADF;
+      return  -1;
+    }
+}       /* _fstat () */
+	  

+ The implementation when a UART is available is almost identical, + except that STDIN_FILENO is also an acceptable + file for which status can be provided. +

5.3.8.  + Get the Current Process ID, getpid +

+ For a namespace clean function, implement + _getpid, otherwise implement + getpid. The implementation of this + functionality will be tightly bound to any operating + infrastructure for handling multiple processes. +

+ For a minimal implementation, with no processes, this can just + return a constant. It is perhaps safer to return one rather than + zero, to avoid issue with software that believes process zero is + something special. +

+int
+_getpid ()
+{
+  return  1;                            /* Success */
+
+}       /* _getpid () */
+	  

5.3.9.  + Determine the Nature of a Stream, isatty +

+ For a namespace clean function, implement + _isatty, otherwise implement + isatty. The detailed implementation will + depend on the file handling functionality available. +

+ This specifically checks whether a stream is a terminal. The + minimal implementation only has the single output stream, which is + to the console, so always returns 1. +

+int
+_isatty (int   file)
+{
+  return  1;
+
+}       /* _isatty () */
+	  
[Caution]Caution

+ Contrary to the standard libc documentation, this applies to + any stream, not just output streams. +

+ The OpenRISC 1000  version gives a little more detail, setting + errno if the stream is not standard output, + standard error or (for the UART version of the BSP) standard + input. +

+#include <errno.h>
+#include <unistd.h>
+
+#undef ERRNO
+extern int  errno;
+
+int
+_isatty (int   file)
+{
+  if ((file == STDOUT_FILENO) || (file == STDERR_FILENO))
+    {
+      return  1;
+    }
+  else
+    {
+      errno = EBADF;
+      return  -1;
+    }
+}       /* _isatty () */
+	  

+ The UART version is almost identical, but also succeeds for + standard input. +

5.3.10.  + Send a Signal, kill +

+ For a namespace clean function, implement + _kill, otherwise implement + kill. The implementation of this + functionality will be tightly bound to any operating + infrastructure for handling multiple processes. +

+ A minimal implementation has no concept of either signals, nor of + processes to receive those signals. So this function should always + fail with an appropriate value in errno. +

+#include <errno.h>
+
+#undef errno
+extern int  errno;
+
+int
+_kill (int  pid,
+       int  sig)
+{
+  errno = EINVAL;
+  return -1;                    /* Always fails */
+
+}       /* _kill () */
+	  

5.3.11.  + Rename an existing file, link +

+ For a namespace clean function, implement + _link, otherwise implement + link. The detailed implementation will + depend on the file handling functionality available. +

+ A minimal implementation has no file system, so this function must + always fail, with an appropriate value set in + errno. +

+#include <errno.h>
+
+#undef errno
+extern int  errno;
+
+int
+_link (char *old,
+       char *new)
+{
+  errno = EMLINK;
+  return -1;                    /* Always fails */
+
+}       /* _link () */
+	  

5.3.12.  + Set Position in a File, lseek +

+ For a namespace clean function, implement + _lseek, otherwise implement + lseek. The detailed implementation will + depend on the file handling functionality available. +

+ A minimal implementation has no file system, so this function can + return 0, indicating that the only stream (standard output) is + positioned at the start of file. +

+#include <errno.h>
+
+#undef errno
+extern int  errno;
+
+int
+_lseek (int   file,
+        int   offset,
+        int   whence)
+{
+  return  0;
+
+}       /* _lseek () */
+	  

+ The OpenRISC 1000  version is a little more detailed, returning zero only + if the stream is standard output, standard error or (for the + UART version of the BSP) standard input. Otherwise -1 is + returned and an appropriate error code set in + errno. +

+#include <errno.h>
+#include <unistd.h>
+
+#undef errno
+extern int  errno;
+
+int
+_lseek (int   file,
+        int   offset,
+        int   whence)
+{
+  if ((STDOUT_FILENO == file) || (STDERR_FILENO == file))
+    {
+      return  0;
+    }
+  else
+    {
+      errno = EBADF;
+      return  (long) -1;
+    }
+}       /* _lseek () */
+	  

+ The UART version is almost identical, but also succeeds for + standard input. +

5.3.13.  + Open a file, open +

+ For a namespace clean function, implement + _open, otherwise implement + open. The detailed implementation will + depend on the file handling functionality available. +

+ A minimal implementation has no file system, so this function must + always fail, with an appropriate error code set in + errno. +

+#include <errno.h>
+
+#undef errno
+extern int  errno;
+
+int
+_open (const char *name,
+       int         flags,
+       int         mode)
+{
+  errno = ENOSYS;
+  return -1;                    /* Always fails */
+
+}       /* _open () */
+	  

5.3.14.  + Read from a File, read +

+ For a namespace clean function, implement + _read, otherwise implement + read. The detailed implementation will depend + on the file handling functionality available. +

+ A minimal implementation has no file system. Rather than failing, + this function returns 0, indicating end-of-file. +

+#include <errno.h>
+
+#undef errno
+extern int  errno;
+
+int
+_read (int   file,
+       char *ptr,
+       int   len)
+{
+  return  0;                            /* EOF */
+
+}       /* _read () */
+	  

+ The OpenRISC 1000  BSP without a UART is very similar to the minimal + implementation, but checks that the stream is standard input + before returning 0. For all other streams it returns an error. +

+#include <errno.h>
+#include <unistd.h>
+
+#undef errno
+extern int  errno;
+
+int
+_read (int   file,
+       char *ptr,
+       int   len)
+{
+  if (STDIN_FILENO == file)
+    {
+      return  0;                        /* EOF */
+    }
+  else
+    {
+      errno = EBADF;
+      return  -1;
+    }
+}       /* _read () */
+	  

+ The OpenRISC 1000  BSP with a UART is more complex. In this case, if + the stream is standard input, a character is read (and optionally + echoed) from the UART. +

+#include <errno.h>
+#include <unistd.h>
+
+#undef errno
+extern int  errno;
+
+int
+_read (int   file,
+       char *buf,
+       int   len)
+{
+  if (STDIN_FILENO == file)
+    {
+      int  i;
+
+      for (i = 0; i < len; i++)
+	{
+	  buf[i] = _uart_getc ();
+#ifdef UART_AUTO_ECHO
+	  _uart_putc (buf[i]);
+#endif
+	  /* Return partial buffer if we get EOL */
+	  if ('\n' == buf[i])
+	    {
+	      return  i;
+	    }
+	}
+
+      return  i;			/* Filled the buffer */
+    }
+  else
+    {
+      errno = EBADF;
+      return  -1;
+    }
+}	/* _read () */
+	  
[Caution]Caution

+ The Or1ksim UART implementation only returns data when + carriage return is hit, rather than as each character becomes + available, which can lead to some unexpected behavior. +

5.3.15.  + Allocate more Heap, sbrk +

+ For a namespace clean function, implement + _sbrk, otherwise implement + sbrk. This is one function for which there is + no default minimal implementation. It is important that it is + implemented wherever possible, since malloc + depends on it, and in turn many other functions depend on + malloc. In this application note, the OpenRISC 1000  + implementation is used as an example. +

+ As noted earlier (Section 5.2.2), the heap on + the OpenRISC 1000  grows up from the end of loaded program space, and the + stack grows down from the top of memory. The linker defines the + symbol _end, which will be the start of the + heap, whilst the C runtime initialization places the address of + the last work in memory in the global variable + _stack. +

[Caution]Caution

+ _end is a symbol defined by the linker, not a + variable, so it is its address that must be + used, not its value. +

+ Within a C program these two variables are referred to without + their leading underscore—the C compiler prepends all + variable names with underscore. +

+#include <errno.h>
+
+#undef errno
+extern int  errno;
+
+#define STACK_BUFFER  65536     /* Reserved stack space in bytes. */
+
+void *
+_sbrk (int nbytes)
+{
+  /* Symbol defined by linker map */
+  extern int  end;              /* start of free memory (as symbol) */
+
+  /* Value set by crt0.S */
+  extern void *stack;           /* end of free memory */
+
+  /* The statically held previous end of the heap, with its initialization. */
+  static void *heap_ptr = (void *)&end;         /* Previous end */
+
+  if ((stack - (heap_ptr + nbytes)) > STACK_BUFFER )
+    {
+      void *base  = heap_ptr;
+      heap_ptr   += nbytes;
+                
+      return  base;
+    }
+  else
+    {
+      errno = ENOMEM;
+      return  (void *) -1;
+    }
+}       /* _sbrk () */
+	  

+ The program always tries to keep a minimum of 65,536 + (216) bytes spare for the stack. +

[Note]Note

+ This implementation defines _sbrk as + returning type void *. The standard newlib + documentation uses return type caddr_t, which is + defined in unistd.h. The author believes + that void * is now the recommended return type for + this function. +

[Important]Important

+ sbrk has to return the previous end of the + heap, whose value is held in the static variable, + heap_ptr. +

+ The problem is that this now makes the function + non-reentrant. If the function were interrupted after the + assignment to base, but before the following + assignment to heap_ptr, and the interrupt + routine itself also called sbrk, then the + heap would become corrupted. +

+ For simple systems, it would be sufficient to avoid using this + function in interrupt service routines. However the problem then + knowing which functions might call malloc + and hence sbrk, so effectively all library + functions must be avoided. +

+ The problem cannot even be completely avoided by using reentrant + functions (see Section 5.4), since + just providing a per thread data structure does not help. The + end of heap is a single global value. The only full solution is + to surround the update of the global variable by a semaphore, + and failing the allocation if the region is blocked (we cannot + wait, or deadlock would result). +

5.3.16.  + Status of a File (by Name), stat +

+ For a namespace clean function, implement + _stat, otherwise implement + stat. The detailed implementation will + depend on the file handling functionality available. +

+ A minimal implementation should assume that all files are + character special devices and populate the status data structure + accordingly. +

+#include <sys/stat.h>
+
+int
+_stat (char        *file,
+       struct stat *st)
+{
+  st->st_mode = S_IFCHR;
+  return 0;
+
+}       /* _stat () */
+	  

+ The OpenRISC 1000  implementation takes a stricter view of this. Since no + named files are supported, this function always fails. +

+#include <errno.h>
+#include <sys/stat.h>
+
+#undef errno
+extern int  errno;
+
+int
+_stat (char        *file,
+       struct stat *st)
+{
+  errno = EACCES;
+  return  -1;
+
+}       /* _stat () */
+	  

5.3.17.  + Provide Process Timing Information, times +

+ For a namespace clean function, implement + _times, otherwise implement + times. The implementation of this + functionality will be tightly bound to any operating + infrastructure for handling multiple processes. +

+ A minimal implementation need not offer any timing information, so + should always fail with an appropriate value in + errno. +

+#include <errno.h>
+#include <sys/times.h>
+
+#undef errno
+extern int  errno;
+
+int
+_times (struct tms *buf)
+{
+  errno = EACCES;
+  return  -1;
+
+}       /* _times () */
+	  

5.3.18.  + Remove a File's Directory Entry, unlink +

+ For a namespace clean function, implement + _unlink, otherwise implement + unlink. The detailed implementation will + depend on the file handling functionality available. +

+ A minimal implementation has no file system, so this function + should always fail, setting an appropriate value in + errno. +

+#include <errno.h>
+
+#undef errno
+extern int  errno;
+
+int
+_unlink (char *name)
+{
+  errno = ENOENT;
+  return -1;                    /* Always fails */
+
+}       /* _unlink () */
+	  

5.3.19.  + Wait for a Child Process, wait +

+ For a namespace clean function, implement + _wait, otherwise implement + wait. The implementation of this + functionality will be tightly bound to any operating + infrastructure for handling multiple processes. +

+ A minimal implementation has only one process, so can wait for no + other process and should always fail with an appropriate value in + errno. +

+#include <errno.h>
+
+#undef errno
+extern int  errno;
+
+int
+_wait (int *status)
+{
+  errno = ECHILD;
+  return -1;                    /* Always fails */
+
+}       /* _wait () */
+	  

5.3.20.  + Write to a File, write +

+ For a namespace clean function, implement + _write, otherwise implement + write. The detailed implementation will + depend on the file handling functionality available. +

+ A minimal implementation only supports writing to standard + output. The core of the implementation is: +

+int
+_write (int   file,
+        char *buf,
+        int   nbytes)
+{
+  int i;
+
+  /* Output character at at time */
+  for (i = 0; i < nbytes; i++)
+    {
+      outbyte (buf[i]);
+    }
+        
+  return nbytes;
+
+}       /* _write () */
+	  

+ The function outbyte must use the + functionality of the target platform to write a single character + to standard output. For example copying the character to a serial + line for display. There can be no standard implementation of this + function. +

+ For the OpenRISC 1000  two versions are needed one for the BSP without a + UART one for the BSP with a UART. +

+ Without a UART the implementation uses the + l.nop opcode with a parameter, as with the + implementation of _exit (Section 5.3.3). In this case the parameter 4 will cause the + simulator to print out the value in register r3 + as an ASCII character. +

+#include "or1ksim-board.h"
+
+static void
+outbyte (char  c)
+{
+  register char  t1 asm ("r3") = c;
+
+  asm volatile ("\tl.nop\t%0" : : "K" (NOP_PUTC), "r" (t1));
+
+}       /* outbyte () */
+	  

+ We also use a stricter implementation of the main + write function, only permitting a write if + the standard output or standard error stream is specified. +

+#include <errno.h>
+#include <unistd.h>
+
+#undef errno
+extern int  errno;
+
+int
+_write (int   file,
+        char *buf,
+        int   nbytes)
+{
+  int i;
+
+  /* We only handle stdout and stderr */
+  if ((file != STDOUT_FILENO) && (file != STDERR_FILENO))
+    {
+      errno = EBADF;
+      return -1;
+    }
+
+  /* Output character at at time */
+  for (i = 0; i < nbytes; i++)
+    {
+      outbyte (buf[i]);
+    }
+        
+  return nbytes;
+
+}       /* _write () */
+	  

+ For the BSP supporting a UART, all that is needed is to change + the outbyte function to use the routines to + drive the UART +

+static void
+outbyte (char  c)
+{
+  _uart_putc (c);
+
+}       /* outbyte () */
+	  

+ The UART support routines are provided separately, driving the + interface via its memory mapped registers. +

5.4.  + Reentrant System Call Implementations +

+ Reentrancy is achieved by providing a global reentrancy structure, + struct _reent for each thread of control, which + holds thread specific versions of global data structures, such as + errno. +

+ For a fully reentrant system, the BSP should implement the + reentrant versions of the system calls, having defined + syscall_dir=syscalls and added + -DREENTRANT_SYSCALLS_PROVIDED" to + newlib_cflags in + configure.host (see Section 3.3.1). +

+ 16 of the system calls have reentrant versions, which take the + suffix _r and are passed an additional first + argument, which is a pointer to the reentrancy structure, + struct reent for the thread of control. Thus + _close is replaced by + _close_r. The reentrant functions are + _close_r, _execve_r, + _fcntl_r, _fork_r, + _fstat_r, _getpid_r, + _link_r, _lseek_r, + _open_r, _read_r, + _sbrk_r, _stat_r, + _times_r, _unlink_r, + _wait_r and _write_r. +

+ Two system calls do not need reentrant versions, + _kill and _exit, which are + provided as with non-reentrant versions. +

+ For many of the reentrant functions, the behavior is almost + identical to that of the non-reentrant versions, beyond ensuring the + thread specific version of errno in the + reentrancy structure is used. Template versions can be found in the + libc/reent directory under the + newlib directory. +

+ There are two ways in which the end user can be supported with these + reentrancy functions. In the first it is up to the user to manage + per thread reentrancy data structures and to call the reentrant + functions explicitly. +

+ However the more powerful solution is for the system to manage the + reentrancy structure itself. The end user can call the standard + functions, and they will be mapped to reentrant calls, passing in a + reentrancy structure for the thread. +

+ For this approach to be used, -D__DYNAMIC_REENT__ + must be added to newlib_cflags and the BSP must + define the function __getreent, to return the + reentrancy structure for the current thread. +

5.5.  + BSP Configuration and Make file; +

+ There is little documentation for the configuration and make files + for the BSPs. The general guideline is to copy the baseline + versions of these files in the default platform library, + libnosys, which is based on the minimal + implementations described in Section 5.3. +

+ This application note uses the configuration and make files for + the OpenRISC 1000  to illustrate the key principles. +

+ Building the BSP only uses autoconf and autoheader, but not + automake. So there is a configure.in (or + configure.ac) and + Makefile.in, but no + Makefile.am. After making any changes it is + important to run autoconf and autoheader to regenerate the + configure script and header files. It will also + need a aclocal.m4 to give the local macro + definitions, which can be regenerated from the main libgloss + acinclude.m4 using aclocal. The command + needed are: +

+aclocal -I ..
+autoheader
+autoconf
+	

+ aclocal need only be run the first time the directory is + created. autoheader is only needed if the BSP needs configuration + parameters from the system in a local config.h + file. +

5.5.1.  + configure.in for the BSP +

+ The configure.in for the OpenRISC 1000  is closely + based on the version in libnosys. +

+ The initial declarations just need modifying to change the name of + the package. +

+AC_PREREQ(2.59)
+AC_INIT(libor32.a,0.2.0)
+AC_CONFIG_HEADER(config.h)
+	  

+ There is then code to print a warning if the user has asked for + shared library support (not available) and to locate the + auxiliary tools for autoconf. +

+ The script makes use of AC_CANONICAL_SYSTEM to + determine the system type and set appropriate variables. This is + now obsolete, and is replaced by + AC_CANONICAL_TARGET in the OpenRISC 1000  version. The + installed program names may be changed (for example by + --prefix), so we need + AC_ARG_PROGRAM and we locate the install + program. +

+AC_CANONICAL_TARGET
+
+AC_ARG_PROGRAM
+AC_PROG_INSTALL
+	  

+ The assumption is made that we are using GNU ld, so we define + HAVE_GNU_LD. The script in + libnosys does this in an obsolete way, which + is fixed in the OpenRISC 1000  script. +

+AC_DEFINE(HAVE_GNU_LD, 1, [Using GNU ld])
+	  

+ The standard script tests the canonical target name to determine + if this is an ELF target. For OpenRISC 1000  this is + always the case, so the test can be replaced by a simple + declaration. +

+AC_DEFINE(HAVE_ELF, 1, [Using ELF format])
+	  

+ The script in libnosys then tests for the + presence of various features. Most of those are not relevant to + OpenRISC 1000  so can be left out. However we do need to determine what + the symbol prefix is. We could just define this as being '_', but + instead we let the script work it out, using the standard script's + code. +

+AC_CACHE_CHECK([for symbol prefix], libc_symbol_prefix, [dnl
+cat > conftest.c <<\EOF
+foo () { }
+EOF
+
+libc_symbol_prefix=none
+if AC_TRY_COMMAND([${CC-cc} -S conftest.c -o - | fgrep "\$foo" > /dev/null]);
+then
+  libc_symbol_prefix='$'
+else
+  if AC_TRY_COMMAND([${CC-cc} -S conftest.c -o - | fgrep "_foo" > /dev/null]);
+  then
+    libc_symbol_prefix=_
+  fi
+fi
+rm -f conftest* ])
+if test $libc_symbol_prefix != none; then
+  AC_DEFINE_UNQUOTED(__SYMBOL_PREFIX, "$libc_symbol_prefix", [symbol prefix])
+else
+  AC_DEFINE(__SYMBOL_PREFIX, "", [symbol prefix])
+fi
+	  

+ The code to define the various host tools used is + standard. However it will expect to find an + aclocal.m4 file in the directory. This can be + regenerated, or simply copied from the + libnosys directory. The variable + host_makefile_frag refers to standard make + script defining how compilation is carried out for the various + source files. +

+ Finally the new Makefile can be generated in + a suitably initialized environment. +

+AC_CONFIG_FILES(Makefile,
+                ac_file=Makefile . ${libgloss_topdir}/config-ml.in,
+                srcdir=${srcdir}
+                target=${target}
+                with_multisubdir=${with_multisubdir}
+                ac_configure_args="${ac_configure_args} --enable-multilib"
+                CONFIG_SHELL=${CONFIG_SHELL-/bin/sh}
+                libgloss_topdir=${libgloss_topdir}
+)
+AC_OUTPUT
+	  

5.5.2.  + Makefile.in for the BSP +

+ The first part of Makefile.in is just + transferring values from configure and is + used unchanged. The first potential variation is in multilib + handling. If your GCC implements multilibs, then that may need + to be mirrored in the BSP implementation. If not, then there is + no need to set MULTIDO and + MULTICLEAN to true and these + lines can be removed. +

+ The Makefile.in in + libnosys includes an option to use + new versions of the loader and + assembler. However for most implementations, the plain tool is all + that is needed, so simple transfer of the configured values is + sufficient. +

+CC = @CC@
+AS = @AS@
+AR = @AR@
+LD = @LD@
+RANLIB = @RANLIB@
+	  

+ The main tools will already have been transformed to take account + of any prefix (for example using or32-elf-gcc + rather than gcc). However this has not been + done for objdump and + objcopy, so these are transformed here. +

+ This is the point at which we define the BSPs to be built. Any + custom flags for the compilation can be added to + CFLAGS here. +

+CFLAGS = -g
+	  

+ We specify the C start up file(s) and BSP(s) to be built. +

+CRT0     = crt0.o
+BSP      = libor32.a
+BSP_UART = libor32uart.a
+
+OUTPUTS  = $(CRT0) $(BSP) $(BSP_UART)
+	  
[Important]Important

+ It is important to define OUTPUTS. This is + the complete set of programs and libraries being built. It is + used in the clean and + install targets. +

+ For each BSP we specify the object files from which it is + built. For the plain OpenRISC 1000  BSP we have: +

+OBJS = _exit.o      \
+       close.o      \
+       environ.o    \
+       execve.o     \
+       fork.o       \
+       fstat.o      \
+       getpid.o     \
+       isatty.o     \
+       kill.o       \
+       link.o       \
+       lseek.o      \
+       open.o       \
+       read.o       \
+       sbrk.o       \
+       stat.o       \
+       times.o      \
+       uart-dummy.o \
+       unlink.o     \
+       wait.o       \
+       write.o
+	  

+ For the BSP with UART support we use many of the same files, + but also have some different files. +

+UART_OBJS = _exit.o       \
+            close.o       \
+            environ.o     \
+            execve.o      \
+            fork.o        \
+            fstat-uart.o  \
+            getpid.o      \
+            isatty-uart.o \
+            kill.o        \
+            link.o        \
+            lseek-uart.o  \
+            open.o        \
+            read-uart.o   \
+            sbrk.o        \
+            stat.o        \
+            times.o       \
+	    uart.o        \
+            unlink.o      \
+            wait.o        \
+            write-uart.o
+	  

+ At this point, the version of Makefile.in in + libnosys specifies explicitly the rules for + compiling object files from C and assembler source. However it is + better to incorporate a standard set of rules, using the + host_makefile_frag reference from the + configuration. +

+@host_makefile_frag@
+	  

+ This is the point at which to specify the first make rule to + create the C runtime start up files and BSPs. +

+all: ${CRT0} ${BSP} ${BSP_UART}
+	  

+ The object files (including crt0.o) will be + built automatically, but we need rules to build the libraries from + them. +

+$(BSP): $(OBJS)
+        ${AR} ${ARFLAGS} $@ $(OBJS)
+        ${RANLIB} $@
+
+$(BSP_UART): $(UART_OBJS)
+        ${AR} ${ARFLAGS} $@ $(UART_OBJS)
+        ${RANLIB} $@
+	  

+ The remainder of Makefile.in is standard. It + provides rules to clean the build directory, to install the + generated BSP(s) and C start up file(s), and rules to ensure + configure and Makefile + are regenerated when necessary. +

+ There also hooks to create, clean and install any documentation + (as info files), which are empty by default. +

+ Very often these rules are sufficient, so long as all the entities + created have been listed in OUTPUTS. They + should be modified if necessary. +

5.6.  + The Default BSP, libnosys +

+ Newlib also builds a default BSP + libnosys.a. This can be used with the + -lnosys flag, and provides a convenient way of + testing that code will link correctly in the absence of a full BSP +

+ The code can be found in the libnosys + sub-directory of the main libgloss directory. +

+ For completeness, the configuration template file, + configure.in, in this directory should be updated + for any new target that is defining namespace clean versions of the + functions. Each such system is selected using a + case statement. The new entry for the OpenRISC 1000  is as + follows. +

+  or32-*-*)
+	;;
+	

+ Having updated the configuration template, run autoconf to + regenerate the configure script file. +

Chapter 6.  + Configuring, Building and Installing Newlib and Libgloss +

+ Having made all the changes it is not time to configure, build and + install the system. The examples in this chapter for the OpenRISC 1000  assume a + unified source tree in srcw and a build directory, + bld-or32, with the installation directory prefix + /opt/or32-elf-new. +

6.1.  + Configuring Newlib and Libgloss +

+ Newlib is configured as follows. +

+cd bld-or32
+../srcw/configure --target=or32-elf --with-newlib --prefix=/opt/or32-elf-new
+	
[Note]Note

+ Other options may be needed on the command line if other GNU tools + are being built. However these are the options relevant to newlib +

6.2.  + Building Newlib and Libgloss +

+ The system is built using make from within the + bld-or32 directory. +

+make all-target-newlib
+make all-target-libgloss
+	

6.3.  + Testing Newlib and Libgloss +

+ Testing newlib and libgloss requires further configuration. The + details are discussed later in this application note (see Chapter 8). For now this step can be skipped. +

6.4.  + Installing Newlib and Libgloss +

+ The system is installed using make from within the + bld-or32 directory. +

+make install-target-newlib
+make install-target-libgloss
+	

Chapter 7.  + Modifying the GNU Tool Chain +

7.1.  + Putting Newlib in a Custom Location +

+ Normally newlib will be installed in a standard place with the rest + of the tool chain. Its headers will go in the + include directory within the target specific + installation directory. The C runtime start up file, the newlib + libraries themselves and BSP libraries will go in the + lib directory within the target specific + installation directory. +

+ This arrangement ensures that GCC will pick up the headers and + libraries automatically and in the correct sequence. +

+ However if newlib is not the only C library, then this may be + inconvenient. For example the OpenRISC 1000  usually uses uClibc, and + only uses newlib when regression testing the GNU tool chain. +

+ The solution is to move the newlib headers and libraries to a custom + location and modify GCC to search there when newlib is being used + (see Section 7.2). +

+ This is achieved with a simple script at the end of build and + install. For example with the OpenRISC 1000  the following command will + suffice, where the prefix used for the entire tool chain build is in + ${install_dir}. +

+mkdir -p ${install_dir}/or32-elf/newlib
+rm -rf ${install_dir}/or32-elf/newlib-include
+mv ${install_dir}/or32-elf/include ${install_dir}/or32-elf/newlib-include
+mv ${install_dir}/or32-elf/lib/*.a ${install_dir}/or32-elf/newlib
+mv ${install_dir}/or32-elf/lib/crt0.o ${install_dir}/or32-elf/newlib
+	

7.2.  + Changes to GCC +

+ In general GCC will work with newlib with no change. All that is + needed is to include the BSP library on the command line. +

+ However it is convenient to modify GCC so that it picks up the BSP + automatically. This is particularly useful when newlib has been + installed in a custom location (see Section 7.1). +

+ This is achieved by adding machine specific options to GCC, and + modifying the Spec definitions to pick up the newlib libraries when + the relevant option is in effect. +

+ All the relevant files are found in the + gcc/config/target + directory of GCC. For the 32-bit OpenRISC 1000  this is + gcc/config/or32. +

7.2.1.  + Adding Machine Specific Options for Newlib +

+ Machine specific options are described in the + target.opt file. By + convention machine specific options begin with 'm'. +

+ For the OpenRISC 1000  we define two options, + -mor32-newlib and + -mor32-newlib-uart for the plain and UART + enabled versions of the BSP respectively. +

+ For each option we provide its name on one line, any parameters on + subsequent lines and a final line of description. In this case the + only parameter is to say that the parameter can only appear in its + positive form (i.e. --mno-or32-newlib is not + permitted). +

+mor32-newlib
+Target RejectNegative
+Link with the OR32 newlib library
+
+mor32-newlib-uart
+Target RejectNegative
+Link with the OR32 newlib UART library
+	  

+ These parameters can then be used elsewhere. +

7.2.2.  + Updating Spec Definitions +

+ GCC calls a number of subsidiary programs (the compiler itself, + the assembler, the linker etc). The arguments to these are built up + from the parametrized strings, known as Spec + strings. +

+ This application note cannot describe the huge range of possible + parameters. However we will use one example to show what is + possible. The changes are all made to the definitions of the strings + in target.h. In the + case of the OpenRISC 1000  this is or32.h. +

+ We need to make four changes. +

  1. + We need to tell the C preprocessor to look for headers in the + relocated newlib library directory. +

  2. + We need to tell the linker to pick up the newlib C runtime + start up file. +

  3. + We need to tell the linker where to find the newlib libraries. +

  4. + We need to tell the linker to include the BSP library in the + right place. +

+ The Target Specific Installation Directory +

+ All of these changes will require knowing the location of the + target specific installation directory. Unfortunately there is no + Spec parameter giving this. However we can construct it from two + definitions available when compiling + GCC. STANDARD_EXEC_PREFIX is the directory + where the GCC executables will be found. Two directories up from + that will be the main prefix directory. The target machine is + specified in DEFAULT_TARGET_MACHINE. So + concatenating the three strings yields the target specific + directory. +

+STANDARD_EXEC_PREFIX "/../../" DEFAULT_TARGET_MACHINE
+	    

+ The newlib headers are in the subdirectory + newlib-include and the C runtime start up and + libraries in newlib. +

+ We define a new string, TARGET_PREFIX based on + the concatenation. +

+#define CONC_DIR(dir1, dir2) dir1 "/../../" dir2
+#define TARGET_PREFIX CONC_DIR (STANDARD_EXEC_PREFIX, DEFAULT_TARGET_MACHINE)
+	    

+ Defined constants cannot be used directly in Spec strings, but we + can make them available by defining the macro + EXTRA_SPECS. +

+#define EXTRA_SPECS                                   \
+  { "target_prefix", TARGET_PREFIX }
+	    

+ The Spec string target_prefix is now available + to be used in other Spec strings. +

+ Specifying the header directory. +

+ Additional arguments to the C preprocessor are defined in + CPP_SPEC. The newlib header directory should + we searched after any user specified header directories (from + -I arguments) and after the GCC system + headers. So it is specified using the + -idirafter option. +

+#undef CPP_SPEC
+#define CPP_SPEC "%{mor32-newlib*:-idirafter %(target_prefix)/newlib-include}"
+	    

+ This specifies that any option beginning + -mor32-newlib should be replaced by the string + -idirafter followed by the + newlib-incldue subdirectory of the + target_prefix directory. +

+ So so for example, if we build the OpenRISC 1000  GCC with + --prefix=/opt/or32-elf-new, we would have + STANDARD_EXEC_PREFIX set to + /opt/or32-elf-new/lib/gcc and + DEFAULT_TARGET_MACHINE set to + or32-elf. The Spec variable + target_prefix would therefore be + /opt/or32-elf-new/lib/gcc/../../or32-elf and + thus the C preprocessor would have the following added to its + option list. +

+-idirafter /opt/or32-elf-new/lib/gcc/../../or32-elf/newlib-include"
+	    

+ This substitution only occurs when + -mor32-newlib or + -mor32-newlib-uart is specified, which is + exactly the behavior desired. +

[Note]Note

+ If newlib is not relocated as described in Section 7.1, then the headers will be in a + standard location, which GCC will search anyway, so there is + no need to define CPP_SPEC. +

+ Specifying the C Start up File +

+ crt0.o should be the first object file or + library specified to the linker. This is covered by + STARTFILE_SPEC. +

+ This string already has a partial definition, to look for + crt0.o in a standard place, and to include + the crtinit.o file from a standard place. +

+#undef STARTFILE_SPEC
+#define STARTFILE_SPEC "%{!shared:crt0%s crtinit.o%s}"
+	    

+ So long as -shared is not specified as an + option, this looks for crt0.o and + crtinit.o in standard directories and + substitutes them on the command line (the suffix + %s indicates that the preceding file should be + searched for in standard directories, and its name expanded to + include the directory name). +

+ This needs changing to indicate that if + -mor32-newlib or + -mor32-newlib-uart is specified, then + crt0.o should be taken from the newlib + directory. +

+#define STARTFILE_SPEC \
+    "%{!shared:%{mor32-newlib*:%(target_prefix)/newlib/crt0.o} \
+     %{!mor32-newlib*:crt0.o%s} crtinit.o%s}"
+	    

+ Note that we must also include the case that when neither of the + newlib options is specified, then crt0.o + will be searched for in standard directories. +

[Note]Note

+ If newlib is not relocated as described in Section 7.1, then + crt0.o will be in a standard location, + which GCC will search anyway, so there is no need to modify + STARTFILE_SPEC. +

+ Specifying the Newlib library location +

+ We need to tell the linker where to look for newlib + libraries. This is achieved in a similar manner to the search for + the headers, but using the -L option and + LINK_SPEC. +

+#undef LINK_SPEC
+#define LINK_SPEC "%{mor32-newlib*:-L%(target_prefix)/newlib}"
+	    
[Note]Note

+ If newlib is not relocated as described in Section 7.1, then the newlib libraries + will be in a standard location searched by GCC, so there is no + need to specify LINK_SPEC. +

+ Adding a BSP to the link line. +

+ The libraries searched by GCC are by default specified to be + -lgcc -lc -lgcc, with variants if + profiling is being used. When a BSP is used, it must be searched + after libc, but that can leave references unresolved, so libc + must be searched again afterward. +

+ The sequence of libraries to be searched between the two searches + of libgcc is given in LIB_SPEC. It already + has a definition. +

+#define LIB_SPEC "%{!p:%{!pg:-lc}}%{p:-lc_p}%{pg:-lc_p}
+	    

+ This specifies a variant library when profiling is in + place. newlib does not offer profiling support, but it does have + a debugging version of the library (libg). +

+#undef LIB_SPEC 
+#define LIB_SPEC "%{!mor32-newlib*:%{!p:%{!pg:-lc}}%{p:-lc_p}%{pg:-lc_p}} \
+                  %{mor32-newlib:%{!g:-lc -lor32 -lc}                     \
+                                 %{g:-lg -lor32 -lg}}                     \
+                  %{mor32-newlib-uart:%{!g:-lc -lor32uart -lc}            \
+                                 %{g:-lg -lor32uart -lg}}"
+	    

+ This ensures that the correct BSP library will be used, + according the the option selected, and that if + -g is specified on the command line, the + debugging version of the C library (libg) will be used instead. +

+ Even if the newlib is not relocated as described in Section 7.1, then this Spec change is + required in order to ensure the correct libraries are picked up. +

7.3.  + Changes to the GNU Linker +

+ In general changes to the linker are not needed. Instead the BSP + should make use of information provided by the standard linker. For + example in the definition of sbrk (see Section 5.3.15) the code uses the _end symbol + defined by the linker at the end of the loaded image to be the start + of the heap. +

Chapter 8.  + Testing Newlib and Libgloss +

+ Newlib and libgloss both come with DejaGnu test infrastructures, + although as noted in Section 8.2, the + libgloss infrastructure is non-functional. +

+ The total number of tests is modest (24 tests in release 1.18.0). In + practice much of the testing is achieved through the GCC test suite + (40,000+ tests) and the GDB test suite (5,000+ tests). +

8.1.  + Testing Newlib +

+ Like all tools, newlib can be tested with a DejaGnu + test suite. DejaGnu must be installed on the test machine. +

+ If you already have testing set up for other tools in the GNU tool + chain on your target, then you can skip the remainder of this section, + and just test newlib from the build directory with the following. +

+	  cd bld-or32
+	  make check-target-newlib
+	

+ If this is the first time you have tried testing, then you'll need to + set up your system appropriately. Once this is done, you will be able + to test all the GNU tool chain components. +

+ The tests require a target on which to run the tests. This can be a + physical machine, or it can be a simulator for the target + architecture. +

+ The details of the target are provided in an expect board + configuration file. This is referenced from the DejaGnu global + configuration file. The environment variable + DEJAGNU should point to the global configuration + file. +

+ For the OpenRISC 1000 , the global configuration file is in + site.exp and a subdirectory, + boards contains + or32-sim.exp, which is the board configuration + file for the OpenRISC simulator target. +

+ The site.exp file has two functions. First, it + must add the boards directory to the list of + board directories to search. Secondly, it must ensure that the target + triplet name is mapped to the name of the board configuration file. +

+ This site.exp file can be reused for checking + other targets in the GNU tool chain, which may have a different + test suite hierarchy. We cannot therefore just reference the + boards directory relative to the test + directory. All we know is that it will be in one of the directories + above, and there is no other boards directory in the hierarchy, so we + add all the possible directories. Not elegant, but effective. +

+#Make sure we look in the right place for the board description files
+if ![info exists boards_dir] {
+        set boards_dir {}
+}
+
+# Crude way of finding the boards directory
+lappend boards_dir "${tool_root_dir}/../boards"
+lappend boards_dir "${tool_root_dir}/../../boards"
+lappend boards_dir "${tool_root_dir}/../../../boards"
+lappend boards_dir "${tool_root_dir}/../../../../boards"
+
+global target_list
+  case "$target_triplet" in {
+    { "or32-*-elf" } {
+        set target_list { "or32-sim" }
+    }
+  }
+	

+ Within the boards directory, the board + configuration file, or32-sim.cfg gives all the + details required for the configuration. +

+ The tool chains supported by this board are specified first. In the + case of the OpenRISC 1000 , only one is supported. +

+set_board_info target_install {or32-elf}
+	

+ We then need to load some generic routines, and the generic board + configuration. +

+load_generic_config "sim"
+load_base_board_description "basic-sim"
+	

+ The default settings assume that a program is executed on the target + by a command named run, built in a target specific + subdirectory of the top level sim directory. In + the case of the OpenRISC 1000  this directory would be + sim/or32. +

+ At a minimum, run takes as argument an executable + to run, and returns the exit code from that executable as its result. +

+ The sim directory is usually distributed as part + of GDB. Simulators may be derived from CGEN specifications of the + architecture, or by integrating third party simulators. The latter is + the case for the OpenRISC 1000 . +

+ The default settings for a target are obtained using the + setup_sim procedure. +

+setup_sim or32
+	

+ The remainder of the file is used to configure variations on the + default settings. This is done using the + set_board_info procedure. +

+ The OpenRISC 1000  simulator needs an additional argument, which is a + configuration file for the simulator. We know that file will be in the + libgloss target directory and named sim.cfg. We + can use the lookfor_file procedure to search up + from the current source directory to locate the file. +

+set cfg_file [lookfor_file ${srcdir} libgloss/or32/sim.cfg]
+set_board_info sim,options "-a \"-f ${cfg_file}\""
+	

+ A number of helpful procedures make it easy to locate parts of the + tool chain and their default arguments. For the OpenRISC 1000  we make one + change, which is to specify -mor32-newlib for the + linker flags, so that the newlib BSP will be used. +

+process_multilib_options ""
+set_board_info compiler "[find_gcc]"
+set_board_info cflags "[libgloss_include_flags] [newlib_include_flags]"
+set_board_info ldflags "[libgloss_link_flags] -mor32-newlib [newlib_link_flags]"
+set_board_info ldscript ""
+	

+ Not all targets have the same functionality, and the remaining options + specify those limitations. This is a generic board specification, so + some of these apply to testing components other than newlib. The + limitations specified will mean that some tests, which are + inappropriate do not run. +

+ For the OpenRISC 1000  we specify that the simulator is fast, that programs it + runs cannot be passed arguments, that it does not support signals + (for testing GDB) and that the maximum stack size is 64KB (for + testing GCC). +

+set_board_info slow_simulator 0
+set_board_info noargs  1
+set_board_info gdb,nosignals  1
+set_board_info gcc,stack_size 65536
+	

+ We can now set DEJAGNU to point to the global + configuration directory, change to the build directory and run the + make command to check newlib. +

+	  export DEJAGNU=`pwd`/site.exp
+	  cd bld-or32
+	  make check-target-newlib
+	

+ The good thing is that this set up is generic across all the GNU + tool chain, so all the other tools can be checked in the same way. +

8.1.1.  + Checking Physical Hardware +

+ The same technique can be used to run the tests against physical + hardware rather than a simulator. The setup of the board + configuration is rather more complicated, with considerable + variation for different arrangements. +

+ The detail is beyond the scope of this application note, but is well + described in Dan Kegel's Crosstool project + [2]. +

8.2.  + Testing Libgloss +

+ In principle, having set up newlib testing, testing libgloss + should be as simple as: +

+	  cd bld-or32
+	  make check-target-libgloss
+	

+ Unfortunately, the current newlib release (at the time of writing + 1.18.0) does not implement testing for libgloss. The + testsuite subdirectory exists, but the code to + configure it is currently commented out in + configure.in. +

It should not be difficult to build the infrastructure. However + as noted at the start of this chapter, testing of newlib and + libgloss is as much achieved through GCC and GDB testing as + through the modest number of tests within newlib +

Chapter 9.  + Summary Checklist +

+ This summary can be used as a checklist when creating a new port of + newlib. The configuration and build steps are typically encapsulated + in a simple shell script, which builds, tests and installs the entire + GNU tool chain as well as newlib and libgloss +

+ Throughout this checklist, the new target architecture is referred to as + target. It is recommended newlib and + libgloss are built as part of a unified source tree including the + newlib distribution (see Section 2.1). +

  1. + Edit newlib/configure.host adding entries for + the new target (Section 3.3). +

    • + Decide whether to implement reentrant or non-reentrant system + calls and whether to use namespace clean system call names + (Section 3.2). +

  2. + Add a newlib machine subdirectory for the new target, + newlib/libc/machine/target + (Section 4.1). +

    • + Modify configure.in in + newlib/libc/machine to configure the new + target subdirectory and run autoconf in + newlib/libc/machine to regenerate the + configure script (Section 4.1.1). +

  3. + Implement setjmp and + longjmp in the target specific machine + directory, + newlib/libc/machine/target + (Section 4.1.2). +

    • + Copy and modify Makefile.am and + configure.in from the fr30 directory and + run aclocal, autoconf and automake in + newlib/libc/machine/target + to regenerate the configure script and + Makefile template. (Section 4.1.3). +

  4. + Modify newlib header files (Section 4.2). +

    • + Add entries in newlib/libc/include/ieeefp.c + (Section 4.2.1) +

    • + Add entry in in + newlib/libc/include/setjmp.c (Section 4.2.2) +

    • + Add entries in + newlib/libc/include/sys/config.h (Section 4.2.3). +

    • + Optionally add other custom headers in + newlib/libc/machine/target/machine (Section 4.2.4). +

  5. + Add a libgloss platform directory, + libgloss/target + (Section 5.1). +

    • + Modify libgloss/configure.in to configure the + platform subdirectory and run autoconf in the + libgloss directory to regenerate the + configure script (Section 5.1.1). +

  6. + Implement the Board Support Package(s) for the target (Chapter 5). +

    • + Implement the C Runtime start up, + crt0.o for each BSP (Section 5.2). +

    • + Implement the environment global variable and 18 system call + functions for each BSP following the convention namespace and + reentrancy conventions specified in + newlib/configure.host (Section 5.3 and Section 5.4). +

    • + Create + libgloss/target/Makefile.in + and + libgloss/target/configure.ac, + based on the versions in the + libgloss/libnosys directory and run + aclocal and autoconf in + libgloss/target + (Section 5.5). +

  7. + If necessary update + libgloss/libnosys/configure.in to indicate the + target is using namespace clean system calls and run autoconf in + libgloss/libnosys (Section 5.6). +

  8. + Modify GCC for newlib (Section 7.2). +

    • + Optionally add target specific option(s) to specify newlib + BSP(s) (Section 7.2.1). +

    • + Optionally specify the location of newlib headers, the BSP C + runtime start up file and the newlib libraries, if they have been + moved from their standard locations and/or names (Section 7.2.2) +

    • + Specify the libgloss BSP library to be linked, ensuring + malloc and free are + linked in if required (the section called “ + Adding a BSP to the link line. + ”). +

  9. + Ensure the linker scripts are suitable for use with newlib (Section 7.3). +

  10. + Configure and build newlib and libgloss (Chapter 6). +

    • + Optionally move the newlib header directory, libraries, C + start-up and BSP(s) to a custom location (Section 7.1). +

    • + Rebuild GCC +

    • + Rebuild ld if any linker scripts have been changed. +

  11. + Test newlib (Section 8.1). +

  12. + Install newlib and libgloss (Chapter 6). +

    • + Reinstall GCC +

    • + Reinstall ld if any linker scripts have been changed. +

+ You should now have a working newlib implementation integrated within + your GNU tool chain. +

+ Glossary +

Application Binary Interface (ABI)

+ The definition of how registers are used during function call and + return for a particular architecture. +

big endian

+ A multi-byte number representation, in which the most significant + byte is placed first (i.e. at the lowest address) in memory. +

+ See also little endian +

Board Support Package (BSP)

+ The low level interface between an operating system or library and + the underlying physical platform. +

Block Stated by Symbol (BSS)

+ Universally known by its acronym (the full name is a historical + relic), this refers to an area of storage used for holding static + variables and initialized to zero. +

little endian

+ A multi-byte number representation, in which the least significant + byte is placed first (i.e. at the lowest address) in memory. +

+ See also big endian +

reentrant

+ A function which is reentrant may be safely + called from another thread of control while an initial thread's flow + of control is still within the function. +

+ In general a function will be reentrant if it changes no static + state. +

special purpose register (SPR)

+ A set of up to 216 32-bit registers used + to hold additional information controlling the operation of the + OpenRISC 1000  +

supervision register

+ An OpenRISC 1000  special purpose register holding information about the + most recent test result, whether the processor is in supervisor + mode, and whether certain functions (cache etc) are enabled. +

+ See also special purpose register +

+ References +

[1] + + The Red Hat Newlib C Library + + + Available at sourceware.org/newlib/libc.html. + +

[2] + + The Crosstool Project, + + DanKegel. + + Available at www.kegel.com/crosstool. + +

diff --git a/userspace/ncurses/Makefile b/userspace/ncurses/Makefile index 4a8fc56..22bae34 100644 --- a/userspace/ncurses/Makefile +++ b/userspace/ncurses/Makefile @@ -1,8 +1,11 @@ CC=i686-foolos-gcc -AS=i686-foolos-as +CFLAGS= +CFLAGS+=-O0 +#CFLAGS+=-gstabs +CFLAGS+=-g -LDLIBS=-lncurses -lcurses -CFLAGS=-static +#LDLIBS=-lncurses -lform -lmenu -lpanel -ltinfo +LDLIBS=-lncurses -ltinfo ncurs: diff --git a/userspace/ncurses/ncurs.c b/userspace/ncurses/ncurs.c index 6edf8e6..26068fa 100644 --- a/userspace/ncurses/ncurs.c +++ b/userspace/ncurses/ncurs.c @@ -1,13 +1,75 @@ #include +#include "../newcalls.h" + +int dup(int oldfd) +{ + return _dup2(oldfd,0xffffffff); // dup emulation mode +} + +void print_in_middle(WINDOW *win, int starty, int startx, int width, char *string) +{ + int length, x, y; + float temp; + + if(win == NULL) + win = stdscr; + getyx(win, y, x); + if(startx != 0) + x = startx; + if(starty != 0) + y = starty; + if(width == 0) + width = 80; + + length = strlen(string); + temp = (width - length)/ 2; + x = startx + (int)temp; + mvwprintw(win, y, x, "%s", string); + refresh(); +} + +/* +int write() +{ + printf("hi\n"); +} +*/ int main() { -// initscr(); /* Start curses mode */ + initscr(); + + //cbreak(); + ////noecho(); + +if(has_colors() == FALSE) + + { endwin(); + printf("Your terminal does not support color\n"); + exit(1); + } + + start_color(); /* Start color */ + init_pair(1, COLOR_RED, COLOR_BLACK); + + attron(COLOR_PAIR(1)); + print_in_middle(stdscr, LINES / 2, 0, 0, "Viola !!! In color ..."); + attroff(COLOR_PAIR(1)); + getch(); + print_in_middle(stdscr, LINES / 2, 0, 0, "Fool Masters"); + getch(); + endwin(); + + //write(); + +// initscr(); /* Start curses mode */ // printw("Hello World !!!"); /* Print Hello World */ // refresh(); /* Print it on to the real screen */ // getch(); /* Wait for user input */ + //while(1); + // endwin(); /* End curses mode */ - return 0; +// return 0; } diff --git a/userspace/sysc.c b/userspace/sysc.c new file mode 100644 index 0000000..f5a6719 --- /dev/null +++ b/userspace/sysc.c @@ -0,0 +1,4 @@ +int main() +{ + write(1,"dupa\n",5); +} -- cgit v1.2.3