big commit mostly related to moving start addresses to 0x8000
This commit is contained in:
226
README
226
README
@@ -1,17 +1,32 @@
|
||||
|
||||
Right, I know...Got my raspberry pi today.
|
||||
|
||||
This repo serves as a collection of low level examples. No operating
|
||||
system, embedded or low level embedded or deeply embedded, whatever
|
||||
your term is for this.
|
||||
system, embedded or low level embedded or deeply embedded or bare metal,
|
||||
whatever your term is for this.
|
||||
|
||||
From what we know so far there is a gpu on chip that boots off of I
|
||||
assume an on chip rom. This goes to the sd card and does things. it
|
||||
appears that the entry point for us as programmers is the kernel.img
|
||||
file, which appears to be the memory image copied into the ARM memory
|
||||
before releasing reset on the ARM processor. The name of course because
|
||||
this is intended to be a Linux based educational computer, but it is
|
||||
just a file name, just a memory image.
|
||||
I am in no way shape or form associated with the raspberry pi organization
|
||||
nor broadcom. I just happen to own one (some) and am sharing my
|
||||
experiences. The raspberry pi is about education, and I feel low
|
||||
level education is just as important as Python programming.
|
||||
|
||||
From what we know so far there is a gpu on chip which:
|
||||
|
||||
1) boots off of an on chip rom of some sort
|
||||
2) reads the sd card and looks for additional gpu specific boot files
|
||||
bootcode.bin, loader.bin, start.elf in the root dir of the first partition
|
||||
(fat formatted)
|
||||
3) in the same dir it looks for config.txt which you can do things like
|
||||
change the arm speed from the default 700MHz, change the address where
|
||||
to load kernel.img, and many others
|
||||
4) it reads kernel.img the arm boot binary file and copies it to memory
|
||||
5) releases reset on the arm such that it runs from the address where
|
||||
the kernel.img data was written
|
||||
|
||||
I have tried a few things for example incorrectly assuming kernel.img
|
||||
was loaded at address 0x00000000 as a default. If you tell it zero you
|
||||
still get 0x8000. The arm and gpu share memory I am guessing the gpu
|
||||
is using that first part of memory, dont really know. 0x8000 being
|
||||
familiar to linux folks and this is intended to be first a linux
|
||||
computer so this makes sense.
|
||||
|
||||
You will want to go here
|
||||
http://elinux.org/RPi_Hardware
|
||||
@@ -22,46 +37,87 @@ And the schematic for the board
|
||||
http://www.raspberrypi.org/wp-content/uploads/2012/04/Raspberry-Pi-Schematics-R1.0.pdf
|
||||
(might be an old link, find the one on the wiki page)
|
||||
|
||||
The manual uses addresses like 0x7Exxxxxx, which is the real address for
|
||||
something. But there is an address translation layer between the ARM
|
||||
physical address and the real address. All of this code will use the
|
||||
ARM physical address which is 0x20xxxxxx. The rest of the address is
|
||||
the same so if the manual says 0x7E123456, then from the ARM use 0x20123456
|
||||
Early in the BCM2835 document you see a memory map. I am going to
|
||||
operate based on the middle map, this is how the ARM comes up. The
|
||||
left side is the system which we dont have direct access to in that
|
||||
form, the gpu probably, not the ARM. The ARM comes up with a memory
|
||||
space that is basically 0x40000000 bytes in size as it mentions in
|
||||
the middle chart. 256MBytes is 0x10000000, I am guessing they gave
|
||||
room to add memory as peripherals are mapped into arm address space at
|
||||
0x20000000. When you see 0x7Exxxxxx in the manual replace that with
|
||||
0x20xxxxxx as your ARM physical address. Experimentally I have seen
|
||||
the memory repeats every 0x40000000, read 0x40008000 and you see the
|
||||
data from 0x8000. I wouldnt rely on this, just an observation (likely
|
||||
ignoring the upper address bits in the memory controller).
|
||||
|
||||
I dont normally use .data nor gcc libraries nor C libraries so you can
|
||||
build most if not all of my examples using a gcc cross compilerl. Basically
|
||||
Now this memory map shows that somewhere within the SDRAM address space
|
||||
there is a boundary between the ARM memory in the lower addresses and
|
||||
the GPU memory in the upper addresses. That boundary is not explained
|
||||
in that document. There are at the moment three gpu start.elf files
|
||||
to choose from. A or the difference between them is where this boundary
|
||||
lies. The default is a 50/50 split the arm gets 128MBytes, and the gpu
|
||||
128MBytes. arm224_start.elf for example gives 224MBytes to the ARM
|
||||
and 32MBytes to the GPU. They say that you dont get full gpu performance
|
||||
if you limit the gpu memory this much. These examples are all going
|
||||
to assume that the ARM only has 128MBytes and the default boot setting
|
||||
of 0x8000 for the kernel_address.
|
||||
|
||||
I do not normally use .data nor gcc libraries nor C libraries so you can
|
||||
build most if not all of my examples using a gcc cross compiler. Basically
|
||||
it doesnt matter if you use arm-none-linux-gnueabi or arm-none-eabi.
|
||||
what was formerly codesourcery.com still has a LITE version of their
|
||||
What was formerly codesourcery.com still has a LITE version of their
|
||||
toolchain which is easy to come by, easy to install and well maybe not
|
||||
easy to use but you can use it. Building your own toolchain from gnu
|
||||
sources (binutils and gcc) is fairly straight forward and at some point
|
||||
will create a script to do that for you.
|
||||
sources (binutils and gcc) is fairly straight forward see the build_gcc
|
||||
directory for a build script.
|
||||
|
||||
As far as we know so far the Raspberry Pi is not "brickable". Normally
|
||||
what brickable means is the processor relies on a boot flash. For example
|
||||
there may be a bootloader that allows you to re-program the flash. If you
|
||||
make a mistake writing code at this low level and load the boot flash
|
||||
with that bad code you may not be able to reload the flash again. There
|
||||
are many ways to prevent this, but there are also still boards that
|
||||
can be bricked or at least require more equipment or soldering, etc to
|
||||
recover them. They way this board works is quite interesting. There
|
||||
is a GPU on chip that boots from an on chip flash (in that respect it
|
||||
may be brickable, but we dont have access to that GPU boot loader). The
|
||||
GPU on chip bootloader looks for an sd card, the sd card contains more
|
||||
GPU code. That code probably initializes sdram, and then copies the
|
||||
contents of kernel.img on the sd card to sdram. Then releases reset
|
||||
on the ARM. Each of these example programs produce a .bin file.
|
||||
kernel.img is nothing more than a .bin file, an image of the flash.
|
||||
The filename is special to the raspi bootloder, so you need to use
|
||||
that file name. Backup your original kernel.img if you want to go back
|
||||
to playing with linux then copy the .bin file in the example to
|
||||
kernel.img on the sd card. For example
|
||||
cp blinker01.bin /media/9876-5432/kernel.img
|
||||
sync
|
||||
umount /media/9876-5432
|
||||
Insert the sd card into the raspi and power.
|
||||
what brickable means is the processor relies on a boot flash and with
|
||||
that flash it is possible to change/erase it such that the processor will
|
||||
not boot normally. Brickable and bricked sometimes excludes things
|
||||
like jtag or speciall programming headers. From the customers perspective
|
||||
a bricked board is...bricked. But on return to the vendor they may
|
||||
have other equipment that is able to recover the board without doing
|
||||
any soldering, perhaps plugging in jtag or some other cable on pins/pads
|
||||
they have declared as reserved. Take apart a tv remote control or
|
||||
calculator, etc and you may see some holes or pads on the circuit board,
|
||||
for some of these devices just opening the battery case you have a view
|
||||
of some of the pcboard. This is no doubt a programming header. Long
|
||||
story short, so far as I know the Raspberry Pi is not brickable because
|
||||
the rom/flash that performs the initial boot is for the gpu and we dont
|
||||
have access to the gpu nor its boot rom/flash. The gpu relies on the
|
||||
sd card to complete the boot, so the sd card flash is really the boot
|
||||
flash for the system. And it is very easy for the customer to remove
|
||||
and replace/modify that boot flash. So from a software perspective
|
||||
unless you/we accidentally figure out how to change/erase the gpu boot
|
||||
code (my guess is it is a one time programmable) you cant brick it.
|
||||
|
||||
It wont take you very long to figure out this is going to get painful.
|
||||
To use my samples you do not need a huge sd card. Nor do you need nor
|
||||
want to download one of the linux images, takes a while to download,
|
||||
takes a bigger sd card to use, and takes forever to write to the sd card.
|
||||
AND I am not able to run with the firmware on those cards. I use the
|
||||
firmware from http://github.com/raspberrypi. The minimum configuration
|
||||
you need to get started at this level is:
|
||||
|
||||
go to http://github.com/raspberrypi, you DO NOT need to download
|
||||
the repo, they have some large files in there you will not need (for
|
||||
my examples). go to the firmware directory and then the boot directory.
|
||||
For each of these files, bootcode.bin, loader.bin, start.elf (NOT
|
||||
kernel.img, dont need it, too big). Click on the file name, it will
|
||||
go to another page then click on View Raw and it will let you download
|
||||
the file.
|
||||
|
||||
bootcode.bin is about 2MBytes, the other files are smaller, so you will
|
||||
want an sd card that is at least a few meg, probably a full 128MBytes or
|
||||
256MBytes or larger (gigabytes are just fine) for the gpu files plus
|
||||
the sample files here. ARM memory for these samples is assumed 128MB
|
||||
so they wont be even that large.
|
||||
|
||||
What I do is setup the sd card with a single partition, fat32. And
|
||||
copy the above files. bootcode.bin, loader.bin and start.elf. From
|
||||
there you take .bin files from my examples and place them on the sd card
|
||||
with the name kernel.img. It wont take you very long to figure out this
|
||||
is going to get painful.
|
||||
|
||||
1) power off raspi
|
||||
2) remove sd card
|
||||
@@ -79,59 +135,69 @@ There are ways to avoid this, one is jtag, which is not as expensive
|
||||
as it used to be. It used to be in the thousands of dollars, now it
|
||||
is under $50 and the software tools are free. Now the raspi does have
|
||||
jtag on the arm, getting the jtag connected to that is going to require
|
||||
some soldering. I have not done it yet but will and will post info.
|
||||
Unfortunately the connection to jtag is not there on power up you have
|
||||
to run some code on the arm, so when that happens I will post that
|
||||
program.
|
||||
some soldering. (this is described later and in the armjtag sample).
|
||||
|
||||
Another method is a bootloader, typically you connect a serial port.
|
||||
The program that actually boots on the processor has some way for you
|
||||
to get into a bootloader. Sometimes that is all that is there, sometimes
|
||||
you have to hit a key within a few seconds after it starts to boot.
|
||||
The bootloader will have some way for you to use either the serial
|
||||
or ethernet to copy a file into memory or flash. In this case probably
|
||||
memory. I have a bootloader that works. Am working on a second one
|
||||
that will probably be easier/better to use. With the bootloader method
|
||||
at least how I am implementing it for the raspi, you perform the sd
|
||||
card dance above one time to copy the bootloader to the sd card. You
|
||||
use some flavor of serial port as described below. When the board
|
||||
boots you can load your programs over the serial connection, never
|
||||
needing to do the sd card dance until you want to leave your application
|
||||
on the raspi and not the bootloader. The bootloader step will be
|
||||
something like:
|
||||
Another method is a bootloader, typically you use a serial port connected
|
||||
to the target processor. That processor boots a bootloader program that
|
||||
in some way, shape, or form allows you to interact with the bootloader
|
||||
and load programs into memory (that the bootloader is not using itself)
|
||||
and then the bootloader branches/jumps to your program. If your program
|
||||
is still being debugged and you want to try again, you reboot the processor
|
||||
the bootloader comes up and you can try again without having to move any
|
||||
sd cards, etc. The sd card dance above is now replaced with the
|
||||
bootloader dance:
|
||||
|
||||
1) power off raspi
|
||||
2) power on raspi
|
||||
3) type command to load and start new program
|
||||
|
||||
I have working bootloader examples. bootloader03 is the currently
|
||||
recommended version. But you need more hardware (no soldering is
|
||||
required). For those old enough to know what a serial port is, you
|
||||
CANNOT connect your raspberry pi directly to this port, you will fry
|
||||
the raspberry pi. You need some sort of serial port at 3.3V either
|
||||
a level shifter of some sort (transceiver like a MAX232) or a usb
|
||||
serial port where the signals are 3.3V (dont need to use RS232 just
|
||||
stay at the logic level). The solution I recommend is a non-solder
|
||||
solution:
|
||||
|
||||
My first bootloader is working, this will greatly save on wear and tear
|
||||
on the sd card socket. You will need some sort of serial adapter.
|
||||
The uart signals on the raspi are not at RS232 levels, you CANNOT
|
||||
simply connect them to a "COM port", you will fry your raspberry pi.
|
||||
A simple solution is to get these two items at sparkfun or something
|
||||
similar (there are many ftdi usb to serial 3.3v solutions out there)
|
||||
http://www.sparkfun.com/products/9873
|
||||
plus some male/female wire
|
||||
http://www.sparkfun.com/products/9140
|
||||
|
||||
Solutions that may involve soldering
|
||||
http://www.sparkfun.com/products/718
|
||||
http://www.sparkfun.com/products/8430
|
||||
|
||||
Or this for level shifting to a real com port.
|
||||
http://www.sparkfun.com/products/449
|
||||
|
||||
On the raspberry pi, the connector with two rows of a bunch of pins is
|
||||
P1. Starting at that corner of the board, the outside corner pin is
|
||||
pin 2. From pin 2 heading toward the yellow rca connector the pins
|
||||
are 2, 4, 6, 8, 10. Pin 6 connect to gnd on the usb to serial board
|
||||
pin 8 is tx out of the raspi connect that to RX on the usb to serial
|
||||
board. pin 10 is rx into the raspi, connect that to TX on the usb to
|
||||
pin 8 is TX out of the raspi connect that to RX on the usb to serial
|
||||
board. pin 10 is RX into the raspi, connect that to TX on the usb to
|
||||
serial board. Careful not to have metal items on the usb to serial
|
||||
board touch metal items on the raspberry pi (other than the three
|
||||
connections described). On your host computer you will want to use
|
||||
some sort of dumb terminal program, minicom, putty, etc. Set the
|
||||
serial port (usb to serial board) to 115200 baud, 8 data bits, no
|
||||
parity, 1 stop bit. NO flow control. With minicom you likely have
|
||||
to save the config, exit minicom, then restart in order for flow control
|
||||
changes to take effect.
|
||||
parity, 1 stop bit. NO flow control. With minicom to get no flow
|
||||
control you normally have to save the config, exit minicom, then
|
||||
restart minicom and load the config in order for flow control
|
||||
changes to take effect. Once you have a saved config you dont have
|
||||
to mess with it any more.
|
||||
|
||||
I recommend you start with blinker01 and follow the discovery through
|
||||
those to uart01, etc. If you dont have a bootloader, do the sd card
|
||||
dance with the .bin file.
|
||||
Read more about the bootloaders in their local README files. Likewise
|
||||
if you are able to do some soldering on electronics see the armjtag
|
||||
README file. Other than chewing up a few more GPIO pins, and another
|
||||
thing you have to buy, the jtag solution is the most powerful and useful.
|
||||
My typical setup is the armjtag binary as kernel.img, a usb to jtag
|
||||
board like the amontec jtag-tiny and a usb to serial using minicom.
|
||||
|
||||
bootloader01 uses the .hex file from the examples and prograspi program
|
||||
bootloader02 uses the .bin file from the examples and xmodem from a
|
||||
terminal program
|
||||
As far as these samples go I recommend starting with blinker01 then
|
||||
follow the discovery of the chip into uart01, etc. You will need some
|
||||
sort of cross compiler (well maybe a native compiler on a raspberry pi
|
||||
or other arm system). See the build_gcc directory if you cant get
|
||||
the LITE version from codesourcery.com (now mentor graphics).
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
|
||||
MEMORY
|
||||
{
|
||||
ram : ORIGIN = 0x00000000, LENGTH = 0x1000
|
||||
ram : ORIGIN = 0x00008000, LENGTH = 0x1000
|
||||
}
|
||||
|
||||
SECTIONS
|
||||
|
||||
@@ -1,10 +1,7 @@
|
||||
|
||||
.globl _start
|
||||
_start:
|
||||
b reset
|
||||
|
||||
reset:
|
||||
mov sp,#0x1000
|
||||
mov sp,#0x8000
|
||||
bl notmain
|
||||
hang: b hang
|
||||
|
||||
|
||||
@@ -10,9 +10,61 @@ an output. Then goes into a loop that sets the gpio, waits, resets it,
|
||||
waits, repeat. gpio16 is shown on the schematic to connect to the OK
|
||||
led. One of the bank of leds on the corner near the audio out and host
|
||||
usb ports. The blink rate for me is a few blinks a second perhaps.
|
||||
Future examples will get use a timer if there is one and narrow in on
|
||||
the clock setup, etc.
|
||||
|
||||
novectors.s is the entry point for this code. This just gets things
|
||||
started then calls a C function (blinker01.c) where the bulk of the
|
||||
program is found.
|
||||
I normally set my stack pointer to be at the top of some bank of ram
|
||||
if only one ram bank in the system then the top of that ram bank. See
|
||||
the top level README, they force us to start somewhere other than zero
|
||||
so for such simple programs like these I am setting the program to start
|
||||
at 0x8000 and the stack to start at 0x7FFC. Note that on an ARM the
|
||||
stack pointer (r13) points at the first address after the top of the
|
||||
stack so setting r13 to 0x8000 means the stack starts at 0x7FFC and
|
||||
works down away from our program.
|
||||
|
||||
vectors.s is the entry point for this program, even an application on
|
||||
an operating system like linux has some assembly up front before
|
||||
calling the main function. For this processor the minimum is to to
|
||||
set up the stack pointer and call the main function. Because some
|
||||
compilers add extra stuff if they see a main() funtion I use some
|
||||
function name other than main() typically for embedded systems like this.
|
||||
If you dont have any pre-initialized variables, and dont assume that
|
||||
un-initialized variables are zero, then you dont have or need a .data
|
||||
and wont need to zero .bss. Typically the asm that preceeds the call
|
||||
to the main function would prepare the .data segment if needed and zero
|
||||
the .bss segment. Also the linker script is usually more complicated
|
||||
to initialize global variables with the addresses and sizes of the
|
||||
segments. I dont do these things so my startup code only needs to
|
||||
set the stack pointer and branch to the main function.
|
||||
|
||||
The example includes a Makefile that is capable of building using
|
||||
gnu/gcc tools or a hybrid clang(llvm)/gnu binutils to experience an
|
||||
alternate C compiler.
|
||||
|
||||
The reason for the dummy function is that when a compiler optimizes
|
||||
code like this:
|
||||
|
||||
for(ra=0;ra<0x1000;ra++) continue;
|
||||
|
||||
It replaces it with this equivalent:
|
||||
|
||||
ra = 0x1000;
|
||||
|
||||
Which we dont want, we want the program to actually burn some time so
|
||||
we can see the led with our slow eyes.
|
||||
|
||||
The compiler doesnt know what dummy does because the asm for it is not
|
||||
something the C compiler can inspect. So
|
||||
|
||||
for(ra=0;ra<0x1000;ra++) dummy(ra);
|
||||
|
||||
To properly implement your program the C compiler must in order call
|
||||
dummy(0), dummy(1), dummy(2), etc. For smaller loops it may choose
|
||||
to unroll the loop. that is fine.
|
||||
|
||||
Another solution is to declare ra volatile and that will cause first
|
||||
the loop to not get optimized, and ra to be read from and saved to memory
|
||||
each time through the loop. I like one approach you may like another.
|
||||
|
||||
The program is simple refer to the broadcom arm document for information
|
||||
on these registers. Remember that in the broadcom document the addresses
|
||||
will be 0x7Exxxxxx not 0x20xxxxxx.
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
|
||||
MEMORY
|
||||
{
|
||||
ram : ORIGIN = 0x00000000, LENGTH = 0x1000
|
||||
ram : ORIGIN = 0x8000, LENGTH = 0x10000
|
||||
}
|
||||
|
||||
SECTIONS
|
||||
|
||||
@@ -1,10 +1,7 @@
|
||||
|
||||
.globl _start
|
||||
_start:
|
||||
b reset
|
||||
|
||||
reset:
|
||||
mov sp,#0x1000
|
||||
mov sp,#0x8000
|
||||
bl notmain
|
||||
hang: b hang
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@ these programs.
|
||||
|
||||
There is a free-running 64 bit timer, super easy to use, just read it.
|
||||
|
||||
Based on a couple of experiments, without messing with anything it
|
||||
Based on a couple of experiments, without messing with anything else it
|
||||
appears that the timer is runing at about a megahertz, 1 million ticks
|
||||
per second.
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
|
||||
MEMORY
|
||||
{
|
||||
ram : ORIGIN = 0x00000000, LENGTH = 0x1000
|
||||
ram : ORIGIN = 0x8000, LENGTH = 0x1000
|
||||
}
|
||||
|
||||
SECTIONS
|
||||
|
||||
@@ -1,10 +1,7 @@
|
||||
|
||||
.globl _start
|
||||
_start:
|
||||
b reset
|
||||
|
||||
reset:
|
||||
mov sp,#0x1000
|
||||
mov sp,#0x8000
|
||||
bl notmain
|
||||
hang: b hang
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@ on the raspberry pi. Also find information on how to load and run
|
||||
these programs.
|
||||
|
||||
This example uses the free running ARM timer, not the 64 bit system
|
||||
one as in blinker02 but the so called ARM timer.
|
||||
timer as in blinker02 but the so called ARM timer.
|
||||
|
||||
The system clock appears to come up at 250MHz as documented. Divide that
|
||||
by 250 to get 1Mhz on this free running ARM timer. Then count to four
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
|
||||
MEMORY
|
||||
{
|
||||
ram : ORIGIN = 0x00000000, LENGTH = 0x1000
|
||||
ram : ORIGIN = 0x8000, LENGTH = 0x1000
|
||||
}
|
||||
|
||||
SECTIONS
|
||||
|
||||
@@ -1,10 +1,7 @@
|
||||
|
||||
.globl _start
|
||||
_start:
|
||||
b reset
|
||||
|
||||
reset:
|
||||
mov sp,#0x1000
|
||||
mov sp,#0x8000
|
||||
bl notmain
|
||||
hang: b hang
|
||||
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
|
||||
ARMGNU ?= arm-none-eabi
|
||||
|
||||
COPS = -Wall -O2 -nostdlib -nostartfiles -ffreestanding
|
||||
AOPS = --warn --fatal-warnings
|
||||
COPS = -Wall -Werror -O2 -nostdlib -nostartfiles -ffreestanding
|
||||
|
||||
|
||||
|
||||
gcc : blinker04.hex blinker04.bin
|
||||
|
||||
@@ -37,6 +40,7 @@ blinker04.hex : blinker04.elf
|
||||
|
||||
|
||||
|
||||
|
||||
LOPS = -Wall -m32 -emit-llvm
|
||||
LLCOPS = -march=arm -mcpu=arm1176jzf-s
|
||||
LLCOPS0 = -march=arm
|
||||
@@ -64,7 +68,3 @@ blinker04.clang.bin : blinker04.clang.opt.elf
|
||||
$(ARMGNU)-objcopy blinker04.clang.opt.elf blinker04.clang.bin -O binary
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
|
||||
MEMORY
|
||||
{
|
||||
ram : ORIGIN = 0x00000000, LENGTH = 0x1000
|
||||
ram : ORIGIN = 0x8000, LENGTH = 0x1000
|
||||
}
|
||||
|
||||
SECTIONS
|
||||
|
||||
@@ -1,10 +1,7 @@
|
||||
|
||||
.globl _start
|
||||
_start:
|
||||
b reset
|
||||
|
||||
reset:
|
||||
mov sp,#0x1000
|
||||
mov sp,#0x8000
|
||||
bl notmain
|
||||
hang: b hang
|
||||
|
||||
|
||||
@@ -2,6 +2,14 @@
|
||||
//-------------------------------------------------------------------------
|
||||
//-------------------------------------------------------------------------
|
||||
|
||||
//The raspberry pi wants you to not have your kernel.img file loaded
|
||||
//at address 0x0000. Using a bootloader like this it works just fine
|
||||
//but to avoid having example binaries that are at 0x8000 for running
|
||||
//from the sd card and a binary at 0x0000 for loading with the
|
||||
//bootloader, instead the bootloader is going to default to 0x8000
|
||||
//as well.
|
||||
#define ARMBASE 0x8000
|
||||
|
||||
extern void PUT32 ( unsigned int, unsigned int );
|
||||
extern void PUT16 ( unsigned int, unsigned int );
|
||||
extern void PUT8 ( unsigned int, unsigned int );
|
||||
@@ -147,7 +155,7 @@ int notmain ( void )
|
||||
if(GET32(AUX_MU_LSR_REG)&0x01) break;
|
||||
}
|
||||
block=1;
|
||||
addr=0;
|
||||
addr=ARMBASE;
|
||||
while(1)
|
||||
{
|
||||
xstring[0]=uart_recv();
|
||||
@@ -184,7 +192,7 @@ int notmain ( void )
|
||||
}
|
||||
if(xstring[0]==0x04)
|
||||
{
|
||||
BRANCHTO(0);
|
||||
BRANCHTO(ARMBASE);
|
||||
}
|
||||
return(0);
|
||||
}
|
||||
|
||||
@@ -15,7 +15,7 @@ clean :
|
||||
rm -f *.list
|
||||
rm -f *.img
|
||||
rm -f *.bc
|
||||
rm -f *.clang.opt.s
|
||||
rm -f *.clang.s
|
||||
|
||||
|
||||
vectors.o : vectors.s
|
||||
@@ -24,14 +24,19 @@ vectors.o : vectors.s
|
||||
bootloader03.o : bootloader03.c
|
||||
$(ARMGNU)-gcc $(COPS) -c bootloader03.c -o bootloader03.o
|
||||
|
||||
kernel.img : loader vectors.o bootloader03.o
|
||||
$(ARMGNU)-ld vectors.o bootloader03.o -T loader -o bootloader03.elf
|
||||
periph.o : periph.c
|
||||
$(ARMGNU)-gcc $(COPS) -c periph.c -o periph.o
|
||||
|
||||
kernel.img : loader vectors.o periph.o bootloader03.o
|
||||
$(ARMGNU)-ld vectors.o periph.o bootloader03.o -T loader -o bootloader03.elf
|
||||
$(ARMGNU)-objdump -D bootloader03.elf > bootloader03.list
|
||||
$(ARMGNU)-objcopy bootloader03.elf -O ihex bootloader03.hex
|
||||
$(ARMGNU)-objcopy bootloader03.elf -O binary kernel.img
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
start.o : start.s
|
||||
$(ARMGNU)-as start.s -o start.o
|
||||
|
||||
@@ -50,34 +55,29 @@ blinker.bin : memmap start.o blinker.o
|
||||
|
||||
|
||||
LOPS = -Wall -m32 -emit-llvm
|
||||
LLCOPS = -march=arm -mcpu=arm1176jzf-s
|
||||
LLCOPS0 = -march=arm
|
||||
LLCOPS1 = -march=arm -mcpu=arm1176jzf-s
|
||||
LLCOPS = $(LLCOPS1)
|
||||
COPS = -Wall -O2 -nostdlib -nostartfiles -ffreestanding
|
||||
OOPS = -std-compile-opts
|
||||
|
||||
clang : bootloader03.clang.hex bootloader03.clang.bin
|
||||
|
||||
|
||||
bootloader03.clang.bc : bootloader03.c
|
||||
clang $(LOPS) -c bootloader03.c -o bootloader03.clang.bc
|
||||
|
||||
bootloader03.clang.opt.elf : loader vectors.o bootloader03.clang.bc
|
||||
opt $(OOPS) bootloader03.clang.bc -o bootloader03.clang.opt.bc
|
||||
llc $(LLCOPS) bootloader03.clang.opt.bc -o bootloader03.clang.opt.s
|
||||
$(ARMGNU)-as bootloader03.clang.opt.s -o bootloader03.clang.opt.o
|
||||
$(ARMGNU)-ld -o bootloader03.clang.opt.elf -T loader vectors.o bootloader03.clang.opt.o
|
||||
$(ARMGNU)-objdump -D bootloader03.clang.opt.elf > bootloader03.clang.opt.list
|
||||
|
||||
bootloader03.clang.hex : bootloader03.clang.opt.elf
|
||||
$(ARMGNU)-objcopy bootloader03.clang.opt.elf bootloader03.clang.hex -O ihex
|
||||
|
||||
bootloader03.clang.bin : bootloader03.clang.opt.elf
|
||||
$(ARMGNU)-objcopy bootloader03.clang.opt.elf bootloader03.clang.bin -O binary
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
clang : bootloader03.bin
|
||||
|
||||
bootloader03.bc : bootloader03.c
|
||||
clang $(LOPS) -c bootloader03.c -o bootloader03.bc
|
||||
|
||||
periph.bc : periph.c
|
||||
clang $(LOPS) -c periph.c -o periph.bc
|
||||
|
||||
bootloader03.clang.elf : loader vectors.o bootloader03.bc periph.bc
|
||||
llvm-link periph.bc bootloader03.bc -o bootloader03.nopt.bc
|
||||
opt $(OOPS) bootloader03.nopt.bc -o bootloader03.opt.bc
|
||||
llc $(LLCOPS) bootloader03.opt.bc -o bootloader03.clang.s
|
||||
$(ARMGNU)-as bootloader03.clang.s -o bootloader03.clang.o
|
||||
$(ARMGNU)-ld -o bootloader03.clang.elf -T loader vectors.o bootloader03.clang.o
|
||||
$(ARMGNU)-objdump -D bootloader03.clang.elf > bootloader03.clang.list
|
||||
|
||||
bootloader03.bin : bootloader03.clang.elf
|
||||
$(ARMGNU)-objcopy bootloader03.clang.elf bootloader03.clang.bin -O binary
|
||||
|
||||
|
||||
|
||||
@@ -1,21 +1,20 @@
|
||||
|
||||
See the top level README for information on where to find the
|
||||
schematic and programmers reference manual for the ARM processor
|
||||
on the raspberry pi. Also find information on how to load and run
|
||||
these programs.
|
||||
See the top level README file for more information on documentation
|
||||
and how to run these programs.
|
||||
|
||||
Derived from bootloader02, this is a very simple bootloader. Instead
|
||||
of the sd dance (see toplevel README), this makes life a bit simpler
|
||||
and greatly reduces physical wear and tear on the sd card socket. Do
|
||||
the sd card dance one time with kernel.img. Get some sort of serial
|
||||
solution to connect a dumb termial program (minicom, hyperterm, etc)
|
||||
with xmodem capabilities to the uart on the raspberry pi. (see toplevel
|
||||
README)
|
||||
solution to connect a dumb termial program with xmodem capabilities
|
||||
to the uart on the raspberry pi. (see the toplevel README for more
|
||||
information).
|
||||
|
||||
The difference between bootloader02 and bootloader03 is that this one
|
||||
uses a state machine for xmodem, maybe it will recover from a lost byte
|
||||
if there is ever one. You take the .bin file of your test program,
|
||||
assumed to be built based on address 0 and less than 0x200000 bytes.
|
||||
if there is ever one, maybe not. You take the .bin file of your test
|
||||
program, assumed to be built based on address 0x8000 and less than
|
||||
0x200000-0x8000 bytes in size.
|
||||
With uart connected to a terminal
|
||||
1) power off raspberry pi
|
||||
2) power on raspberry pi
|
||||
@@ -26,7 +25,10 @@ This bootloader sits at 0x200000 so that you have 0x200000 bytes to
|
||||
develop with. And that way if you like your program you can just
|
||||
copy a .bin version to kernel.img on the sd card and use it. Fairly
|
||||
easy to change this address. bootloader03.c and vectors.s each have
|
||||
a copy of this value.
|
||||
a copy of this value. bootloader04 will use a rasberry pi specific
|
||||
config file to move much deeper in memory giving you much more room
|
||||
if you want more room use that bootloader.
|
||||
|
||||
bootloader01 uses .hex files, bootloader02 and bootloader03 use .bin
|
||||
files, .hex files wont work.
|
||||
files, .hex files wont work. Consider bootloader01 and 02 to be
|
||||
obsolete.
|
||||
|
||||
@@ -2,80 +2,34 @@
|
||||
//-------------------------------------------------------------------------
|
||||
//-------------------------------------------------------------------------
|
||||
|
||||
//The raspberry pi wants you to not have your kernel.img file loaded
|
||||
//at address 0x0000. Using a bootloader like this it works just fine
|
||||
//but to avoid having example binaries that are at 0x8000 for running
|
||||
//from the sd card and a binary at 0x0000 for loading with the
|
||||
//bootloader, instead the bootloader is going to default to 0x8000
|
||||
//as well.
|
||||
#define ARMBASE 0x8000
|
||||
|
||||
extern void PUT32 ( unsigned int, unsigned int );
|
||||
extern void PUT16 ( unsigned int, unsigned int );
|
||||
extern void PUT8 ( unsigned int, unsigned int );
|
||||
extern unsigned int GET32 ( unsigned int );
|
||||
extern unsigned int GETPC ( void );
|
||||
extern void BRANCHTO ( unsigned int );
|
||||
extern void dummy ( unsigned int );
|
||||
|
||||
#define ARM_TIMER_CTL 0x2000B408
|
||||
#define ARM_TIMER_CNT 0x2000B420
|
||||
extern void uart_init ( void );
|
||||
extern unsigned int uart_lcr ( void );
|
||||
extern void uart_send ( unsigned int );
|
||||
extern unsigned int uart_recv ( void );
|
||||
extern void hexstring ( unsigned int );
|
||||
extern void hexstrings ( unsigned int );
|
||||
extern void timer_init ( void );
|
||||
extern unsigned int timer_tick ( void );
|
||||
|
||||
#define GPFSEL1 0x20200004
|
||||
#define GPSET0 0x2020001C
|
||||
#define GPCLR0 0x20200028
|
||||
#define GPPUD 0x20200094
|
||||
#define GPPUDCLK0 0x20200098
|
||||
extern void timer_init ( void );
|
||||
extern unsigned int timer_tick ( void );
|
||||
|
||||
#define AUX_ENABLES 0x20215004
|
||||
#define AUX_MU_IO_REG 0x20215040
|
||||
#define AUX_MU_IER_REG 0x20215044
|
||||
#define AUX_MU_IIR_REG 0x20215048
|
||||
#define AUX_MU_LCR_REG 0x2021504C
|
||||
#define AUX_MU_MCR_REG 0x20215050
|
||||
#define AUX_MU_LSR_REG 0x20215054
|
||||
#define AUX_MU_MSR_REG 0x20215058
|
||||
#define AUX_MU_SCRATCH 0x2021505C
|
||||
#define AUX_MU_CNTL_REG 0x20215060
|
||||
#define AUX_MU_STAT_REG 0x20215064
|
||||
#define AUX_MU_BAUD_REG 0x20215068
|
||||
|
||||
//GPIO14 TXD0 and TXD1
|
||||
//GPIO15 RXD0 and RXD1
|
||||
//------------------------------------------------------------------------
|
||||
unsigned int uart_recv ( void )
|
||||
{
|
||||
while(1)
|
||||
{
|
||||
if(GET32(AUX_MU_LSR_REG)&0x01) break;
|
||||
}
|
||||
return(GET32(AUX_MU_IO_REG)&0xFF);
|
||||
}
|
||||
//------------------------------------------------------------------------
|
||||
void uart_send ( unsigned int c )
|
||||
{
|
||||
while(1)
|
||||
{
|
||||
if(GET32(AUX_MU_LSR_REG)&0x20) break;
|
||||
}
|
||||
PUT32(AUX_MU_IO_REG,c);
|
||||
}
|
||||
//------------------------------------------------------------------------
|
||||
void hexstrings ( unsigned int d )
|
||||
{
|
||||
//unsigned int ra;
|
||||
unsigned int rb;
|
||||
unsigned int rc;
|
||||
|
||||
rb=32;
|
||||
while(1)
|
||||
{
|
||||
rb-=4;
|
||||
rc=(d>>rb)&0xF;
|
||||
if(rc>9) rc+=0x37; else rc+=0x30;
|
||||
uart_send(rc);
|
||||
if(rb==0) break;
|
||||
}
|
||||
uart_send(0x20);
|
||||
}
|
||||
//------------------------------------------------------------------------
|
||||
void hexstring ( unsigned int d )
|
||||
{
|
||||
hexstrings(d);
|
||||
uart_send(0x0D);
|
||||
uart_send(0x0A);
|
||||
}
|
||||
//------------------------------------------------------------------------
|
||||
unsigned char xstring[256];
|
||||
//------------------------------------------------------------------------
|
||||
@@ -90,31 +44,10 @@ int notmain ( void )
|
||||
|
||||
unsigned int crc;
|
||||
|
||||
PUT32(AUX_ENABLES,1);
|
||||
PUT32(AUX_MU_IER_REG,0);
|
||||
PUT32(AUX_MU_CNTL_REG,0);
|
||||
PUT32(AUX_MU_LCR_REG,3);
|
||||
PUT32(AUX_MU_MCR_REG,0);
|
||||
PUT32(AUX_MU_IER_REG,0);
|
||||
PUT32(AUX_MU_IIR_REG,0xC6);
|
||||
PUT32(AUX_MU_BAUD_REG,270);
|
||||
ra=GET32(GPFSEL1);
|
||||
ra&=~(7<<12); //gpio14
|
||||
ra|=2<<12; //alt5
|
||||
ra&=~(7<<15); //gpio15
|
||||
ra|=2<<15; //alt5
|
||||
PUT32(GPFSEL1,ra);
|
||||
PUT32(GPPUD,0);
|
||||
for(ra=0;ra<150;ra++) dummy(ra);
|
||||
PUT32(GPPUDCLK0,(1<<14)|(1<<15));
|
||||
for(ra=0;ra<150;ra++) dummy(ra);
|
||||
PUT32(GPPUDCLK0,0);
|
||||
PUT32(AUX_MU_CNTL_REG,3);
|
||||
|
||||
PUT32(ARM_TIMER_CTL,0x00F90000);
|
||||
PUT32(ARM_TIMER_CTL,0x00F90200);
|
||||
|
||||
uart_init();
|
||||
hexstring(0x12345678);
|
||||
hexstring(GETPC());
|
||||
timer_init();
|
||||
|
||||
//SOH 0x01
|
||||
//ACK 0x06
|
||||
@@ -132,26 +65,27 @@ int notmain ( void )
|
||||
//a single EOT instead of SOH when done, send an ACK on it too
|
||||
|
||||
block=1;
|
||||
addr=0;
|
||||
addr=ARMBASE;
|
||||
state=0;
|
||||
rx=GET32(ARM_TIMER_CNT);
|
||||
crc=0;
|
||||
rx=timer_tick();
|
||||
while(1)
|
||||
{
|
||||
ra=GET32(ARM_TIMER_CNT);
|
||||
ra=timer_tick();
|
||||
if((ra-rx)>=4000000)
|
||||
{
|
||||
uart_send(0x15);
|
||||
rx+=4000000;
|
||||
}
|
||||
if((GET32(AUX_MU_LSR_REG)&0x01)==0) continue;
|
||||
xstring[state]=GET32(AUX_MU_IO_REG)&0xFF;
|
||||
rx=GET32(ARM_TIMER_CNT);
|
||||
if((uart_lcr()&0x01)==0) continue;
|
||||
xstring[state]=uart_recv();
|
||||
rx=timer_tick();
|
||||
if(state==0)
|
||||
{
|
||||
if(xstring[state]==0x04)
|
||||
{
|
||||
uart_send(0x06);
|
||||
BRANCHTO(0);
|
||||
BRANCHTO(ARMBASE);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Binary file not shown.
@@ -1,7 +1,7 @@
|
||||
|
||||
MEMORY
|
||||
{
|
||||
ram : ORIGIN = 0x00000000, LENGTH = 0x10000000
|
||||
ram : ORIGIN = 0x8000, LENGTH = 0x1000000
|
||||
}
|
||||
|
||||
SECTIONS
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
|
||||
MEMORY
|
||||
{
|
||||
ram : ORIGIN = 0x00000000, LENGTH = 0x200000
|
||||
ram : ORIGIN = 0x8000, LENGTH = 0x1000
|
||||
}
|
||||
|
||||
SECTIONS
|
||||
|
||||
124
bootloader03/periph.c
Normal file
124
bootloader03/periph.c
Normal file
@@ -0,0 +1,124 @@
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
//-------------------------------------------------------------------------
|
||||
|
||||
extern void PUT32 ( unsigned int, unsigned int );
|
||||
extern void PUT16 ( unsigned int, unsigned int );
|
||||
extern void PUT8 ( unsigned int, unsigned int );
|
||||
extern unsigned int GET32 ( unsigned int );
|
||||
extern void BRANCHTO ( unsigned int );
|
||||
extern void dummy ( unsigned int );
|
||||
|
||||
#define ARM_TIMER_CTL 0x2000B408
|
||||
#define ARM_TIMER_CNT 0x2000B420
|
||||
|
||||
#define GPFSEL1 0x20200004
|
||||
#define GPSET0 0x2020001C
|
||||
#define GPCLR0 0x20200028
|
||||
#define GPPUD 0x20200094
|
||||
#define GPPUDCLK0 0x20200098
|
||||
|
||||
#define AUX_ENABLES 0x20215004
|
||||
#define AUX_MU_IO_REG 0x20215040
|
||||
#define AUX_MU_IER_REG 0x20215044
|
||||
#define AUX_MU_IIR_REG 0x20215048
|
||||
#define AUX_MU_LCR_REG 0x2021504C
|
||||
#define AUX_MU_MCR_REG 0x20215050
|
||||
#define AUX_MU_LSR_REG 0x20215054
|
||||
#define AUX_MU_MSR_REG 0x20215058
|
||||
#define AUX_MU_SCRATCH 0x2021505C
|
||||
#define AUX_MU_CNTL_REG 0x20215060
|
||||
#define AUX_MU_STAT_REG 0x20215064
|
||||
#define AUX_MU_BAUD_REG 0x20215068
|
||||
|
||||
//GPIO14 TXD0 and TXD1
|
||||
//GPIO15 RXD0 and RXD1
|
||||
//------------------------------------------------------------------------
|
||||
unsigned int uart_lcr ( void )
|
||||
{
|
||||
return(GET32(AUX_MU_LSR_REG));
|
||||
}
|
||||
//------------------------------------------------------------------------
|
||||
unsigned int uart_recv ( void )
|
||||
{
|
||||
while(1)
|
||||
{
|
||||
if(GET32(AUX_MU_LSR_REG)&0x01) break;
|
||||
}
|
||||
return(GET32(AUX_MU_IO_REG)&0xFF);
|
||||
}
|
||||
//------------------------------------------------------------------------
|
||||
void uart_send ( unsigned int c )
|
||||
{
|
||||
while(1)
|
||||
{
|
||||
if(GET32(AUX_MU_LSR_REG)&0x20) break;
|
||||
}
|
||||
PUT32(AUX_MU_IO_REG,c);
|
||||
}
|
||||
//------------------------------------------------------------------------
|
||||
void hexstrings ( unsigned int d )
|
||||
{
|
||||
//unsigned int ra;
|
||||
unsigned int rb;
|
||||
unsigned int rc;
|
||||
|
||||
rb=32;
|
||||
while(1)
|
||||
{
|
||||
rb-=4;
|
||||
rc=(d>>rb)&0xF;
|
||||
if(rc>9) rc+=0x37; else rc+=0x30;
|
||||
uart_send(rc);
|
||||
if(rb==0) break;
|
||||
}
|
||||
uart_send(0x20);
|
||||
}
|
||||
//------------------------------------------------------------------------
|
||||
void hexstring ( unsigned int d )
|
||||
{
|
||||
hexstrings(d);
|
||||
uart_send(0x0D);
|
||||
uart_send(0x0A);
|
||||
}
|
||||
//------------------------------------------------------------------------
|
||||
void uart_init ( void )
|
||||
{
|
||||
unsigned int ra;
|
||||
|
||||
PUT32(AUX_ENABLES,1);
|
||||
PUT32(AUX_MU_IER_REG,0);
|
||||
PUT32(AUX_MU_CNTL_REG,0);
|
||||
PUT32(AUX_MU_LCR_REG,3);
|
||||
PUT32(AUX_MU_MCR_REG,0);
|
||||
PUT32(AUX_MU_IER_REG,0);
|
||||
PUT32(AUX_MU_IIR_REG,0xC6);
|
||||
PUT32(AUX_MU_BAUD_REG,270);
|
||||
ra=GET32(GPFSEL1);
|
||||
ra&=~(7<<12); //gpio14
|
||||
ra|=2<<12; //alt5
|
||||
ra&=~(7<<15); //gpio15
|
||||
ra|=2<<15; //alt5
|
||||
PUT32(GPFSEL1,ra);
|
||||
PUT32(GPPUD,0);
|
||||
for(ra=0;ra<150;ra++) dummy(ra);
|
||||
PUT32(GPPUDCLK0,(1<<14)|(1<<15));
|
||||
for(ra=0;ra<150;ra++) dummy(ra);
|
||||
PUT32(GPPUDCLK0,0);
|
||||
PUT32(AUX_MU_CNTL_REG,3);
|
||||
}
|
||||
//------------------------------------------------------------------------
|
||||
void timer_init ( void )
|
||||
{
|
||||
//0xF9+1 = 250
|
||||
//250MHz/250 = 1MHz
|
||||
PUT32(ARM_TIMER_CTL,0x00F90000);
|
||||
PUT32(ARM_TIMER_CTL,0x00F90200);
|
||||
}
|
||||
//-------------------------------------------------------------------------
|
||||
unsigned int timer_tick ( void )
|
||||
{
|
||||
return(GET32(ARM_TIMER_CNT));
|
||||
}
|
||||
//-------------------------------------------------------------------------
|
||||
//-------------------------------------------------------------------------
|
||||
@@ -1,6 +1,7 @@
|
||||
|
||||
.globl _start
|
||||
_start:
|
||||
mov sp,#0x8000
|
||||
bl notmain
|
||||
hang: b hang
|
||||
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
|
||||
.globl _start
|
||||
_start:
|
||||
b reset
|
||||
b skip
|
||||
|
||||
.space 0x200000-4,0
|
||||
.space 0x200000-0x8004,0
|
||||
|
||||
reset:
|
||||
mov sp,#0x10000000
|
||||
skip:
|
||||
mov sp,#0x08000000
|
||||
bl notmain
|
||||
hang: b hang
|
||||
|
||||
@@ -30,6 +30,11 @@ GET32:
|
||||
ldr r0,[r0]
|
||||
bx lr
|
||||
|
||||
.globl GETPC
|
||||
GETPC:
|
||||
mov r0,lr
|
||||
bx lr
|
||||
|
||||
.globl BRANCHTO
|
||||
BRANCHTO:
|
||||
bx r0
|
||||
|
||||
83
bootloader04/Makefile
Normal file
83
bootloader04/Makefile
Normal file
@@ -0,0 +1,83 @@
|
||||
|
||||
ARMGNU ?= arm-none-eabi
|
||||
|
||||
COPS = -Wall -O2 -nostdlib -nostartfiles -ffreestanding
|
||||
|
||||
gcc : kernel.img blinker.bin
|
||||
|
||||
all : gcc clang
|
||||
|
||||
clean :
|
||||
rm -f *.o
|
||||
rm -f *.bin
|
||||
rm -f *.hex
|
||||
rm -f *.elf
|
||||
rm -f *.list
|
||||
rm -f *.img
|
||||
rm -f *.bc
|
||||
rm -f *.clang.s
|
||||
|
||||
|
||||
vectors.o : vectors.s
|
||||
$(ARMGNU)-as vectors.s -o vectors.o
|
||||
|
||||
bootloader04.o : bootloader04.c
|
||||
$(ARMGNU)-gcc $(COPS) -c bootloader04.c -o bootloader04.o
|
||||
|
||||
periph.o : periph.c
|
||||
$(ARMGNU)-gcc $(COPS) -c periph.c -o periph.o
|
||||
|
||||
kernel.img : loader vectors.o periph.o bootloader04.o
|
||||
$(ARMGNU)-ld vectors.o periph.o bootloader04.o -T loader -o bootloader04.elf
|
||||
$(ARMGNU)-objdump -D bootloader04.elf > bootloader04.list
|
||||
$(ARMGNU)-objcopy bootloader04.elf -O ihex bootloader04.hex
|
||||
$(ARMGNU)-objcopy bootloader04.elf -O binary kernel.img
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
start.o : start.s
|
||||
$(ARMGNU)-as start.s -o start.o
|
||||
|
||||
blinker.o : blinker.c
|
||||
$(ARMGNU)-gcc $(COPS) -c blinker.c -o blinker.o
|
||||
|
||||
blinker.bin : memmap start.o blinker.o
|
||||
$(ARMGNU)-ld start.o blinker.o -T memmap -o blinker.elf
|
||||
$(ARMGNU)-objdump -D blinker.elf > blinker.list
|
||||
$(ARMGNU)-objcopy blinker.elf -O ihex blinker.hex
|
||||
$(ARMGNU)-objcopy blinker.elf -O binary blinker.bin
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
LOPS = -Wall -m32 -emit-llvm
|
||||
LLCOPS0 = -march=arm
|
||||
LLCOPS1 = -march=arm -mcpu=arm1176jzf-s
|
||||
LLCOPS = $(LLCOPS1)
|
||||
COPS = -Wall -O2 -nostdlib -nostartfiles -ffreestanding
|
||||
OOPS = -std-compile-opts
|
||||
|
||||
clang : bootloader04.bin
|
||||
|
||||
bootloader04.bc : bootloader04.c
|
||||
clang $(LOPS) -c bootloader04.c -o bootloader04.bc
|
||||
|
||||
periph.bc : periph.c
|
||||
clang $(LOPS) -c periph.c -o periph.bc
|
||||
|
||||
bootloader04.clang.elf : loader vectors.o bootloader04.bc periph.bc
|
||||
llvm-link periph.bc bootloader04.bc -o bootloader04.nopt.bc
|
||||
opt $(OOPS) bootloader04.nopt.bc -o bootloader04.opt.bc
|
||||
llc $(LLCOPS) bootloader04.opt.bc -o bootloader04.clang.s
|
||||
$(ARMGNU)-as bootloader04.clang.s -o bootloader04.clang.o
|
||||
$(ARMGNU)-ld -o bootloader04.clang.elf -T loader vectors.o bootloader04.clang.o
|
||||
$(ARMGNU)-objdump -D bootloader04.clang.elf > bootloader04.clang.list
|
||||
|
||||
bootloader04.bin : bootloader04.clang.elf
|
||||
$(ARMGNU)-objcopy bootloader04.clang.elf bootloader04.clang.bin -O binary
|
||||
|
||||
|
||||
9
bootloader04/README
Normal file
9
bootloader04/README
Normal file
@@ -0,0 +1,9 @@
|
||||
|
||||
Same as bootloader03, except it uses the config.txt file to load to
|
||||
0x06000000 leaving much more room (than you would probably want to
|
||||
use xmodem to load) for development.
|
||||
|
||||
Copy both kernel.img and config.txt to the sd card. Remove or modify
|
||||
config.txt when you change to some other kernel.img. The main drawback
|
||||
to this version is remembering to copy and then remove/replace both
|
||||
files.
|
||||
57
bootloader04/blinker.c
Normal file
57
bootloader04/blinker.c
Normal file
@@ -0,0 +1,57 @@
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
//-------------------------------------------------------------------------
|
||||
|
||||
extern void PUT32 ( unsigned int, unsigned int );
|
||||
extern unsigned int GET32 ( unsigned int );
|
||||
extern void dummy ( unsigned int );
|
||||
|
||||
#define ARM_TIMER_LOD 0x2000B400
|
||||
#define ARM_TIMER_VAL 0x2000B404
|
||||
#define ARM_TIMER_CTL 0x2000B408
|
||||
#define ARM_TIMER_DIV 0x2000B41C
|
||||
#define ARM_TIMER_CNT 0x2000B420
|
||||
|
||||
#define SYSTIMERCLO 0x20003004
|
||||
#define GPFSEL1 0x20200004
|
||||
#define GPSET0 0x2020001C
|
||||
#define GPCLR0 0x20200028
|
||||
|
||||
#define TIMEOUT 1000000
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
int notmain ( void )
|
||||
{
|
||||
unsigned int ra;
|
||||
unsigned int rb;
|
||||
|
||||
ra=GET32(GPFSEL1);
|
||||
ra&=~(7<<18);
|
||||
ra|=1<<18;
|
||||
PUT32(GPFSEL1,ra);
|
||||
|
||||
PUT32(ARM_TIMER_CTL,0x00F90000);
|
||||
PUT32(ARM_TIMER_CTL,0x00F90200);
|
||||
|
||||
rb=GET32(ARM_TIMER_CNT);
|
||||
while(1)
|
||||
{
|
||||
PUT32(GPSET0,1<<16);
|
||||
while(1)
|
||||
{
|
||||
ra=GET32(ARM_TIMER_CNT);
|
||||
if((ra-rb)>=TIMEOUT) break;
|
||||
}
|
||||
rb+=TIMEOUT;
|
||||
PUT32(GPCLR0,1<<16);
|
||||
while(1)
|
||||
{
|
||||
ra=GET32(ARM_TIMER_CNT);
|
||||
if((ra-rb)>=TIMEOUT) break;
|
||||
}
|
||||
rb+=TIMEOUT;
|
||||
}
|
||||
return(0);
|
||||
}
|
||||
//-------------------------------------------------------------------------
|
||||
//-------------------------------------------------------------------------
|
||||
166
bootloader04/bootloader04.c
Normal file
166
bootloader04/bootloader04.c
Normal file
@@ -0,0 +1,166 @@
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
//-------------------------------------------------------------------------
|
||||
|
||||
//The raspberry pi wants you to not have your kernel.img file loaded
|
||||
//at address 0x0000. Using a bootloader like this it works just fine
|
||||
//but to avoid having example binaries that are at 0x8000 for running
|
||||
//from the sd card and a binary at 0x0000 for loading with the
|
||||
//bootloader, instead the bootloader is going to default to 0x8000
|
||||
//as well.
|
||||
#define ARMBASE 0x8000
|
||||
|
||||
extern void PUT32 ( unsigned int, unsigned int );
|
||||
extern void PUT16 ( unsigned int, unsigned int );
|
||||
extern void PUT8 ( unsigned int, unsigned int );
|
||||
extern unsigned int GET32 ( unsigned int );
|
||||
extern unsigned int GETPC ( void );
|
||||
extern void BRANCHTO ( unsigned int );
|
||||
extern void dummy ( unsigned int );
|
||||
|
||||
extern void uart_init ( void );
|
||||
extern unsigned int uart_lcr ( void );
|
||||
extern void uart_send ( unsigned int );
|
||||
extern unsigned int uart_recv ( void );
|
||||
extern void hexstring ( unsigned int );
|
||||
extern void hexstrings ( unsigned int );
|
||||
extern void timer_init ( void );
|
||||
extern unsigned int timer_tick ( void );
|
||||
|
||||
extern void timer_init ( void );
|
||||
extern unsigned int timer_tick ( void );
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
unsigned char xstring[256];
|
||||
//------------------------------------------------------------------------
|
||||
int notmain ( void )
|
||||
{
|
||||
unsigned int ra;
|
||||
//unsigned int rb;
|
||||
unsigned int rx;
|
||||
unsigned int addr;
|
||||
unsigned int block;
|
||||
unsigned int state;
|
||||
|
||||
unsigned int crc;
|
||||
|
||||
uart_init();
|
||||
hexstring(0x12345678);
|
||||
hexstring(GETPC());
|
||||
timer_init();
|
||||
|
||||
//SOH 0x01
|
||||
//ACK 0x06
|
||||
//NAK 0x15
|
||||
//EOT 0x04
|
||||
|
||||
//block numbers start with 1
|
||||
|
||||
//132 byte packet
|
||||
//starts with SOH
|
||||
//block number byte
|
||||
//255-block number
|
||||
//128 bytes of data
|
||||
//checksum byte (whole packet)
|
||||
//a single EOT instead of SOH when done, send an ACK on it too
|
||||
|
||||
block=1;
|
||||
addr=ARMBASE;
|
||||
state=0;
|
||||
crc=0;
|
||||
rx=timer_tick();
|
||||
while(1)
|
||||
{
|
||||
ra=timer_tick();
|
||||
if((ra-rx)>=4000000)
|
||||
{
|
||||
uart_send(0x15);
|
||||
rx+=4000000;
|
||||
}
|
||||
if((uart_lcr()&0x01)==0) continue;
|
||||
xstring[state]=uart_recv();
|
||||
rx=timer_tick();
|
||||
if(state==0)
|
||||
{
|
||||
if(xstring[state]==0x04)
|
||||
{
|
||||
uart_send(0x06);
|
||||
BRANCHTO(ARMBASE);
|
||||
break;
|
||||
}
|
||||
}
|
||||
switch(state)
|
||||
{
|
||||
case 0:
|
||||
{
|
||||
if(xstring[state]==0x01)
|
||||
{
|
||||
crc=xstring[state];
|
||||
state++;
|
||||
}
|
||||
else
|
||||
{
|
||||
//state=0;
|
||||
uart_send(0x15);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 1:
|
||||
{
|
||||
if(xstring[state]==block)
|
||||
{
|
||||
crc+=xstring[state];
|
||||
state++;
|
||||
}
|
||||
else
|
||||
{
|
||||
state=0;
|
||||
uart_send(0x15);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 2:
|
||||
{
|
||||
if(xstring[state]==(0xFF-xstring[state-1]))
|
||||
{
|
||||
crc+=xstring[state];
|
||||
state++;
|
||||
}
|
||||
else
|
||||
{
|
||||
uart_send(0x15);
|
||||
state=0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 131:
|
||||
{
|
||||
crc&=0xFF;
|
||||
if(xstring[state]==crc)
|
||||
{
|
||||
for(ra=0;ra<128;ra++)
|
||||
{
|
||||
PUT8(addr++,xstring[ra+3]);
|
||||
}
|
||||
uart_send(0x06);
|
||||
block=(block+1)&0xFF;
|
||||
}
|
||||
else
|
||||
{
|
||||
uart_send(0x15);
|
||||
}
|
||||
state=0;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
crc+=xstring[state];
|
||||
state++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return(0);
|
||||
}
|
||||
//-------------------------------------------------------------------------
|
||||
//-------------------------------------------------------------------------
|
||||
1
bootloader04/config.txt
Normal file
1
bootloader04/config.txt
Normal file
@@ -0,0 +1 @@
|
||||
kernel_address=0x06000000
|
||||
BIN
bootloader04/kernel.img
Executable file
BIN
bootloader04/kernel.img
Executable file
Binary file not shown.
12
bootloader04/loader
Normal file
12
bootloader04/loader
Normal file
@@ -0,0 +1,12 @@
|
||||
|
||||
MEMORY
|
||||
{
|
||||
ram : ORIGIN = 0x06000000, LENGTH = 0x2000
|
||||
}
|
||||
|
||||
SECTIONS
|
||||
{
|
||||
.text : { *(.text*) } > ram
|
||||
.bss : { *(.bss*) } > ram
|
||||
}
|
||||
|
||||
12
bootloader04/memmap
Normal file
12
bootloader04/memmap
Normal file
@@ -0,0 +1,12 @@
|
||||
|
||||
MEMORY
|
||||
{
|
||||
ram : ORIGIN = 0x8000, LENGTH = 0x1000
|
||||
}
|
||||
|
||||
SECTIONS
|
||||
{
|
||||
.text : { *(.text*) } > ram
|
||||
.bss : { *(.bss*) } > ram
|
||||
}
|
||||
|
||||
124
bootloader04/periph.c
Normal file
124
bootloader04/periph.c
Normal file
@@ -0,0 +1,124 @@
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
//-------------------------------------------------------------------------
|
||||
|
||||
extern void PUT32 ( unsigned int, unsigned int );
|
||||
extern void PUT16 ( unsigned int, unsigned int );
|
||||
extern void PUT8 ( unsigned int, unsigned int );
|
||||
extern unsigned int GET32 ( unsigned int );
|
||||
extern void BRANCHTO ( unsigned int );
|
||||
extern void dummy ( unsigned int );
|
||||
|
||||
#define ARM_TIMER_CTL 0x2000B408
|
||||
#define ARM_TIMER_CNT 0x2000B420
|
||||
|
||||
#define GPFSEL1 0x20200004
|
||||
#define GPSET0 0x2020001C
|
||||
#define GPCLR0 0x20200028
|
||||
#define GPPUD 0x20200094
|
||||
#define GPPUDCLK0 0x20200098
|
||||
|
||||
#define AUX_ENABLES 0x20215004
|
||||
#define AUX_MU_IO_REG 0x20215040
|
||||
#define AUX_MU_IER_REG 0x20215044
|
||||
#define AUX_MU_IIR_REG 0x20215048
|
||||
#define AUX_MU_LCR_REG 0x2021504C
|
||||
#define AUX_MU_MCR_REG 0x20215050
|
||||
#define AUX_MU_LSR_REG 0x20215054
|
||||
#define AUX_MU_MSR_REG 0x20215058
|
||||
#define AUX_MU_SCRATCH 0x2021505C
|
||||
#define AUX_MU_CNTL_REG 0x20215060
|
||||
#define AUX_MU_STAT_REG 0x20215064
|
||||
#define AUX_MU_BAUD_REG 0x20215068
|
||||
|
||||
//GPIO14 TXD0 and TXD1
|
||||
//GPIO15 RXD0 and RXD1
|
||||
//------------------------------------------------------------------------
|
||||
unsigned int uart_lcr ( void )
|
||||
{
|
||||
return(GET32(AUX_MU_LSR_REG));
|
||||
}
|
||||
//------------------------------------------------------------------------
|
||||
unsigned int uart_recv ( void )
|
||||
{
|
||||
while(1)
|
||||
{
|
||||
if(GET32(AUX_MU_LSR_REG)&0x01) break;
|
||||
}
|
||||
return(GET32(AUX_MU_IO_REG)&0xFF);
|
||||
}
|
||||
//------------------------------------------------------------------------
|
||||
void uart_send ( unsigned int c )
|
||||
{
|
||||
while(1)
|
||||
{
|
||||
if(GET32(AUX_MU_LSR_REG)&0x20) break;
|
||||
}
|
||||
PUT32(AUX_MU_IO_REG,c);
|
||||
}
|
||||
//------------------------------------------------------------------------
|
||||
void hexstrings ( unsigned int d )
|
||||
{
|
||||
//unsigned int ra;
|
||||
unsigned int rb;
|
||||
unsigned int rc;
|
||||
|
||||
rb=32;
|
||||
while(1)
|
||||
{
|
||||
rb-=4;
|
||||
rc=(d>>rb)&0xF;
|
||||
if(rc>9) rc+=0x37; else rc+=0x30;
|
||||
uart_send(rc);
|
||||
if(rb==0) break;
|
||||
}
|
||||
uart_send(0x20);
|
||||
}
|
||||
//------------------------------------------------------------------------
|
||||
void hexstring ( unsigned int d )
|
||||
{
|
||||
hexstrings(d);
|
||||
uart_send(0x0D);
|
||||
uart_send(0x0A);
|
||||
}
|
||||
//------------------------------------------------------------------------
|
||||
void uart_init ( void )
|
||||
{
|
||||
unsigned int ra;
|
||||
|
||||
PUT32(AUX_ENABLES,1);
|
||||
PUT32(AUX_MU_IER_REG,0);
|
||||
PUT32(AUX_MU_CNTL_REG,0);
|
||||
PUT32(AUX_MU_LCR_REG,3);
|
||||
PUT32(AUX_MU_MCR_REG,0);
|
||||
PUT32(AUX_MU_IER_REG,0);
|
||||
PUT32(AUX_MU_IIR_REG,0xC6);
|
||||
PUT32(AUX_MU_BAUD_REG,270);
|
||||
ra=GET32(GPFSEL1);
|
||||
ra&=~(7<<12); //gpio14
|
||||
ra|=2<<12; //alt5
|
||||
ra&=~(7<<15); //gpio15
|
||||
ra|=2<<15; //alt5
|
||||
PUT32(GPFSEL1,ra);
|
||||
PUT32(GPPUD,0);
|
||||
for(ra=0;ra<150;ra++) dummy(ra);
|
||||
PUT32(GPPUDCLK0,(1<<14)|(1<<15));
|
||||
for(ra=0;ra<150;ra++) dummy(ra);
|
||||
PUT32(GPPUDCLK0,0);
|
||||
PUT32(AUX_MU_CNTL_REG,3);
|
||||
}
|
||||
//------------------------------------------------------------------------
|
||||
void timer_init ( void )
|
||||
{
|
||||
//0xF9+1 = 250
|
||||
//250MHz/250 = 1MHz
|
||||
PUT32(ARM_TIMER_CTL,0x00F90000);
|
||||
PUT32(ARM_TIMER_CTL,0x00F90200);
|
||||
}
|
||||
//-------------------------------------------------------------------------
|
||||
unsigned int timer_tick ( void )
|
||||
{
|
||||
return(GET32(ARM_TIMER_CNT));
|
||||
}
|
||||
//-------------------------------------------------------------------------
|
||||
//-------------------------------------------------------------------------
|
||||
20
bootloader04/start.s
Normal file
20
bootloader04/start.s
Normal file
@@ -0,0 +1,20 @@
|
||||
|
||||
.globl _start
|
||||
_start:
|
||||
mov sp,#0x8000
|
||||
bl notmain
|
||||
hang: b hang
|
||||
|
||||
.globl PUT32
|
||||
PUT32:
|
||||
str r1,[r0]
|
||||
bx lr
|
||||
|
||||
.globl GET32
|
||||
GET32:
|
||||
ldr r0,[r0]
|
||||
bx lr
|
||||
|
||||
.globl dummy
|
||||
dummy:
|
||||
bx lr
|
||||
40
bootloader04/vectors.s
Normal file
40
bootloader04/vectors.s
Normal file
@@ -0,0 +1,40 @@
|
||||
|
||||
.globl _start
|
||||
_start:
|
||||
mov sp,#0x08000000
|
||||
bl notmain
|
||||
hang: b hang
|
||||
|
||||
.globl PUT32
|
||||
PUT32:
|
||||
str r1,[r0]
|
||||
bx lr
|
||||
|
||||
.globl PUT16
|
||||
PUT16:
|
||||
strh r1,[r0]
|
||||
bx lr
|
||||
|
||||
.globl PUT8
|
||||
PUT8:
|
||||
strb r1,[r0]
|
||||
bx lr
|
||||
|
||||
.globl GET32
|
||||
GET32:
|
||||
ldr r0,[r0]
|
||||
bx lr
|
||||
|
||||
.globl GETPC
|
||||
GETPC:
|
||||
mov r0,lr
|
||||
bx lr
|
||||
|
||||
.globl BRANCHTO
|
||||
BRANCHTO:
|
||||
bx r0
|
||||
|
||||
.globl dummy
|
||||
dummy:
|
||||
bx lr
|
||||
|
||||
Reference in New Issue
Block a user