从图书馆随便借的(实际bootloader只有就这一本
也不过就是给txt打了个tag(x
bootloader TP368.1/742
PC boot seqense:
BIOS -> MBR -> GRUB -> Linux -> User
uefi sequense:
(?
vim:
#[TODO] vimtutor
plugin:
ctags
taglist
cscope
gcc:
man gcc
gcc:
-x language
-c -S -E -o
-ffreestanding -fno-builtin > build bootloader
-Wall
-g -p -pg
ld:
-nostdinc
-nostdlib -nodefaultlibs -nostartfiles
-share
-T script
Linux command:
man find
man grep
-e externed regexp
-i –ignore-case
-v reverse
-x full line
-m num
-D action (special/device file)
-d action (folder)
-r recursive
Regexp:
nothing new
pipe line, redirect:
stdout : 0
stdin : 1
stderr : 2
> redirect stdout to file
< redirect stdin from file
>> append stdout to file
>| force >
n>| force file as descriptor n
<> use file as stdin and stdout
n>file
n<file
n>>file
n>& copy stdout to file n
n<& copy n to stdin
n>&m n used as copy of outstream m
n<&m n used as copy of instream m
&>file stdout, stderr to file
<&- close stdin
>&- close stdout
n>&- close n output
n<&- close n input
Makefile:
recursive make (?
phony
functions:
$(..) return
subst from, to, text replace all ’from’ to ’to’ in text
patsubst %.xml, %.dvi, text replace all ’.xml’ to ’.dvi’
strip strint drop head and tail spaces, merge multiply space character to one space character
findstring find, in find.indexOf(in)==-1?find[find.indexOf(in),find.indexOf(in)+in.length]:none
filter pattern…, text all strings match
filter-out reverse use of filter
sort list sort by first character and exclude same word
word N, Text Text[n-1]
wordlist s, e, text text[s,e]
words text len(text)
firstword text text[0]
dir names names.map(item=>Path(item).dir())
notdir names names.map(item=>Path(item).name())
suffix names names.map(item=>item.slice(item.lastIndexOf(‘.’)))
basename names names.map(item=>Path(item.slice(0, item.lastIndexOf(‘.’)).name()))
addsuffix suffix, names names.map(item=>${item}suffix
)
addprefix prefix, names names.map(item=>prefix${item}
)
join list1, list2 [list1[i]+list2[i] for i in range(min(len(list1), len(list2)))]
wildcard pattern find . | grep pattern
arm:
mode:
user: 0b10000 normal
fiq: 0b10001 fast data copy, interrupt
irq: 0b10010 interrupt
supervisor: 0b10011 system protection
abort: 0b10111 virtual storage or protection
undefined: 0b11011 hardware cp simulation
system: 0b11111 operating system task
error:
fiq, irq, svc, abt, und
exception table:
rst: 0x0 system reset
und: 0x4 undefined instruction
svc: 0x8 software interrupt
abt: 0xc code get error
abt: 0x10 data get error
rev: 0x14
irq: 0x18 interrupt
fiq: 0x1c fast interrupt
register:
37 registers.
user mode, system mode common register R1 R7, R8 R12, R13 ~ R14
svc, abt, und, irq mode special register R13_*, R14_*, SPSR_*
fiq mode special register R8_fiq ~ R14_fiq, SPSR_fiq
all mode common pc, cpsr
r0~r7: common usage.
r13: sp
r14: lr
r15: pc
cpsr:
N Z C V Q R R J R R R G E G E R R R R R R E A I F T M M M M
user access:
NZCV: condition flags
N: negative
Z: zero
C: carry
V: signed carry
Q: (?
GE: (?
E: (?
privilged access:
A: EAll
I: EIrq
F: EFiq
M: -> mode
J T: instruction set. 8bit / 16bit.
arm instruction set:
format: instruction
shifter:
LSL: <<
LSR: >>
ASR
ROR
RRX
mov rd, N
mvn rd, N
rd = ()N :mvn
mov r0, r1, LSL #9
mov r0, #0
Immediate bigger than 256u and can’t shift by number within 256 need use ”ldr” instruction
ADC Rd, Rn, N Rd = Rn + N + carry
ADD Rd, Rn, N Rd = Rn + N
RSB Rd, Rn, N Rd = N - Rn
RSC Rd, Rn, N Rd = N - Rn - !carry
SBC Rd, Rn, N Rd = Rn - N - !carry
SUB Rd, Rn, N Rd = Rn - N
N can be 8bit imm or Rm
AND Rd, Rn, N Rd = Rn & N
ORR Rd, Rn, N Rd = Rn | N
EOR Rd, Rn, N Rd = Rn ^ n
BIC Rd, Rn, N Rd = Rn &~ N
N can be 8bit imm or Rm
CMN Rd, N Rd + N -> NZCV
CMP Rd, N Rd - N -> NZCV
TEQ Rd, N Rd ^ N -> NZCV
TST Rd, N Rn & N -> NZCV
MLA Rd, Rm, Rs, Rn Rd = (Rm * Rs) + Rn
MUL Rd, Rm, Rs Rd = Rm * Rs
SMLAL RdLo, RdHi, Rm, Rs
SMULL RdLo, RdHi, Rm, Rs
UMLAL RdLo, RdHi, Rm, Rs
UMULL RdLo, RdHi, Rm, Rs
B label PC = label
BL label PC = label, lr = PC + 8
BX Rm PC = Rm & ~1, T = Rm & 1
BLX Rm
SWI num
MRS Rd, CPSR|SPSR Rd = .
MSR CPSR|SPSR_*, Rd . = Rd
MSR CPSR|SPSR_*, #imm . = imm
!cp register: what the fuck?
cdp cp, opcode1, Cd, Cn, {, opcode2}
mrc|mcr cp, opcode1, Rd, Cn, Cm {, opcode2}
ldc|stc cp, Cd, addressing
fake ins:
ldr Rd, =imm Rd = imm
adr Rd, label Rd = &label
addressing:
> ldr|str{cond}{B}{T}
# instruction struct:
cond 0 1 S P U B W L Rn Rd data
cond: condition
S: shift
P: update register sequense
U: direction
B: byte
W: write to register
L: load ~L: store
[M, shifter N] [M shifter N]
8bit imm + 4bit shift
register + 4bit shift
register + register shift
! if R15(PC) as the register number the value is current position + 8
! use shifter will change cpsr
[Rn, +/- N] [Rn +/- N]
12bit imm offset
register
# to access byte array membey by index
[Rn, +/- Rm, shifter N] [Rn] +/- (Rm shifter N)
4bit imm
[Rn, +/- N]! Rn {=} [Rn +/- N]
12bit imm offset
register
! condition must passed before update Rn
! do NOT use R15(PC) as Rn
[Rn, +/- Rm, shifter N]! Rn {=} [Rn +/- (Rm shifter N)]
4bit imm
# auto update Rn before accessing array member
[Rn], +/- N [Rn] {=} Rn +/- N
12bit imm offset
register
# auto update Rn after accessing array member
[Rn], +/- Rm, shifter N [Rn] {=} Rn +/- (Rm shifter N)
4bit imm
> ldr|str{cond}H|SH|SB|D Rd, addressing
# instruction struct:
cond 0 0 0 P U 1 W L Rn Rd data
cond: condition
P: register update sequense
! P = 0 while update register even if W = 0
U: direction
W: write to register
! while P = 0, W must = 0. P = 0, W = 1 is not allowed
L, S, H:
L=0, S=0, H=1 str dbyte
L=0, S=1, H=0 ldr dword
L=0, S=1, H=1 str dword
L=1, S=0, H=1 ldr unsigned dbtye
L=1, S=1, H=0 ldr signed byte
L=1, S=1, H=1 ldr signed dbyte
! S=0, H=0 represent an unsigned byte operation, this operation will not use this addressing, using previous adressing instead. instruction ldrb, ldrbt, strb, strbt will cause this happend
! S=1, L=0 represent a signed byte str operation. H=0 ldrd, H=1 strd
[Rn, +/- N] [Rn +/- N]
8bit offset imm
! [Rn] represent [Rn, #0]
# to access member of a struct
# to access vars in stack
# to access data addressed by Rn
register
# access array member
[Rn, +/- N]! Rn {=} [Rn +/- N]
8bit offset imm
! [Rn, #0]! is not allowed
# auto update Rn after access array member using Rn +/- N if condition passed
register
[Rn], +/- N
8bit offset imm
# auto update Rn after access array member using Rn if condition passed
register
!! no scaled operation
> ldm|stm{cond}IA|IB|DA|DB Rn{!}, registers{^}
IA: increase after
IB: increase before
DA: decrease after
DB: decrease before
# instruction struct:
cond 1 0 0 P U S W L Rn registers
cond: condition
P: Rn is in the inbound/outbound
U: direction
S: if load pc/r15 with ldms this bit represent copy spsr to cpsr, else in the privilged mode this bit represent to load/store registers in the common mode
W: write to register
L: load ~L: store
registers: 16bit, each bit represent a register.
! registers = 0x00 is not allowed.
# registers are covered by ’{}’. : {r0, r1, pc, sp}
> mcr|mrc|ldc|stc{cond}(L) cp, CRd, addressing
! mcr, mrc is not fully explained in this book.
# instruction struct
cond 1 1 0 P U N W L Rn CRd cp_num offset_8
P: addressing mode + W
U: direction
N: size of byte
W: write to register
L: load ~L: store
[Rn, #+/-offset_8*4]
# size of bytes to transfer is controlled by co-operator
# maxium 16 words is transfered
[Rn, $+/-offset_8*4]!
[Rn], #+/-offset_8*4
[Rn], option
ld:
GNU Tools:
ar, strings, strip, nm, size, readelf
elf:
relocatable, executable, shared object
struction:
elf.h
elf header:
elf32_ehdr http://www.openvirtualization.org/documentation/structElf32__Ehdr.html
! elf_type
elf section header table:
elf32_Shdr http://www.openvirtualization.org/documentation/structElf32__Shdr.html
! sh_type
progbits: program, data, debug info
nobits: .bss
strtab,dynsym: symbol
rel, rela: relocation data
dynamic, hash:
! sh_flags:
alloc: alloc memory during load
write: writable after load
execinstr: executable code
# segments:
.text: program
.data: global variables with initial value
.rodata: readonly variables
.bss: global variables without initial value
.rel.text: relocation data
.rel.data
.rel.rodata
.init: > C++
.fini > C++
.symtab
.dynsym
.strtab: symbol table name
.dynsym
.got: global offset table
.plt: progress link table
.debug
.line
.comment
…
symbol table struction:
elf32_sym http://www.openvirtualization.org/documentation/structElf32__Sym.html
stroage allocation:
merge same section using relocation table
relocation table:
struct elf32_rel
elf32_addr r_offset
elf32_word r_info
struct elf32_rela
elf32_sword r_addend
! r_info: relocation type and symbol offset
! r_addend: align
link:
symbol analysis:
strong symbol can’t redefined
! strong symbol: function, initilized global variables
strong symbol will refefine weak symbol
multiply weak symbol will use biggest symbol
relocation:
relocation table can get the symbol offset address
ld scripts:
section
memory
. position counter
!
ENTRY(symbol)
INCLUDE
OUTPUT_FORMAT(elf32-bigmips, elf32-bigmips, elf32-littlemips)
default -EB -EL
REGION_ALIAS(alias, region)
~ INCLUDE linkcmds.memory
~ sections{
~ .text:{
~ *(.text)
~ }> REGION_TEXT
~ …
~ }
`
~ MEMORY{
~ RAM: ORIGIN=0, LENGTH=4M
~ …
~ }
~ REGION_ALIAS(“REGION_TEXT”, RAM)
~ …
ASSERT(exp, message)
if(!exp){print(message)}
EXTERN(symbol symbol …):
make symbol undefined
NOCROSSREFS(section1 section2 …)
function in section1 can’t call function in section2
symbol:
operator:
=: declare, transfer
~ etext = .
! etext can be used in code, with uninitilized global var etext.
! . can only used on section command
+=
-=
*=
/=
<<=
>>=
&=
|=
HIDDEN(symbol):
~ HIDDEN(etext = .)
! can NOT accessed in other program(not exported)
PROVIDE(symbol):
~ PROVIDE(etext = .)
# if symbol not defined will defined etext with ., otherwise use original definition
PROVIDE_HIDDEN(symbol)
sections:
~ sections{
~ sections-command
~ sections-command
~ …
~ }
sections-command:
entry
symbol
output section:
section [address] [(type)]:
[AT(lma)] [ALIGIN(section_aligin)] [SUBALIGIN(subsection_aligin)]
[constraint] { output-section-command} [>region] [AT>lma_origin] [:phdr :phdr] [=fillexp]
VMA: Virtual Memory Address
LMA: Load Memory Address
! LMA can be defined by AT or AT> command
~ .text (.) :{ *(.text) }
section without address can’t be predicted
~ *(EXCLUDE_FILE(*www.o) .ctors)
~ (.text .rodata) vs (.text) *(.rodata)
second description text and rodata will be separated
SORT_BY_NAME SORT_BY_ALIGINMENT
KEEP(sections)
COMMON
# common symbol?
FILL(value)
CREATE_OBJECT_SYMBOLS
/DISCARD/: length is zero
type:
NOLOAD: will not load into memory
DSECT: will not alloc memory during load
COPY
INFO
OVERLAY
OVERLAY:
will override previous definition in SECTIONS, same as SECTIONS
MEMORY:
~ MEMORY{
~ name [(attr)]: ORIGIN = origin, LENGTH = len
~ }
attr:
R W X A I L !
R: read only
W: write & read
X: executable
A: allocable
I: already initilized
L: = I
!: NOT
separated section:
ld will guess where these section will be put
. = .:
special usage. ld think you have saved .
functions:
ABSOLUTE(exp)
ADDR(section)
ALIGIN(aligin)
ALIGIN(exp, aligin)
ALIGINOF(section)
DATA_SEGMENT_ALIGIN(maxpagesize, commonpagesize)
DEFINED(symbol)
LEGNTH(memory)
LOADADDR(section): LMA
MAX(exp1, exp2)
MIN(exp1, exp2)
NEXT(exp) : nearest not alloc address can be divided by exp
ORIGIN(exp) : start address
SEGMENT_START(segment, default)
SIZEOF(section)
SIZEOF_HEADERS
Linux
GNU ASM:
fake instruction / command:
.ascii
.asciz
.baligin
.byte
.hword
.word
.code
.else .if .endif .ifdef .ifndef
.end EOF
.macro name {arg1, arg2, …}
.endm macro end
.rept
.endr loop end
.equ symbol, value #define symbol value
.err error
.exitm exit macro
.global symbol make symbol global
.include ”
.section
.set ,
.space
@ # ; #$
addr, %rn, [%rn], [%rn, #n], #imm
led: write register. such as mcu.
u-boot:
arch/arm/armv7/start.S
! now arch/arm/lib/vector.S
[todo] boot sequense is IMPORTANT.
! something OUT-OF-DATE!
! anlysis boot sequense using gnu elftools
! anlysis boot sequense using symbol and arm instrution
CP15 have NO explanation in this book.
# maybe armv8 user guide?
Bootloader:
IAP
# [TODO] Try write it on STM32?
# why not build IAP using FreeRTOS?
boot linux:
bootloader should do these things before booting linux:
initilize RAM:
load kernel to RAM to run
! not SRAM, kernel Image is too big to run in SRAM
initilize at least one UART port:
just for debug
detect CPU Type
put machine type in R1.
linux/arch/arm/tools/mach-types
establish kernel tag list:
tag list:
ATAG_CORE
ATAG_MEM
ATAG_NONE
dtb:
64bit aligin(????) put in ram
? I have tried not put in 64bit aligin using bootz, but also successed
magic number: 0xd00dfeed
documention/devicetree/booting-with-out-of.txt
call kernel image
put zImage on RAM and execute
bootloader must disable all DMA devices (?)
(?) just use dma to load zImage data into RAM. but why can’t?
r0 = 0
r1 = mach-types
r2 = taglist or dtb address
CPU must in SVC mode and disable irq and fiq.
Cache and MMU must disabled. Code cache is optional to close.
Cortex-A must set ARM instruction mode .code 32 / .ARM
Cortex-M must set Thumb instruction mode .code 16 / .Thumb
Summary:
what bootloader do?
initialize watch dog
initialize clock
initialize serial
set sp(r14) and enter svc mode
initialize ram
initialize mmc controller
clear .bss
prepare to boot linux
branch to address of linux kernel
bootloader lifecycle ended