Remove pending C tutorials

Presence of these files caused github to show the project as a C
project.
pull/4/head
Andre Richter 6 years ago
parent 6266cd38c6
commit 907f8dc75c
No known key found for this signature in database
GPG Key ID: 2116C1AB102F615E

@ -1,43 +0,0 @@
#
# Copyright (C) 2018 bzt (bztsrc@github)
#
# Permission is hereby granted, free of charge, to any person
# obtaining a copy of this software and associated documentation
# files (the "Software"), to deal in the Software without
# restriction, including without limitation the rights to use, copy,
# modify, merge, publish, distribute, sublicense, and/or sell copies
# of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be
# included in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
# HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
# DEALINGS IN THE SOFTWARE.
#
#
SRCS = $(wildcard *.c)
OBJS = $(SRCS:.c=.o)
CFLAGS = -Wall -O2 -ffreestanding -nostdinc -nostdlib -nostartfiles
all: clean kernel8.img
start.o: start.S
aarch64-elf-gcc $(CFLAGS) -c start.S -o start.o
%.o: %.c
aarch64-elf-gcc $(CFLAGS) -c $< -o $@
kernel8.img: start.o $(OBJS)
aarch64-elf-ld -nostdlib -nostartfiles start.o $(OBJS) -T link.ld -o kernel8.elf
aarch64-elf-objcopy -O binary kernel8.elf kernel8.img
clean:
rm kernel8.elf *.o >/dev/null 2>/dev/null || true

@ -1,36 +0,0 @@
Oktatóanyag 09 - Framebuffer
============================
Rendben, végre valami parasztvakítás :-) Eddig a képernyőn csak a szivárvány doboz volt. Most be fogjuk állítani a felbontását
egy csomó parancsot tartalmazó üzenettel és egyetlen egy mbox_call hívással, majd kirakunk egy képet. Teleraktam
kommenttel az lfb.c forrást (igaz, angol nyelvűek), hogy segítsenek eligazodni a parancsokban. De végeredményben
nem tesz mást, mint feltölt egy int tömböt és meghívja az mbox_call-t, igazán egyszerű. Ha gondolod, megpróbálhatsz
hozzáadni vagy elvenni parancsokat, hogy lásd, mi történik. Használhattam volna az MBOX_CH_FB (FrameBuffer csatornát)
is, de az MBOX_CH_PROP sokkal több mindent tesz lehetővé és sokkal rugalmasabb.
Fontos tudnivaló a pitch-ről: talán nem tudod, de a video képernyő rasztersorai nem feltétlenül vannak sorfolytonosan
tárolva a memóriában. Például lehetséges, hogy 800 pixelnél (800 * 4=3200 bájt helyett) 4096 bájton tárolódik minden
sor. Ezért fontos, hogy mindig a dinamikusan lekért pitch értékével számoljuk width * 4 helyett a képernyő Y
koordinátáját.
Arra is érdemes figyelni, hogy a GPU a Raspberry Pi-n nagyon combos. Létrehozhatsz például egy hatalmas virtuális
képernyőt (mondjuk 65536x768), amiből egyszerre csak 1024x768 lesz megjelenítve. Levelesláda üzenetekkel piszok
gyorsan mozgathatod ezt az ablakot, annélkül, hogy pixelbuffereket kéne másolgatni, ezáltal egy nagyon sima
szkrollozó hatást hozva létre. Ebben a példában mind a virtuális, mind a fizikai képméretet 1024x768-ra állítottam.
Lfb.h, lfb.c
------------
`lfb_init()` beállítja a felbontást, színmélységet, színcsatorna sorrendjét. Lekéri továbbá a framebuffer címét.
`lfb_showpicture()` a framebuffer-be direkt pixelek írásával megjelenít egy képet a képernyő közepén.
Homer.h
-------
A kép, Gimp-el C header formátumban lementve. Nincs tömörítve, a pixelek egymás után következnek.
Main
----
Nagyon egyszerű. Beállítjuk a felbontást, és kirajzoljuk a képet, ennyi.

@ -1,35 +0,0 @@
Tutorial 09 - Framebuffer
=========================
Okay, finaly some eyecandy :-) So far the screen showed the rainbow splash. Now we're about to change the resolution with
several tags in a single mbox_call, then display a pixmap. I've put a lot of comments for each tag and
argument to help you, see lfb.c. But at the end of the day it's nothing more than filling up an int array
and call mbox_call, really simple. If you wish, you can try to remove or add more tags to the message and
see what happens. Could have used MBOX_CH_FB (FrameBuffer channel), but MBOX_CH_PROP gives us more flexibility.
Important note on pitch: maybe you don't know, but video screens does not necessairly map raster lines
continously in memory. For example it is possible that 800 pixels (800 * 4=3200 bytes) are stored in 4096
bytes for every line. Therefore it's important to use the queried pitch value instead of width * 4 when
calculating the postition for the Y coordinate.
Also note that the GPU on the Raspberry Pi is very powerful. You can create a large virtual screen (let's say
65536x768) but display only 1024x768 pixels at once. With mailbox messages you can move that window very fast
without the need of copying pixel buffers, thus creating a smooth scrolling effect. In this tutorial both
virtual screen and physical screen is set to 1024x768.
Lfb.h, lfb.c
------------
`lfb_init()` sets up resolution, depth, and color channel order. Also queries framebuffer's address.
`lfb_showpicture()` displays a picture in the center of the screen by drawing pixels to the framebuffer.
Homer.h
-------
The pixmap, saved with the Gimp as C header file. No compression, pixels are stored one-by-one.
Main
----
Very simple. We set the resolution and display the picture, that's all.

@ -1,81 +0,0 @@
/*
* Copyright (C) 2018 bzt (bztsrc@github)
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use, copy,
* modify, merge, publish, distribute, sublicense, and/or sell copies
* of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
*/
#include "gpio.h"
#define SYSTMR_LO ((volatile unsigned int*)(MMIO_BASE+0x00003004))
#define SYSTMR_HI ((volatile unsigned int*)(MMIO_BASE+0x00003008))
/**
* Wait N CPU cycles (ARM CPU only)
*/
void wait_cycles(unsigned int n)
{
if(n) while(n--) { asm volatile("nop"); }
}
/**
* Wait N microsec (ARM CPU only)
*/
void wait_msec(unsigned int n)
{
register unsigned long f, t, r;
// get the current counter frequency
asm volatile ("mrs %0, cntfrq_el0" : "=r"(f));
// read the current counter
asm volatile ("mrs %0, cntpct_el0" : "=r"(t));
// calculate expire value for counter
t+=((f/1000)*n)/1000;
do{asm volatile ("mrs %0, cntpct_el0" : "=r"(r));}while(r<t);
}
/**
* Get System Timer's counter
*/
unsigned long get_system_timer()
{
unsigned int h=-1, l;
// we must read MMIO area as two separate 32 bit reads
h=*SYSTMR_HI;
l=*SYSTMR_LO;
// we have to repeat it if high word changed during read
if(h!=*SYSTMR_HI) {
h=*SYSTMR_HI;
l=*SYSTMR_LO;
}
// compose long int value
return ((unsigned long) h << 32) | l;
}
/**
* Wait N microsec (with BCM System Timer)
*/
void wait_msec_st(unsigned int n)
{
unsigned long t=get_system_timer();
// we must check if it's non-zero, because qemu does not emulate
// system timer, and returning constant zero would mean infinite loop
if(t) while(get_system_timer() < t+n);
}

@ -1,29 +0,0 @@
/*
* Copyright (C) 2018 bzt (bztsrc@github)
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use, copy,
* modify, merge, publish, distribute, sublicense, and/or sell copies
* of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
*/
void wait_cycles(unsigned int n);
void wait_msec(unsigned int n);
unsigned long get_system_timer();
void wait_msec_st(unsigned int n);

@ -1,45 +0,0 @@
/*
* Copyright (C) 2018 bzt (bztsrc@github)
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use, copy,
* modify, merge, publish, distribute, sublicense, and/or sell copies
* of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
*/
#define MMIO_BASE 0x3F000000
#define GPFSEL0 ((volatile unsigned int*)(MMIO_BASE+0x00200000))
#define GPFSEL1 ((volatile unsigned int*)(MMIO_BASE+0x00200004))
#define GPFSEL2 ((volatile unsigned int*)(MMIO_BASE+0x00200008))
#define GPFSEL3 ((volatile unsigned int*)(MMIO_BASE+0x0020000C))
#define GPFSEL4 ((volatile unsigned int*)(MMIO_BASE+0x00200010))
#define GPFSEL5 ((volatile unsigned int*)(MMIO_BASE+0x00200014))
#define GPSET0 ((volatile unsigned int*)(MMIO_BASE+0x0020001C))
#define GPSET1 ((volatile unsigned int*)(MMIO_BASE+0x00200020))
#define GPCLR0 ((volatile unsigned int*)(MMIO_BASE+0x00200028))
#define GPLEV0 ((volatile unsigned int*)(MMIO_BASE+0x00200034))
#define GPLEV1 ((volatile unsigned int*)(MMIO_BASE+0x00200038))
#define GPEDS0 ((volatile unsigned int*)(MMIO_BASE+0x00200040))
#define GPEDS1 ((volatile unsigned int*)(MMIO_BASE+0x00200044))
#define GPHEN0 ((volatile unsigned int*)(MMIO_BASE+0x00200064))
#define GPHEN1 ((volatile unsigned int*)(MMIO_BASE+0x00200068))
#define GPPUD ((volatile unsigned int*)(MMIO_BASE+0x00200094))
#define GPPUDCLK0 ((volatile unsigned int*)(MMIO_BASE+0x00200098))
#define GPPUDCLK1 ((volatile unsigned int*)(MMIO_BASE+0x0020009C))

@ -1,399 +0,0 @@
/* GIMP header image file format (RGB) */
static unsigned int homer_width = 96;
static unsigned int homer_height = 64;
/* Call this macro repeatedly. After each use, the pixel data can be extracted */
#define HEADER_PIXEL(data,pixel) {\
pixel[0] = (((data[0] - 33) << 2) | ((data[1] - 33) >> 4)); \
pixel[1] = ((((data[1] - 33) & 0xF) << 4) | ((data[2] - 33) >> 2)); \
pixel[2] = ((((data[2] - 33) & 0x3) << 6) | ((data[3] - 33))); \
data += 4; \
}
static char *homer_data =
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
"!!!!!!!!!!!!!!!!!1)$!Q5*$2=C$\"9B#!U5%BUM'3R((#Z-%S%T#!Y7!A-&!!!!"
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
"!!!!!!!!!!!!#R-?$REJ%2YP%C%W'3F%$BAI$2AM*DJ:#B%7$\"%9%2YR(#^*!A-&"
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
"!!!!!!!!#B5A%B]Y$BMK\"1I0'4*+\"B)B!!!!\"1];$\"QV$3>#$C9`$2]T#R9F(D&1"
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
"!!!!!!!!#\"1D%S=\\!19,#B)A$B-?(C9N+CMI34Q=?'9>BWY>?75=75E7.T)I'\"E="
")4)]!!!\"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
"!!!!!1-%%S-X\"QY9#R)>(\"QD=6=FJHUHY\\-L`_1J`_E?`_9A`_AA`_IH`^YIVLM@"
"F9%O5&*#!1I9\"QQ3!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
"!!!!!!!!%3!\\'2=BFXEU:UU?QJ%VW;EI_^-B`^EA`^EA`^IB`^IB`^IA`^IB`^QA"
"`^EB\\^%^K*NK!QQC\"AI2!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
"!!!!$BUR'BI7P:1ZV+-I<F9CQ*=L\\]9A`^U@`^IB`^IB`^IB`^IB`^IB`^IB`^IB"
"`^IC`.I;`_.#O[^\\\"QQ;!!!\"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
"!1E1+DB(>6IKV*UOT;%JL9!NU[=K`^QD`^I@`^IB`^IB`^IB`^IB`^IB`^IB`^IB"
"`^MA`^IC`N9<_^^3A(RD%2IG!!!!!!!!!!!!!!!!!!!#!!!!!!-*!!!%!!!!!!9,"
"!!!$!!!'!!%\"!!5/$\"-=!!!%!!!!!!!!!!!&#\"!9!!5.!!!!!!!!!!%\"!!!$!!!$"
"!!%'!!!!!!!$!!!!!!=1#A]:!!!&!!!!!!!\"!!50#!Y8!!)*!!!!!!!$!!!+!!-*"
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
"#RANE7QKS*=NUJQOT;!LT:UM\\M1F`^M@`^I@`^IB`^IB`^IB`^IB`^IB`^IB`^IB"
"`^IB`^IB`^ED`NIH[>2V.%*/!!!!!!!!!!!!\"1A+=Y'.O<`$8WJ^DZGCP-,)3&NN"
"G;7MK\\;])$64I\\#ZQ]H-J\\#U(CU_$C-PH[KRR-P1LLH\"(DB0!!!!(#Y^I+WXL,;^"
";(\"]OM$'=([/(D\"&KLD!QML/I[SR'3M['#M]JL+`R-H*K<3\\&SV&=Y?:PM@-78+("
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!QU:"
".CU?WKAUT;%JU*YOTK!MTJQK_N-G`^E>`^IB`^IB`^IB`^IB`^IB`^IB`^IB`^IB"
"`^IB`^IB`NMA_^I?`_^<B(R2\"B9K!!!!!!!!\"AA+DZG@````DZ?=U^@9````=8B]"
"[OXOW.D;GJ[@````^0,S````HKOYH[[\\````^00T```^N](%!!M8&#%PX/(D_`T["
"EJ35````G[7PI\\3[```_]P0S````H;GXG;GW```_]`,S````K<<!AJ#;````>)/9"
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!1%\"!R)G"
"FX5OV;)NTJYMTJ]LTJ]LT[%I_N5E`^IB`^IB`^IB`^IB`^IB`^IB`^IB`^IB`^IB"
"`^IB`^IB`^M@`^AC`.US`_W6%\"QO!!!!!!!!!Q5(?I3/`@\\_LL#Q[?@H````F*/4"
"````J[?HY?,B\\/XOH;#@```_R=D,P=$\"````J+;I\\O\\P[/PO!!U;'3)OX/,H_`PZ"
"HJ[?````F:C=X?$C]P,SH*[@_PL[S=L,Q-$%````G:K<\\O`OZ/DL>H[%````9XC1"
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!-((31P"
"R*=QU*YJTJ]LTJ]LTJ]LU+)K_N5E`^EA`^IB`^IB`^IB`^IB`^IB`^IB`^IB`^IB"
"`^IB`^IB`^IB`^EC`>AB``/\"8&R1!AQ=!!!!!1)$9W^[_@L]S]X/^P<W````P,S]"
"````C)K.Z/DK\\O\\OIK3E```_S=H+QM4&````K+OM\\_`PZ?HM!R%?'3-OX/,H```^"
"\\?\\O````F*?=X?(D]`0TIK3E_PL[T-\\1Q-4$````HK#A\\`(OZ?HM:X2]````5'6^"
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!-)1U-Z"
"T*MLT:YNTJ]LTJ]LU*]MU*]I_N5D`^IB`^IB`^IB`^IB`^IB`^IB`^IB`^IB`^IB"
"`^IB`^IB`^IB`^IB`NA9`_:JGZ2Q!!!*!!!!!!!!5FVI^`DZ\\`$Q_`P\\`P\\_Z?8F"
"````:(;$Z_@D\\?\\OI[3G`@`_R]L+QM0%````K+OM\\_`PZ?DM\"\"!@'#-OW_0F```_"
"^P@X````EZC<X?,D]`0TIK3G_PL[S]\\1Q=4%````HK#B\\`$PZODJ9H'\"````/U^D"
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!&4%5S"
"U:UKT:]NTJ]LTJ]LU*]LTZYK_N1F`^IA`^IB`^IB`^IB`^IB`^IC`^IB`^IB`^IB"
"`^IB`^IB`^IC`^IB`^E=`>^,T-+6$BAK!1)%!!!!0UJ6]@0V````Z/0DYO,B````"
"````6'W$ZO@G\\?XNHJ_B`P``RML,Q-0&````J+?I\\O\\PZOHM!!U<'#)NX?,G_PT["
"E*#1````F*C<XO,E]P,SHJ_B_PL[SMT0Q=0&````G:S>\\_`O[?TM77S!^`4S+TV4"
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!AA.4%=Y"
"TZUMT+!NTJ]LTJ]LTZ]LT*QI_.%H`NM?`NE@`^MA`_9@`_=B`_%9`NE?`^EC`^E>"
"`^AB`NAA`^Q:`_-=`_1B`^YA^.RCDIRO&2YJ!!!!,TF$Z?DH`P``R=<'R=8(````"
"`0PX7XS>PM@,_0HYT-\\/````N,X$M<L#````T^(2^`@WWNX>!!51'CEXX/0E_@P["
"EZ+6````G*[HR]X0_PL[T=T/````NLX!L\\?`````S]T._@HVV.L>8X'+\\_\\J1V6N"
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!-*1U9^"
"TJMKTZ]MTZ]LTJ]LTJ]KSZQJ[M)J`^I@_.ABW-%OE(IMAG]JO+%W^N5N_>A@`.I;"
"`.AC_>=CZ=9VIY]QG9-OS,)T_>ARS<6L+$2#!!!!(CEUU^D;^`DYJL3]GKCW_@LY"
"Y/4I0%60.6:N]@,V_@L[\\@$S2VJH0&\"=\\?`S_PPY_PX]4G;\"!!!!(#Z\"W>`@]P4T"
"DZ+4`0X^F+/T3GO%^P8V_PP[]0(R37\"W1&>K[OXQ_@LW_@H[06NZ>YG6```_5GC&"
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!-(*#QO"
"S:ERTJ]KTJ]LTJ]LTJ]LT:QMY<=GPKAHD96EDYW;Q]84T.(<K+GYB8^\\HYY\\\\MUJ"
"TL!?C8V5BY32P,\\+RMD7FZ?LAHNR=X\".'S9T!!!!!QA.%C1V&#1X$BUK$2UK%S5W"
"%\"]Q!Q=-!!!\"'CZ#15^>&CAX!!%'!!!&&CE[0%F:(#V!!!)'!!!!\"1I0%2]N%\"]P"
"%\"QH%\"]P$2MH!!!$'CI\\15Z<&SI_!!!\"!!)'&S5W0%F8(#U_!A5+$\"EE&CA^#B5B"
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!)$#2-A"
"P:-YTK!ITJ]LTJ]LTJ]KWK=T?6I<L;CI]`4W`````````````````P``TMX566%F"
"CY2Y[OPP````````````````_@L\\IK+G)4.'!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
"!!!!!!!!!!!!!!!!!!!\"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
"!!!!!!!!!!!!!!!!!!!!!!!\"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!1%#!!!\"!!!!!!!!!!!!!!!!"
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!1]D"
"CWYSV+1JTJ]LTJ]LU+%KGX1@DIS.`````@\\]`P\\_`P\\_`P\\_`P\\_`P\\_```_RM0,"
"<'RJ`````P\\_`P\\_`P\\_`P\\_`P\\_````8'\"H\"B%<!!!!!!!!!!!!!!!!!!!!!!!!"
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\"!1)$!1)$"
"!1)$!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
"!!!!!!!!!!!!!!!!!!!!!!!!!!!&!!)*\"QU5(BY>1%1^,C]C$\"%6!!)(!!!!!!!!"
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\"\"!?"
"4$QCX+ERT:]MTJYNTJYJ=&UX]P,T``T_]P,T[OLK`````P\\_`P\\_`P\\^`@X\\````"
">H:Y[?HK```_`P\\_`P\\_````\\?TNXN\\AV^45%#B#!!!!!!!!!!!!!!!!!!!!!!!!"
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!1)'&S-O4V&*8&F("
"0%&\"#QY4!!%'!!-)!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
"!!!!!!!!!!!!!!!!!!)$!!E@,#5D,#UN-#]MOJ)VRZIIXM)EI:%J%BQL!!!#!!!!"
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
")C=QSJENU;!LUK%MRZ=KCY\"K_PL\\`@X^@8N^(2U>`````````P\\_`P\\_`P\\_````"
"L[_QR]@)```_`@X^`@X^````KKCK35J,_P8P#\"Q\\!!!!!!!!!!!!!!!!!!!!!!!!"
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!)$&C1QDH!WRJ9ISJIH"
"TK5P/$-J-4%O*#EN\"2-F!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
"!!!!!!!!!!!!!1-&%BQOFXYR]MEB^^EHD(9FAW!FY<%N_NAD`>I>C(QQ$29E!!!!"
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
"%#!TGX9FV+5TOI]JRZAOF)NY`@T^```_RM0'H*S=`````P\\_`P\\_`P\\_`P\\_````"
"L+SMR]@)`````@X^_`P\\`@X^^P4W^`8ZR=$!$SJ%!!!!!!!!!!!!!!!!!!!!!!!!"
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\"AU2;6=YTK%OVK%I^>)G"
"DX=IE()NT:QMTZIO:65Q$REL!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
"!!!!!!!!!!!!\"QU9=6MP]=1H`?!>`^A@``!G@W9EJH]MW\\5IY--?RKIH+T9^!!!!"
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!)$\"B%?"
"!AY>>6UKL)-M.3AAG8=GC8B7^@8W`0X^`````````@X^`P\\_`P\\_`P\\_`P\\^````"
":72HM\\#UM<#KHZO1CY.SE)J`Q]8&````5FJI&3-R!!!!!!!!!!!!!!!!!!!!!!!!"
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!QM3)3QX;&!A?W!KJI]DMJIL"
"A'!DW[=UZLUD^^-B_N-K5F%R!AA.!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
"!!!!!1E4!!UJ+SQM=F1DWK9O]N!A`^ME`NI7[=MX/#9:?W)EEXM>F(QH/DAM!!UB"
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!A5*&3>\""
"#S\"\"7V!Y>6ECL)5X;6!A@V]FT=L.`````@X_`P\\_`P\\_`P\\_`P\\``P\\`````KK?T"
"9VUXQL\"@TLB4X=B6]>FAZ^S';'&8AI;0(3E\\!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!AQ8/4=PLYAOV;]FX])FS;]B9V5A"
"FX-K[,QI`NM?`_1FK:-A9F)H%BQM!A]?!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
"!!%%)35HQKEQ]MY@MZQI6U!BW+EO^^1D`^]O3DM9N:5K_>1D`^ED`^AB_^9S7V5Z"
"\"1QB!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!A5)#BUT"
"$#![04=U;6)FTZMR<F9DMIQM4T]O]0$T```^`@X^`0`]`@\\]`0`V``\\YS=T5:VIN"
"`_-O`^QB`^A<`NE?`.I>`^YWFY^E)#=Q#!Y3!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!$RAEJ9!RV[5G`.AA`^EF`^I=_.5I"
">'%HWLIJ_^AH8%Q9D7UORZ9PN)QX.T5Q!15-!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
"$\");D8YI`^U=`^I@`_1DT\\9J75A:S+)Q9EU=Q:QR`^Y@`^IA`NI?`^M>`NI8Y-R4"
"\"1U=!!%$!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!1-'$2YX"
"$\"AJ%R5:85MHUZYNF8-EI8=LRZIS;FIUO<KQZ/0G\\?PR\\?POY.\\EOL;MCHMY^NAF"
"`>=?`>AB`^AA`NIC`^AD[=-D:6MSI*2>%\"5;!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!11(,T!OR:=PYLUD^.%G`NI>`^EA`^Q@"
"X]-I@'YI?GAEK)%VY;]J[<]C_^-?W,MJ*#QL!!%$!!!!!!!!!!!!!!!!!!!!!!!!"
"'C%LMY]E`^MJ`.Q:`>EC`^YAV\\EM44I>FH)K_^9F`^M@`NE<`.MP]>-[_^=<\\^%["
"/$U`!!%%!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!%#$\"MS"
"!A1(#B5E?7!FV*YNS*IOQJ-MT[!JX,-CR+QGIZ-_I9^3K*F0OK:&W<UQ^N5KZ]!G"
"Z\\MV\\]-WZ<AMRZYGDX!=9V%U4E1S?'^&$B-7!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!1)355WS:IG]MYIE8YE^N1C`^A>`NE;"
"`_E^?WV.CGAIX,!F^N)D`^QA_.AEY]9F;'5Y!!)'!!!!!!!!!!!!!!!!!!!!!!!!"
"*C]XGGUJI9EP`^]D`^AB`>M=^N=>?W=GP:9E`^M?`N=<_^=LZNO\"B8!L_^A=]^5Y"
"3EJ#!!!\"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!1%\"$\"Q["
"!1-)#B%?EX%RV*]OT;!JTJ]LT:ULYL9J`^IC`^U;__%HP+-P8UQ41#]40SY@/SI>"
"/3E7-C1/.31:7U=TDX.;S;2]SL32?8\"G'#V&$R9>!!!!!!!!!!!!!!!!!!!!!!!!"
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!-'5UIYU:QK_.=>RKAIB8-W`_:$`.9O"
"``6\\=WR,M9AH_MYI`NI>_NYH;FQAWLYKA(J(!!%'!!!!!!!!!!!!!!!!!!!!!!!!"
"(#-GIHYI*BA3J)MN^N)A`^EE`>I=FHYCJIQE^.=Z]NN=VM:\\:&9SX]=A`NE=^.J)"
"55V$!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
"\"QY:.DIN8UY@E8)LSZUOT[!LTJYKZ<EF^.1CM:AO75-Q9%M_HI*FPJJPQ:JOQ*BQ"
"Q*FRQ*JPQ*NQQZRPU[VZV,&_U\\\"]ZM+4N:_!0%2.$\"5A\"1Q6#B!:\"!A/!!!!!!!!"
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!9.4EIUT*QH_.)J`^Y?J:%A?8&3Q<2_"
"L:^Q04-=QZYP`^]@^.)JBX!H0DA=^.1T<'Z6!!-(!!!!!!!!!!!!!!!!!!!!!!!!"
"$2)8D'YQ7U-A;F5JR:UQ^]IC]=QI@75GC']EDI-`?G^1@H!L[-EG`^]C`>A>_N^B"
"8V^7!Q=/!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!QU?"
"<7)MX\\]HZMIKT,!AS*MNTJ]KT:YKWKUN@GEH?&Z+M)ZHT;F[U+R\\U+Z_U;^_U+Z_"
"U+Z_U+^^UL\"_U\\'!U\\'!U\\\"_UL#\"U;^`WL7$R+O&2%.':':EC9*Y-DR+!A5)!!!!"
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!-.(31OH(QNTJQK_-]D`^Q@\\^!E8&-=P+)G"
"T\\)BU,5J?71GL:5>MJEH>'-IN*MC]NJ3,TF#!A1'!!!!!!!!!!!!!!!!!!!!!!!!"
"!15)6EQMRJIQ955E9%I=@'!I2D)8CWYJ]=MI]=UMOK!>KJ)F`^]?`^I@`>M>_NR)"
"QLC#(3UY!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!%#$2-D"
"P*-N<VIQ+3!1PZUPT[%ITJ]LU;)P@'-K>V^%QJFMV,\"`UL##UL#!UL#!UL&_UL#!"
"UL#!UL#\"UL#\"UL#!UL#!UL#!UL#!UL#\"V,'!SKZ[P;6`V<C$V\\;*A(2N\"QM2!!!!"
"!!!!!!!!!!!!!!!!!!!!!!!!!!)(&\"YHL)1OV;!QT:YI_.%D`_!CF9%BR+=K`^Q>"
"`^AA`^ICZ]ADL:9SM:IJX<UH`_6\"F)FA\"R)B!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
"!!!!%\"-=HXMRV[EQLY9SFH=IQZAWV;%J[]!E`.]9Q;=KMZEE`^UC`^IB`^AB`>I;"
"`_>GFZ\"K(T&)!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!%##R-?"
"QJAZD'AGH(1RDX%HW;1PU+!JNY]P3TALNZ&IU\\&_U,'\"UL\"`UL\"`UL\"`UL&^UL\"_"
"UL#!UL##UL##UL\"`UL'!UL#!UL#!U\\#\"U<'\"UL&YPJZTS[:[SL#\"4V\"3!Q=-!!!!"
"!!!!!!!!!!!!!!!!!!!!!AA0+4%VKI%LVK)NSZYKW[]I`NEA`NICKJ!LZ=9A`^MC"
"`NIA`.MC`^MC`_!<`^Y@`_1`T,^])S]_!!%%!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
"!!!!!!9.(S1MMIAKW;EPU[-LU+!KT:QLY\\5J`^M@U\\9FZ]9F`^IA`^IB`NIC`NM?"
"`.IB`_BCHJ:R$BML!A-$!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!1Q:"
"6UINR*5QWK9XU;-WP*!IW+AN:UIEBGB2S[6XU<*^U<&`UL&`UL&_UL&_UL&_UL&_"
"UL\"`UL#!UL'!UL&_UL&_UL#!UL#!UL#\"UL3!O*>K3DQPPJNPIZ'\"$2AJ!!!!!!!!"
"!!!!!!!!!!!!!!!!!!97,D)RKY%MV+%OTZYMV;1K^M]B`^MB`^EA_>9C`>A>`^ID"
"`^IB`^IB`^A>_>II`_NHR\\FZ.U.-!A=0!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
"!!!!!!!!!19,+3YVMYALU+!MTJ]LTJUMW;IM`^Q<`^M@_^I@`^IB`^IB`^IB`^IC"
"`NIC_NA?`>Z2H*>Q%3!S!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
"\"B!<,41W4$A72D-<MYIOV[=V/SE9P*2MT;F]U<'#U<&_UL*^UL&_UL&_UL'!UL#!"
"UL#!UL#!UL'!UL&_UL&_UL#!UL#!UL#!VL6`FX>=#!5&R;7(&#-Q$2AE!A5*!!!!"
"!!!!!!!!!!!!!!=71$=OQ*5SUK!LSK%MU:YI^-QF`^IB`^IB`^ED`^I@`NMC`^EA"
"`^IB`^EA_^EM`_[*JJBS*$.\"\"1E0!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
"!!!!!!!!!!!!!A=.-$)PN)]NUZ]MTZ]NT:MH^]YI`^M?`^IA`^IB`^IB`^IB`^IB"
"`^IA`^M?`>AA`O.5EYRC)$\"%!!-'!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
"!!!!!!!!!\"1M>&UKX;EKPJ)M54QKQ*:MT;R]UL&_UL&_UL'!UL#!UL#!UL#!UL#!"
"UL'!UL'!UL##UL#!UL#!UL#!UL#!UL#!V<3\"R+\"VNJ*ML*:U\"2%G!!!!!!!!!!!!"
"!!!!!!!!\"Q];4UI[QZEQUZ]LT:YMUK9H^-YD`^M@`^IB`^IB`^IB`^IB`^IB`^MA"
"`^ID_^M?`O:YA8BF!2-J!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
"!!!!!!!!!!!!!!!!!!E90DAKVK-QU:]LU*UQV[AE`>=D`^IB`^IB`^IB`^IB`^IB"
"`^IB`^IB`^E?`>E@`_20M[FV*D%^!QE2!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
"!!!!!!!!!1U=75ADX;IMOIYK75-TQ*BKU+Z\\UL&_UL&_UL&_UL&_UL&_UL#!UL#!"
"UL'!UL'!UL##UL#!UL#!UL#!U\\#\"KYZHK)VMXLO+[];56V2-$2QO!!!!!!!!!!!!"
"!!!%\"!YA;6=QS*ANUK!KTJQRV[MF^N%C`^QB`^IB`^IB`^EA`^IB`^IB`^IB`^IB"
"`>A=`_*>K;\"U&#-U!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
"!!!!!!!!!!!!!!!!!!!!\"B-K651AW[ATT+%LU*]IZ\\QH`^IA`^ID`^IA`^IA`^IB"
"`^IA`^IB`^EB`^IB`^A?`^V!S\\^[+$6\"\"1M4!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
"!!!!!!!!!!922DIAXKQOTK!Q0SUCQZNLT[V]UL#!UL\"`UL&`UL&^UL&_UL#!UL#!"
"UL#!UL#!UL'\"U<'!U<'!U<'\"U,*_U,##2$5P1%B11UF7(#Z$!!!!!!!!!!!!!!)&"
"&#%QDH!QUK%QTZ]KTJQPW+MF_^5E`^IB`^IB`^IB`^IB`^IB`^IB`^MA`NEE`NE;"
"_^Z%Z.33)T%_\"1Q0!1-&!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
"!!!!!!!!!!!!!!!!!!!!!!!!%2YMCGIPT[%NTJYNU;)I]]EE`^IA`^I?`^IB`^IB"
"`^IB`^IB`^IB`^IB`^IB`NA<`_%[X=NS36.9#2-A!!!!!!!!!!!!!!!!!!!!!!!!"
"!!!!!!!!!!9/.3A7X[USV[=R7$]?GXRAU;N]UL#\"UL#!UL&`UL&_UL&_UL#!UL#!"
"UL#!UL#!UL'!U<'!U<'!U,'\"W,'#HY:E)T\"#!!!!!!!!!!!!!!!!!!!!!!9.)SUU"
"GX1HU[-ITJYLT:UMX<!G`NAE`^E@`^IB`^IB`^IB`^IB`^IB`^IB`^IC`^E@_^QU"
"^?+.1%B%\"R-?!!!!!!%\"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
"!!!!!!!!!!!!!!!!!!!!!!!!!!)%*#9DNIUPU+!KT:YNV+)J^=MG`^MB`^EC`^IB"
"`^IB`^IB`^IB`^IB`^IB`^IA`>A>`^]Q[N6C=(\"C#REM!!!!!!!!!!!!!!!!!!!!"
"!!!!!!!!!AA2,C5;X[UWUK%KM)ET5T]RRK*VUL&`UL##UL&`UL&`UL&`UL\"`UL\"`"
"UL\"`UL\"`U\\&`UL'!U<'!XLS)KI^G,$-`!!)&!!!!!!!!!!!!!!!!\"21H4E9TN)IN"
"V[1PTZ]LT*UNYL=D`.9C`^EA`^EB`^IB`^IB`^IB`^IB`^IC`^I@`^E@`>IE_O:["
"<'N9\"B%B!A1%!!!!!1)$!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!50/3]CU;=WU*YNTZ]MU;-H]]UF`^I@`^IA"
"`^IC`^IB`^IB`^IB`^EA`^IB`^IB`^I@`>MA_/\"8F:\"H%35^#B%;!!!!!!!!!!!!"
"!!!!!!!!!AE2,C=;Y+UXTZ]NUK%OA'%MA'6-U\\/!UL&\\UL&`UL#!UL#!UL&_UL&_"
"UL&_UL&_U\\&_U,+\"Y<S'CH\"2*$6*!A9-!!!!!!!!!!!!\"QE*#\"QY=&QKTJQLU*]K"
"U*YOSZMHZ\\YF`>EC`^IB`^IB`^IB`^IB`^IB`^IB`^IA`NMC`^AE_^=B`/:GFJ\"Q"
"&SE\\!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!E<651BT[-LT[!LTJYOV+=J^]]G`^I?"
"`^IC`^IB`^IB`^IB`^IB`^IB`^IB`^IB`^EA`>A<`_6-P+VH*T%Z\"!I3!!!!!!%$"
"!!!!!!!!!!9//#M;X[QTT;!LTK!LTJ]M9UAABX\"7SKS!V,+#V,+\"U\\'!U\\&`U\\*`"
"V,*`V,.`U\\&`P*ZW9VB+%S1X!!!!!!!!!A9/%#%T\"R-C'S-MGH)GW+9RT;!KU*YM"
"U;!I\\-)F`^I?`^I@`^IB`^IB`^IB`^IB`^IB`^IB`^IB`>ED`>A=`_22R\\O('35Z"
"!!%#!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!#!Y<=&UOU:]NTZ]JT*]MVK=I^]]D"
"`^QA`^IA`^IB`^IB`^IB`^IB`^IB`^IB`^IB`^IB`.E@`^]OVL^+6F5V#AU=)39T"
"!!M9!!!!!!E64$QCWKIOT:]JU;%LV+)NW;MOJI]B=&YWDH6:N*6TSKF]U\\#&S[NY"
"O*BXG9\"E?7B+9&F'#B5E!!!!!!!!!!1//U\".J+'E=(\"U6%IYH8AJU+%NTJULT[)M"
"\\=-E`^EB`^EB`^IC`^IB`^IB`^IB`^IB`^MB`^IA`^IB`N=>`_&-U-#!,$R+\"!Y7"
"!!%\"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!%#$R5@H(ASU[!NTJ]OTJ]LV;9G"
"^^!C`^IA`^EB`^ID`^IB`^IB`^IB`^IB`^IB`^IB`NMA`^IB`^EC_>=BH9QI3%\"!"
";WFN\"\"!I!1Y>;F1EZ\\1[V;9ZR:AQLY9KK))ER;IBP[5AC(5D<W)J>7)]9%YU6UMQ"
"='1SI)I@XM:3T<[-!QA/!!!!!A1'-4Z0Q],#Y.@;Y^L8V=L(B9*`<6-KTK%L]MQE"
"`^IB`^IC`^IB`^IB`^IB`^IB`^IB`^IB`^MC`>MB`N=?`>MZZ^7,/52)\"QY7!!!!"
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!))&\"9@LI9VV;)JU*]MTZUP"
"V[EF_>%E`^I=`^EB`^IB`^IB`^IB`^IB`^IB`^IB`^ID`^IA`^MB`NAB^>A><W6)"
"Z.X?@(N]&#1`1$EK34QR049R5UZ/:G.BB)7*FJ7>G:CAFZ/2@8W\"<7.(S,!M_NAE"
"`^U>`^Y?`?&0R\\K((SZ*.5JE.%.8A8R\\WN<4Y^82X>@7XND9Z.H:JKCL@W]^\\-QF"
"`^Q>`^IA`^IB`^IB`^IB`^IB`^IB`^IB`^IB`>E>_NQT]_/,87&8#2-B!!!!!!!!"
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!1.(#%EKI-OU;)LTJ]N"
"T:UMW;II_>%D`^M@`^IA`^ID`^IB`^IB`^IB`^IB`^IB`^IB`^IC`^M<W<YIB9.`"
"_`L[[O0C;G2C?H>XY.T<ZO$?Z_(?]/LJ````````````````````P,P\"CY6VUL9F"
"`^]B`NA>`>M[TM#,E9W.Q,KUWND7D)O/R,[]Y.<6Y.<5X.44Z?(C````V.4=?8*8"
"U,1=`^Q?`^M@`^IC`^IB`^IB`^IB`^IB`^EB`.QS`OG,=8\"@#B-H!!!!!!!!!!!!"
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!1-',CYFPZ%TTZ]L"
"TK!LTZQOV[=G_>%G`^I@`^IC`^IB`^IB`^IB`^IB`^IB`^IB`^EB`_)BCHEAQ]8+"
"`````0T\\Z?(A7665M[SLZ>P;XN85^`4R`P`_`P\\_`P\\_````GZK=K+?J^@D[559\\"
"Z]ML`^Q>`.AKV=;-F)_/;'2H````PLW_J+'>X^L8W^<5\\?LK`PX``P\\_`P\\_\\_`P"
"@H28Y--H`.MA`^MB`^IB`^IB`^IB`^EA`.AC`?K&>X:@%C!S!!!!!!!!!!!!!!!!"
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!1./D1HRZAO"
"U;!JTJ]LT:]LV[MI_>5A`^MC`^IB`^IB`^IB`^IB`^IB`^IB`^QC]>!A<72-_0DZ"
"`P\\_`@X^_`LYT]T*96R;V-\\,YN\\<`````P\\_`P\\_`P\\_````/DA\\````````\\/TQ"
"5%AA^>5A`>AEWMS&3%6&V^@9````^P<X8VZA[O4C]@$P`@\\_`P\\_`P\\_`P\\_```_"
"X>\\E=7J+]N1B`^MA`^IB`^IB`NE?_^AD__:\\H:6S%3-[!!!!!!!!!!!!!!!!!!!!"
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!95149F"
"QJ1OU+%LTJ]LT:YMW+UH_N1B`^MA`^IB`^IB`^IB`^IB`^EB`_!AIYQAL;WR````"
"`P\\_`P\\_````_@@VGZC7G:75^@,S`````P\\_`P\\_````XNX?='ZR`````@X^````"
"QM(\"H)=I_NA;W=G$6VB6R]@(````````5V25ZO4E`````P\\_`P\\_`P\\_`P\\_`P\\_"
"````V>0=<G!O^^AC`^MB`^IB`>EG`_VYK;*Y'CQ[!1)#!!!!!!!!!!!!!!!!!!!!"
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!AE3"
"24IKSJIOTK%IT:]PT:YKW+MG_^5C`^M@`^IA`^IA`^EC`>M>\\-UG<GB2`````P\\^"
"`P\\_`P\\_`P\\_`P\\_YO(@?8>W]`,S``\\```X```X`````J+/EQM($`````P\\_`P\\_"
"_PP\\E)K!X=N#>'F(Z/8J8FV?\\OXO````N\\7WDI[1`````P\\_`P\\_`P\\_`P\\_`P\\_"
"`P\\_````S]X&FI-B`NQC`.E:`_FQJ*VV%S%R\"R%5!!%#!!!!!!!!!!!!!!!!!!!!"
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
"!1I84$UJSJMTU;!JTJ]LT:UMW[QH_^5F`^IB`^IB`^I@`^IED(MKX.T=`````P`^"
"`P\\_`P\\_`P\\_`P\\__`PYC);&SMH*XN\\?W^P<W^L<X.T>B)3'[OLK`P\\^`P\\_`P\\_"
"```_^P<Z7F6-PLK`````^`@Y5V*5````````4ER/`````P\\_`P\\_`P\\_`P\\_`P\\_"
"`P\\```\\\\_PTZFJ\"_YM)D_/:JP,\"`(3Y^!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
"!!!!!!951TQIQZ9NU+%LT[!KTZUMX+]G`.9A`^EB`^YBQ[IEG:?5`@X^`P\\_`P\\_"
"`P\\_`P\\_`P\\_`P\\_```_Z?8E04M^L;SOI;#CJ++FIK'DL[[Q^`@Y`P\\^`P\\_`P\\_"
"`P\\_`P`]```````__`X[````O,;Z;':JDYS1BI7(`````P\\_`P\\_`P\\_`P\\_`P\\_"
"`P\\_`@\\_`P\\]T=\\0IJ6GR<[%+TF+\"!E0!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
"!!!!!!!!\"1U90$1IRZAMU;!NTJ]LT*UJW[UJ`^I>YM->>'N?_0@[`P\\_`P\\_`P\\_"
"`P\\_`P\\_`P\\_`P\\_``\\`````:W:I^`@X`````P\\``P\\_`P\\_`P\\_`P\\_`P\\_`P\\_"
"`P\\_`P\\_`P\\_`P\\_`P\\_`P\\_\\/TNEZ+8\\/TM_`P\\`P\\_`P\\_`P\\_`P\\_`P\\_`P\\_"
"`P\\_`P\\_`P\\_`P``<7RE*$B-\"QY4!!!\"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
"!!!!!!!!!!!!!!=4.3]GPJ1PU+!MTJ]LTZUKT[IK;F]]Y_DH```^`P\\_`P\\_`P\\_"
"`P\\_`P\\_`P\\_`P\\_``\\`````O,;YO,GY`````P\\_`P\\_`P\\_`P\\_`P\\_`P\\_`P\\_"
"`P\\_`P\\_`P\\_`P\\_`P\\_`P\\_`0T]GZK?XNTA``\\```\\_`P\\_`P\\_`P\\_`P\\_`P\\_"
"`P\\_`P\\_`P\\_````BY3($2QK!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
"!!!!!!!!!!!!!!!!!!92-CEEKI-PV;5PRZ=O:F)XS=H/`````@\\_`P\\_`P\\_`P\\_"
"`P\\_`P\\_`P\\_`P\\_`P\\_````[OHKQ=(\"`````P\\_`P\\_`P\\_`P\\_`P\\_`P\\_`P\\_"
"`P\\_`P\\_`P\\_`P\\_`P\\_`P\\_````O\\K]K;?K`````P\\_`P\\_`P\\_`P\\_`P\\_`P\\_"
"`P\\_`P\\``P\\]```]<XC\"\"R!9!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
"!!!!!!!!!!!!!!!!!!!!\"QQ7.SQIF(5P6U9HMKSS\\OPH```^`P`_`P\\_`P\\_`P\\_"
"`P\\_`P\\_`P\\_`P\\_`P\\_`P\\_`@X^`0T]`P\\_`P\\_`P\\_`P\\_`P\\_`P\\_`P\\_`P\\_"
"`P\\_`P\\_`P\\_`P\\_`P\\_`P\\_`P\\_`0T^4UV1`````P\\_`P\\_`P\\_`P\\_`P\\_`P\\_"
"`PX_`@T^````GJ[D(C^#!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
"!!!!!!!!!!!!!!!!!!!!\"QM15&.9/TA[OL3VZ.T:X>86\\/DH`PX^`P\\_`P\\_`P\\_"
"`P\\_`P\\_`P\\_`P\\_`P\\_`P\\_`P\\_`P\\_`P\\_`P\\_`P\\_`P\\_`P\\_`P\\_`P\\_`P\\_"
"`P\\_`P\\_`P\\_`P\\_`P\\_`P\\_`P\\_````='ZQT-P-`````P\\_`P\\_`P\\_`P\\_`P\\_"
"````^P8VG:O?&39^!Q5)!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
"!!!!!!!!!!!!!!!!!!!!!Q9)$\"9EIJW?[_$?X^H6Y.@6X><4Z_4B_`PZ`````P\\`"
"`P\\_`P\\_`P\\_`P\\_`P\\_`P\\_`P\\_`P\\_`P\\_`P\\_`P\\_`P\\_`P\\_`P\\_`P\\_`P\\_"
"`P\\_`P\\_`P\\_`P\\_`P\\_`P\\_`P\\_````Z/0E76>;`````P\\_`P\\_```_``````\\\\"
"S-L*8':U#\"1H!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
"!!!!!!!!!!!!!!!!!!!!!!!!!!!$%\"IL?XK\"XN@2YNP:Y.<5X><5Y>P:^@8T`P``"
"`P\\_`P\\_`P\\_`P\\_`P\\_`P\\_`P\\_`P\\_`P\\_`P\\_`P\\_`P\\_`P\\_`P\\_`P\\_`P\\_"
"`P\\_`P\\_`P\\_`P\\_`P\\_`P\\_`P\\_`P\\_````3%6*```````````````_P\\[_=(K)"
"'35V!A9+!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!1/.4>#KK3EV>(0YNH7XND5X>H8\\/HG"
"`0T\\`P```P\\_`P\\_`P\\_`P\\_`P\\_`P\\_`P\\_`P\\_`P\\_`P\\_`P\\_`P\\_`P\\_`P\\_"
"`P\\_`P\\_`P\\_`P\\_`P\\_`P\\_`P\\_````\\/TMA9#$Q,`\"V>8:CIO30UJ9%3!R!!-*"
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!%&!!A4-DB%=H.]J:_CT-<%UMX-"
"W^87[/<H^P<W`P\\_`P\\_`P\\_`P\\_`P\\_`P\\_`P\\_`P\\_`P\\_`P\\_`P\\_`P\\_`P\\_"
"`P\\_`P\\_`P\\_`P\\_`P\\_`P\\_`P\\_````N<7W56*6&\"YO$\"]P\"2!?#\"AG\"R)8!!!!"
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!#!19-#25F(3!J9VZ;"
";'6D=X\"QSML+`````P\\_`P\\_`P\\_`P\\_`P\\_`P\\_`P\\_`P\\_`P\\_`P\\_`P\\_`P\\_"
"`P\\_`P\\_`P\\_`P\\_`P\\_`P\\_`P\\_`P\\_````\\/PM>XO$&#-X\"A9'!1-&!!!!!!!!"
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
"!!!!!!!!!!%\"!A1'!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!QQ>@8W$\\/8C"
"Z_(>^P0Q`````P\\_`P\\_`P\\_`P\\_`P\\_`P\\_`P\\_`P\\_`P\\_`P\\_`P\\_`P\\_`P\\_"
"`P\\_`P\\_`P\\_`P\\_`P\\_`P\\_`P\\_`P\\_`P\\_```_````D:'5%CE\\!Q5&\"!M2!!!!"
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
"!!!!!!!!!!%\"!A5)!!!!!!!!!!%#!A1'!!%#!!!!!!!!!!!!!!9/15>6Y><5Y.85"
"Z.X=`@X]`P\\_`P\\_`P\\_`P\\_`P\\_`P\\_`P\\_`P\\_`P\\_`P\\_`P\\_`P\\_`P\\_`P\\_"
"`P\\_`P\\_`P\\_`P\\_`P\\_`P\\_`P\\_`P\\_`P\\_`P\\_`@`_````LK[W'SE`#\"!;!!!!"
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
"!!!!!!!!!!!!!!!!!!!!!!!!!!%\"\"AQ4!!!!!!!!!!!!!A9+)T2.RLW_Y>D:W^85"
"^`4T`P\\_`P\\_`P\\_`P\\_`P\\_`P\\_`P\\_`P\\_`P\\_`P\\_`P\\_`P\\_`P\\_`P\\_`P\\_"
"`P\\_`P\\_`P\\_`P\\_`P\\_`P\\_`P\\_`P\\_`P\\_`P\\_`P\\_`@X^`@X\\G*_H&SI`!!!!"
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
"";

Binary file not shown.

@ -1,111 +0,0 @@
/*
* Copyright (C) 2018 bzt (bztsrc@github)
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use, copy,
* modify, merge, publish, distribute, sublicense, and/or sell copies
* of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
*/
#include "uart.h"
#include "mbox.h"
#include "homer.h"
unsigned int width, height, pitch;
unsigned char *lfb;
/**
* Set screen resolution to 1024x768
*/
void lfb_init()
{
mbox[0] = 35*4;
mbox[1] = MBOX_REQUEST;
mbox[2] = 0x48003; //set phy wh
mbox[3] = 8;
mbox[4] = 8;
mbox[5] = 1024; //FrameBufferInfo.width
mbox[6] = 768; //FrameBufferInfo.height
mbox[7] = 0x48004; //set virt wh
mbox[8] = 8;
mbox[9] = 8;
mbox[10] = 1024; //FrameBufferInfo.virtual_width
mbox[11] = 768; //FrameBufferInfo.virtual_height
mbox[12] = 0x48009; //set virt offset
mbox[13] = 8;
mbox[14] = 8;
mbox[15] = 0; //FrameBufferInfo.x_offset
mbox[16] = 0; //FrameBufferInfo.y.offset
mbox[17] = 0x48005; //set depth
mbox[18] = 4;
mbox[19] = 4;
mbox[20] = 32; //FrameBufferInfo.depth
mbox[21] = 0x48006; //set pixel order
mbox[22] = 4;
mbox[23] = 4;
mbox[24] = 1; //RGB, not BGR preferably
mbox[25] = 0x40001; //get framebuffer, gets alignment on request
mbox[26] = 8;
mbox[27] = 8;
mbox[28] = 4096; //FrameBufferInfo.pointer
mbox[29] = 0; //FrameBufferInfo.size
mbox[30] = 0x40008; //get pitch
mbox[31] = 4;
mbox[32] = 4;
mbox[33] = 0; //FrameBufferInfo.pitch
mbox[34] = MBOX_TAG_LAST;
if(mbox_call(MBOX_CH_PROP) && mbox[20]==32 && mbox[28]!=0) {
mbox[28]&=0x3FFFFFFF;
width=mbox[5];
height=mbox[6];
pitch=mbox[33];
lfb=(void*)((unsigned long)mbox[28]);
} else {
uart_puts("Unable to set screen resolution to 1024x768x32\n");
}
}
/**
* Show a picture
*/
void lfb_showpicture()
{
int x,y;
unsigned char *ptr=lfb;
char *data=homer_data, pixel[4];
ptr += (height-homer_height)/2*pitch + (width-homer_width)*2;
for(y=0;y<homer_height;y++) {
for(x=0;x<homer_width;x++) {
HEADER_PIXEL(data, pixel);
*((unsigned int*)ptr)=*((unsigned int *)&pixel);
ptr+=4;
}
ptr+=pitch-homer_width*4;
}
}

@ -1,27 +0,0 @@
/*
* Copyright (C) 2018 bzt (bztsrc@github)
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use, copy,
* modify, merge, publish, distribute, sublicense, and/or sell copies
* of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
*/
void lfb_init();
void lfb_showpicture();

@ -1,44 +0,0 @@
/*
* Copyright (C) 2018 bzt (bztsrc@github)
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use, copy,
* modify, merge, publish, distribute, sublicense, and/or sell copies
* of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
*/
SECTIONS
{
. = 0x80000;
.text : { KEEP(*(.text.boot)) *(.text .text.* .gnu.linkonce.t*) }
.rodata : { *(.rodata .rodata.* .gnu.linkonce.r*) }
PROVIDE(_data = .);
.data : { *(.data .data.* .gnu.linkonce.d*) }
.bss (NOLOAD) : {
. = ALIGN(16);
__bss_start = .;
*(.bss .bss.*)
*(COMMON)
__bss_end = .;
}
_end = .;
/DISCARD/ : { *(.comment) *(.gnu*) *(.note*) *(.eh_frame*) }
}
__bss_size = (__bss_end - __bss_start)>>3;

@ -1,42 +0,0 @@
/*
* Copyright (C) 2018 bzt (bztsrc@github)
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use, copy,
* modify, merge, publish, distribute, sublicense, and/or sell copies
* of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
*/
#include "uart.h"
#include "lfb.h"
void main()
{
// set up serial console and linear frame buffer
uart_init();
lfb_init();
// display a pixmap
lfb_showpicture();
// echo everything back
while(1) {
uart_send(uart_getc());
}
}

@ -1,63 +0,0 @@
/*
* Copyright (C) 2018 bzt (bztsrc@github)
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use, copy,
* modify, merge, publish, distribute, sublicense, and/or sell copies
* of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
*/
#include "gpio.h"
/* mailbox message buffer */
volatile unsigned int __attribute__((aligned(16))) mbox[36];
#define VIDEOCORE_MBOX (MMIO_BASE+0x0000B880)
#define MBOX_READ ((volatile unsigned int*)(VIDEOCORE_MBOX+0x0))
#define MBOX_POLL ((volatile unsigned int*)(VIDEOCORE_MBOX+0x10))
#define MBOX_SENDER ((volatile unsigned int*)(VIDEOCORE_MBOX+0x14))
#define MBOX_STATUS ((volatile unsigned int*)(VIDEOCORE_MBOX+0x18))
#define MBOX_CONFIG ((volatile unsigned int*)(VIDEOCORE_MBOX+0x1C))
#define MBOX_WRITE ((volatile unsigned int*)(VIDEOCORE_MBOX+0x20))
#define MBOX_RESPONSE 0x80000000
#define MBOX_FULL 0x80000000
#define MBOX_EMPTY 0x40000000
/**
* Make a mailbox call. Returns 0 on failure, non-zero on success
*/
int mbox_call(unsigned char ch)
{
unsigned int r;
/* wait until we can write to the mailbox */
do{asm volatile("nop");}while(*MBOX_STATUS & MBOX_FULL);
/* write the address of our message to the mailbox with channel identifier */
*MBOX_WRITE = (((unsigned int)((unsigned long)&mbox)&~0xF) | (ch&0xF));
/* now wait for the response */
while(1) {
/* is there a response? */
do{asm volatile("nop");}while(*MBOX_STATUS & MBOX_EMPTY);
r=*MBOX_READ;
/* is it a response to our message? */
if((unsigned char)(r&0xF)==ch && (r&~0xF)==(unsigned int)((unsigned long)&mbox))
/* is it a valid successful response? */
return mbox[1]==MBOX_RESPONSE;
}
return 0;
}

@ -1,47 +0,0 @@
/*
* Copyright (C) 2018 bzt (bztsrc@github)
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use, copy,
* modify, merge, publish, distribute, sublicense, and/or sell copies
* of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
*/
/* a properly aligned buffer */
extern volatile unsigned int mbox[36];
#define MBOX_REQUEST 0
/* channels */
#define MBOX_CH_POWER 0
#define MBOX_CH_FB 1
#define MBOX_CH_VUART 2
#define MBOX_CH_VCHIQ 3
#define MBOX_CH_LEDS 4
#define MBOX_CH_BTNS 5
#define MBOX_CH_TOUCH 6
#define MBOX_CH_COUNT 7
#define MBOX_CH_PROP 8
/* tags */
#define MBOX_TAG_SETPOWER 0x28001
#define MBOX_TAG_SETCLKRATE 0x38002
#define MBOX_TAG_LAST 0
int mbox_call(unsigned char ch);

@ -1,55 +0,0 @@
/*
* Copyright (C) 2018 bzt (bztsrc@github)
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use, copy,
* modify, merge, publish, distribute, sublicense, and/or sell copies
* of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
*/
.section ".text.boot"
.global _start
_start:
// read cpu id, stop slave cores
mrs x1, mpidr_el1
and x1, x1, #3
cbz x1, 2f
// cpu id > 0, stop
1: wfe
b 1b
2: // cpu id == 0
// set stack before our code
ldr x1, =_start
mov sp, x1
// clear bss
ldr x1, =__bss_start
ldr w2, =__bss_size
3: cbz w2, 4f
str xzr, [x1], #8
sub w2, w2, #1
cbnz w2, 3b
// jump to C code, should not return
4: bl main
// for failsafe, halt this core too
b 1b

@ -1,127 +0,0 @@
/*
* Copyright (C) 2018 bzt (bztsrc@github)
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use, copy,
* modify, merge, publish, distribute, sublicense, and/or sell copies
* of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
*/
#include "gpio.h"
#include "mbox.h"
#include "delays.h"
/* PL011 UART registers */
#define UART0_DR ((volatile unsigned int*)(MMIO_BASE+0x00201000))
#define UART0_FR ((volatile unsigned int*)(MMIO_BASE+0x00201018))
#define UART0_IBRD ((volatile unsigned int*)(MMIO_BASE+0x00201024))
#define UART0_FBRD ((volatile unsigned int*)(MMIO_BASE+0x00201028))
#define UART0_LCRH ((volatile unsigned int*)(MMIO_BASE+0x0020102C))
#define UART0_CR ((volatile unsigned int*)(MMIO_BASE+0x00201030))
#define UART0_IMSC ((volatile unsigned int*)(MMIO_BASE+0x00201038))
#define UART0_ICR ((volatile unsigned int*)(MMIO_BASE+0x00201044))
/**
* Set baud rate and characteristics (115200 8N1) and map to GPIO
*/
void uart_init()
{
register unsigned int r;
/* initialize UART */
*UART0_CR = 0; // turn off UART0
/* set up clock for consistent divisor values */
mbox[0] = 8*4;
mbox[1] = MBOX_REQUEST;
mbox[2] = MBOX_TAG_SETCLKRATE; // set clock rate
mbox[3] = 12;
mbox[4] = 8;
mbox[5] = 2; // UART clock
mbox[6] = 4000000; // 4Mhz
mbox[7] = MBOX_TAG_LAST;
mbox_call(MBOX_CH_PROP);
/* map UART0 to GPIO pins */
r=*GPFSEL1;
r&=~((7<<12)|(7<<15)); // gpio14, gpio15
r|=(4<<12)|(4<<15); // alt0
*GPFSEL1 = r;
*GPPUD = 0; // enable pins 14 and 15
wait_cycles(150);
*GPPUDCLK0 = (1<<14)|(1<<15);
wait_cycles(150);
*GPPUDCLK0 = 0; // flush GPIO setup
*UART0_ICR = 0x7FF; // clear interrupts
*UART0_IBRD = 2; // 115200 baud
*UART0_FBRD = 0xB;
*UART0_LCRH = 0b11<<5; // 8n1
*UART0_CR = 0x301; // enable Tx, Rx, FIFO
}
/**
* Send a character
*/
void uart_send(unsigned int c) {
/* wait until we can send */
do{asm volatile("nop");}while(*UART0_FR&0x20);
/* write the character to the buffer */
*UART0_DR=c;
}
/**
* Receive a character
*/
char uart_getc() {
char r;
/* wait until something is in the buffer */
do{asm volatile("nop");}while(*UART0_FR&0x10);
/* read it and return */
r=(char)(*UART0_DR);
/* convert carrige return to newline */
return r=='\r'?'\n':r;
}
/**
* Display a string
*/
void uart_puts(char *s) {
while(*s) {
/* convert newline to carrige return + newline */
if(*s=='\n')
uart_send('\r');
uart_send(*s++);
}
}
/**
* Display a binary value in hexadecimal
*/
void uart_hex(unsigned int d) {
unsigned int n;
int c;
for(c=28;c>=0;c-=4) {
// get highest tetrad
n=(d>>c)&0xF;
// 0-9 => '0'-'9', 10-15 => 'A'-'F'
n+=n>9?0x37:0x30;
uart_send(n);
}
}

@ -1,30 +0,0 @@
/*
* Copyright (C) 2018 bzt (bztsrc@github)
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use, copy,
* modify, merge, publish, distribute, sublicense, and/or sell copies
* of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
*/
void uart_init();
void uart_send(unsigned int c);
char uart_getc();
void uart_puts(char *s);
void uart_hex(unsigned int d);

@ -1,46 +0,0 @@
#
# Copyright (C) 2018 bzt (bztsrc@github)
#
# Permission is hereby granted, free of charge, to any person
# obtaining a copy of this software and associated documentation
# files (the "Software"), to deal in the Software without
# restriction, including without limitation the rights to use, copy,
# modify, merge, publish, distribute, sublicense, and/or sell copies
# of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be
# included in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
# HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
# DEALINGS IN THE SOFTWARE.
#
#
SRCS = $(wildcard *.c)
OBJS = $(SRCS:.c=.o)
CFLAGS = -Wall -O2 -ffreestanding -nostdinc -nostdlib -nostartfiles
all: clean kernel8.img
start.o: start.S
aarch64-elf-gcc $(CFLAGS) -c start.S -o start.o
%.o: %.c
aarch64-elf-gcc $(CFLAGS) -c $< -o $@
font.o: font.psf
aarch64-elf-ld -r -b binary -o font.o font.psf
kernel8.img: start.o font.o $(OBJS)
aarch64-elf-ld -nostdlib -nostartfiles start.o font.o $(OBJS) -T link.ld -o kernel8.elf
aarch64-elf-objcopy -O binary kernel8.elf kernel8.img
clean:
rm kernel8.elf *.o >/dev/null 2>/dev/null || true

@ -1,40 +0,0 @@
Oktatóanyag 0A - PC Screen Font
===============================
Képeket kirakni poénos, de mindenképpen szükség van többre, karakterek megjelenítésére is. Alapvetően
a fontok nem mások, mint képek minden karakterhez (glyphek). Ehhez az oktatóanyaghoz azt a PC Screen Font
formátumot választottam, amit a Linux Console csomag is használ.
Lfb.h, lfb.c
------------
`lfb_init()` beállítja a felbontást, mélységet, színcsatornákat és visszaadja a framebuffer címét.
`lfb_print(x,y,s)` megjelenít egy szöveget a képernyőn.
Font.psf
--------
A font fájl. Bármelyik használható a /usr/share/kbd/consolefonts mappából. Unicode táblákat nem támogatja.
A karakterek glypehnek való megfeleltetése ezen táblázat által (a meglévő egy-az-egyhez megfeleltetés helyett)
házi feladat, Rád van bízva. Ezt a fontot az eredeti IBM PC VGA ROM-jában található 8x16 fontkészletből generáltam,
és 127 glyphet tartalmaz.
Makefile
--------
Egy új object-et adtam hozzá, ami a psf-ből generálódik. Jó példa arra, hogyan kell bináris fájlt behúzni és
hivatkozni C forrásból. A következő parancsot használtam a cimke nevének kiderítésére:
```sh
$ aarch64-elf-readelf -s font.o
... kimenet törölve az átláthatóság miatt ...
2: 0000000000000820 0 NOTYPE GLOBAL DEFAULT 1 _binary_font_psf_end
3: 0000000000000000 0 NOTYPE GLOBAL DEFAULT 1 _binary_font_psf_start
4: 0000000000000820 0 NOTYPE GLOBAL DEFAULT ABS _binary_font_psf_size
```
Main
----
Nagyon egyszerű. Beállítjuk a felbontást és megjelenítjük a szöveget.

@ -1,39 +0,0 @@
Tutorial 0A - PC Screen Font
============================
Drawing pixmaps is fun, but definitely there's a need to display characters as well. Basicaly fonts
are nothing more than bitmaps for each character. For this tutorial I choosed PC Screen Font format,
the same Linux Console uses.
Lfb.h, lfb.c
------------
`lfb_init()` sets up resolution, depth, and color channel order. Also queries framebuffer's address.
`lfb_print(x,y,s)` displays a string on screen.
Font.psf
--------
The font file. Use any file from /usr/share/kbd/consolefonts. Unicode table is not supported. Translating
characters to glyph index using that table (instead of one-to-one relation) is a homework for you. This font
is generated from the original IBM PC VGA 8x16 Font ROM, and includes 127 glyphs.
Makefile
--------
I've added a new object file, generated from the psf. It's a good example of how to include and reference
a binary file in C. I've used the following command to find out the label:
```sh
$ aarch64-elf-readelf -s font.o
... output removed for clearity ...
2: 0000000000000820 0 NOTYPE GLOBAL DEFAULT 1 _binary_font_psf_end
3: 0000000000000000 0 NOTYPE GLOBAL DEFAULT 1 _binary_font_psf_start
4: 0000000000000820 0 NOTYPE GLOBAL DEFAULT ABS _binary_font_psf_size
```
Main
----
Very simple. We set the resolution and display the string.

@ -1,81 +0,0 @@
/*
* Copyright (C) 2018 bzt (bztsrc@github)
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use, copy,
* modify, merge, publish, distribute, sublicense, and/or sell copies
* of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
*/
#include "gpio.h"
#define SYSTMR_LO ((volatile unsigned int*)(MMIO_BASE+0x00003004))
#define SYSTMR_HI ((volatile unsigned int*)(MMIO_BASE+0x00003008))
/**
* Wait N CPU cycles (ARM CPU only)
*/
void wait_cycles(unsigned int n)
{
if(n) while(n--) { asm volatile("nop"); }
}
/**
* Wait N microsec (ARM CPU only)
*/
void wait_msec(unsigned int n)
{
register unsigned long f, t, r;
// get the current counter frequency
asm volatile ("mrs %0, cntfrq_el0" : "=r"(f));
// read the current counter
asm volatile ("mrs %0, cntpct_el0" : "=r"(t));
// calculate expire value for counter
t+=((f/1000)*n)/1000;
do{asm volatile ("mrs %0, cntpct_el0" : "=r"(r));}while(r<t);
}
/**
* Get System Timer's counter
*/
unsigned long get_system_timer()
{
unsigned int h=-1, l;
// we must read MMIO area as two separate 32 bit reads
h=*SYSTMR_HI;
l=*SYSTMR_LO;
// we have to repeat it if high word changed during read
if(h!=*SYSTMR_HI) {
h=*SYSTMR_HI;
l=*SYSTMR_LO;
}
// compose long int value
return ((unsigned long) h << 32) | l;
}
/**
* Wait N microsec (with BCM System Timer)
*/
void wait_msec_st(unsigned int n)
{
unsigned long t=get_system_timer();
// we must check if it's non-zero, because qemu does not emulate
// system timer, and returning constant zero would mean infinite loop
if(t) while(get_system_timer() < t+n);
}

@ -1,29 +0,0 @@
/*
* Copyright (C) 2018 bzt (bztsrc@github)
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use, copy,
* modify, merge, publish, distribute, sublicense, and/or sell copies
* of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
*/
void wait_cycles(unsigned int n);
void wait_msec(unsigned int n);
unsigned long get_system_timer();
void wait_msec_st(unsigned int n);

Binary file not shown.

@ -1,45 +0,0 @@
/*
* Copyright (C) 2018 bzt (bztsrc@github)
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use, copy,
* modify, merge, publish, distribute, sublicense, and/or sell copies
* of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
*/
#define MMIO_BASE 0x3F000000
#define GPFSEL0 ((volatile unsigned int*)(MMIO_BASE+0x00200000))
#define GPFSEL1 ((volatile unsigned int*)(MMIO_BASE+0x00200004))
#define GPFSEL2 ((volatile unsigned int*)(MMIO_BASE+0x00200008))
#define GPFSEL3 ((volatile unsigned int*)(MMIO_BASE+0x0020000C))
#define GPFSEL4 ((volatile unsigned int*)(MMIO_BASE+0x00200010))
#define GPFSEL5 ((volatile unsigned int*)(MMIO_BASE+0x00200014))
#define GPSET0 ((volatile unsigned int*)(MMIO_BASE+0x0020001C))
#define GPSET1 ((volatile unsigned int*)(MMIO_BASE+0x00200020))
#define GPCLR0 ((volatile unsigned int*)(MMIO_BASE+0x00200028))
#define GPLEV0 ((volatile unsigned int*)(MMIO_BASE+0x00200034))
#define GPLEV1 ((volatile unsigned int*)(MMIO_BASE+0x00200038))
#define GPEDS0 ((volatile unsigned int*)(MMIO_BASE+0x00200040))
#define GPEDS1 ((volatile unsigned int*)(MMIO_BASE+0x00200044))
#define GPHEN0 ((volatile unsigned int*)(MMIO_BASE+0x00200064))
#define GPHEN1 ((volatile unsigned int*)(MMIO_BASE+0x00200068))
#define GPPUD ((volatile unsigned int*)(MMIO_BASE+0x00200094))
#define GPPUDCLK0 ((volatile unsigned int*)(MMIO_BASE+0x00200098))
#define GPPUDCLK1 ((volatile unsigned int*)(MMIO_BASE+0x0020009C))

Binary file not shown.

@ -1,150 +0,0 @@
/*
* Copyright (C) 2018 bzt (bztsrc@github)
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use, copy,
* modify, merge, publish, distribute, sublicense, and/or sell copies
* of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
*/
#include "uart.h"
#include "mbox.h"
/* PC Screen Font as used by Linux Console */
typedef struct {
unsigned int magic;
unsigned int version;
unsigned int headersize;
unsigned int flags;
unsigned int numglyph;
unsigned int bytesperglyph;
unsigned int height;
unsigned int width;
unsigned char glyphs;
} __attribute__((packed)) psf_t;
extern volatile unsigned char _binary_font_psf_start;
unsigned int width, height, pitch;
unsigned char *lfb;
/**
* Set screen resolution to 1024x768
*/
void lfb_init()
{
mbox[0] = 35*4;
mbox[1] = MBOX_REQUEST;
mbox[2] = 0x48003; //set phy wh
mbox[3] = 8;
mbox[4] = 8;
mbox[5] = 1024; //FrameBufferInfo.width
mbox[6] = 768; //FrameBufferInfo.height
mbox[7] = 0x48004; //set virt wh
mbox[8] = 8;
mbox[9] = 8;
mbox[10] = 1024; //FrameBufferInfo.virtual_width
mbox[11] = 768; //FrameBufferInfo.virtual_height
mbox[12] = 0x48009; //set virt offset
mbox[13] = 8;
mbox[14] = 8;
mbox[15] = 0; //FrameBufferInfo.x_offset
mbox[16] = 0; //FrameBufferInfo.y.offset
mbox[17] = 0x48005; //set depth
mbox[18] = 4;
mbox[19] = 4;
mbox[20] = 32; //FrameBufferInfo.depth
mbox[21] = 0x48006; //set pixel order
mbox[22] = 4;
mbox[23] = 4;
mbox[24] = 1; //RGB, not BGR preferably
mbox[25] = 0x40001; //get framebuffer, gets alignment on request
mbox[26] = 8;
mbox[27] = 8;
mbox[28] = 4096; //FrameBufferInfo.pointer
mbox[29] = 0; //FrameBufferInfo.size
mbox[30] = 0x40008; //get pitch
mbox[31] = 4;
mbox[32] = 4;
mbox[33] = 0; //FrameBufferInfo.pitch
mbox[34] = MBOX_TAG_LAST;
if(mbox_call(MBOX_CH_PROP) && mbox[20]==32 && mbox[28]!=0) {
mbox[28]&=0x3FFFFFFF;
width=mbox[5];
height=mbox[6];
pitch=mbox[33];
lfb=(void*)((unsigned long)mbox[28]);
} else {
uart_puts("Unable to set screen resolution to 1024x768x32\n");
}
}
/**
* Display a string
*/
void lfb_print(int x, int y, char *s)
{
// get our font
psf_t *font = (psf_t*)&_binary_font_psf_start;
// draw next character if it's not zero
while(*s) {
// get the offset of the glyph. Need to adjust this to support unicode table
unsigned char *glyph = (unsigned char*)&_binary_font_psf_start +
font->headersize + (*((unsigned char*)s)<font->numglyph?*s:0)*font->bytesperglyph;
// calculate the offset on screen
int offs = (y * font->height * pitch) + (x * (font->width+1) * 4);
// variables
int i,j, line,mask, bytesperline=(font->width+7)/8;
// handle carrige return
if(*s=='\r') {
x=0;
} else
// new line
if(*s=='\n') {
x=0; y++;
} else {
// display a character
for(j=0;j<font->height;j++){
// display one row
line=offs;
mask=1<<(font->width-1);
for(i=0;i<font->width;i++){
// if bit set, we use white color, otherwise black
*((unsigned int*)(lfb + line))=((int)*glyph) & mask?0xFFFFFF:0;
mask>>=1;
line+=4;
}
// adjust to next line
glyph+=bytesperline;
offs+=pitch;
}
x++;
}
// next character
s++;
}
}

@ -1,27 +0,0 @@
/*
* Copyright (C) 2018 bzt (bztsrc@github)
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use, copy,
* modify, merge, publish, distribute, sublicense, and/or sell copies
* of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
*/
void lfb_init();
void lfb_print(int x, int y, char *s);

@ -1,44 +0,0 @@
/*
* Copyright (C) 2018 bzt (bztsrc@github)
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use, copy,
* modify, merge, publish, distribute, sublicense, and/or sell copies
* of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
*/
SECTIONS
{
. = 0x80000;
.text : { KEEP(*(.text.boot)) *(.text .text.* .gnu.linkonce.t*) }
.rodata : { *(.rodata .rodata.* .gnu.linkonce.r*) }
PROVIDE(_data = .);
.data : { *(.data .data.* .gnu.linkonce.d*) }
.bss (NOLOAD) : {
. = ALIGN(16);
__bss_start = .;
*(.bss .bss.*)
*(COMMON)
__bss_end = .;
}
_end = .;
/DISCARD/ : { *(.comment) *(.gnu*) *(.note*) *(.eh_frame*) }
}
__bss_size = (__bss_end - __bss_start)>>3;

@ -1,42 +0,0 @@
/*
* Copyright (C) 2018 bzt (bztsrc@github)
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use, copy,
* modify, merge, publish, distribute, sublicense, and/or sell copies
* of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
*/
#include "uart.h"
#include "lfb.h"
void main()
{
// set up serial console and linear frame buffer
uart_init();
lfb_init();
// display a string on screen
lfb_print(10, 5, "Hello World!");
// echo everything back
while(1) {
uart_send(uart_getc());
}
}

@ -1,63 +0,0 @@
/*
* Copyright (C) 2018 bzt (bztsrc@github)
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use, copy,
* modify, merge, publish, distribute, sublicense, and/or sell copies
* of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
*/
#include "gpio.h"
/* mailbox message buffer */
volatile unsigned int __attribute__((aligned(16))) mbox[36];
#define VIDEOCORE_MBOX (MMIO_BASE+0x0000B880)
#define MBOX_READ ((volatile unsigned int*)(VIDEOCORE_MBOX+0x0))
#define MBOX_POLL ((volatile unsigned int*)(VIDEOCORE_MBOX+0x10))
#define MBOX_SENDER ((volatile unsigned int*)(VIDEOCORE_MBOX+0x14))
#define MBOX_STATUS ((volatile unsigned int*)(VIDEOCORE_MBOX+0x18))
#define MBOX_CONFIG ((volatile unsigned int*)(VIDEOCORE_MBOX+0x1C))
#define MBOX_WRITE ((volatile unsigned int*)(VIDEOCORE_MBOX+0x20))
#define MBOX_RESPONSE 0x80000000
#define MBOX_FULL 0x80000000
#define MBOX_EMPTY 0x40000000
/**
* Make a mailbox call. Returns 0 on failure, non-zero on success
*/
int mbox_call(unsigned char ch)
{
unsigned int r;
/* wait until we can write to the mailbox */
do{asm volatile("nop");}while(*MBOX_STATUS & MBOX_FULL);
/* write the address of our message to the mailbox with channel identifier */
*MBOX_WRITE = (((unsigned int)((unsigned long)&mbox)&~0xF) | (ch&0xF));
/* now wait for the response */
while(1) {
/* is there a response? */
do{asm volatile("nop");}while(*MBOX_STATUS & MBOX_EMPTY);
r=*MBOX_READ;
/* is it a response to our message? */
if((unsigned char)(r&0xF)==ch && (r&~0xF)==(unsigned int)((unsigned long)&mbox))
/* is it a valid successful response? */
return mbox[1]==MBOX_RESPONSE;
}
return 0;
}

@ -1,47 +0,0 @@
/*
* Copyright (C) 2018 bzt (bztsrc@github)
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use, copy,
* modify, merge, publish, distribute, sublicense, and/or sell copies
* of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
*/
/* a properly aligned buffer */
extern volatile unsigned int mbox[36];
#define MBOX_REQUEST 0
/* channels */
#define MBOX_CH_POWER 0
#define MBOX_CH_FB 1
#define MBOX_CH_VUART 2
#define MBOX_CH_VCHIQ 3
#define MBOX_CH_LEDS 4
#define MBOX_CH_BTNS 5
#define MBOX_CH_TOUCH 6
#define MBOX_CH_COUNT 7
#define MBOX_CH_PROP 8
/* tags */
#define MBOX_TAG_SETPOWER 0x28001
#define MBOX_TAG_SETCLKRATE 0x38002
#define MBOX_TAG_LAST 0
int mbox_call(unsigned char ch);

@ -1,55 +0,0 @@
/*
* Copyright (C) 2018 bzt (bztsrc@github)
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use, copy,
* modify, merge, publish, distribute, sublicense, and/or sell copies
* of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
*/
.section ".text.boot"
.global _start
_start:
// read cpu id, stop slave cores
mrs x1, mpidr_el1
and x1, x1, #3
cbz x1, 2f
// cpu id > 0, stop
1: wfe
b 1b
2: // cpu id == 0
// set stack before our code
ldr x1, =_start
mov sp, x1
// clear bss
ldr x1, =__bss_start
ldr w2, =__bss_size
3: cbz w2, 4f
str xzr, [x1], #8
sub w2, w2, #1
cbnz w2, 3b
// jump to C code, should not return
4: bl main
// for failsafe, halt this core too
b 1b

@ -1,127 +0,0 @@
/*
* Copyright (C) 2018 bzt (bztsrc@github)
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use, copy,
* modify, merge, publish, distribute, sublicense, and/or sell copies
* of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
*/
#include "gpio.h"
#include "mbox.h"
#include "delays.h"
/* PL011 UART registers */
#define UART0_DR ((volatile unsigned int*)(MMIO_BASE+0x00201000))
#define UART0_FR ((volatile unsigned int*)(MMIO_BASE+0x00201018))
#define UART0_IBRD ((volatile unsigned int*)(MMIO_BASE+0x00201024))
#define UART0_FBRD ((volatile unsigned int*)(MMIO_BASE+0x00201028))
#define UART0_LCRH ((volatile unsigned int*)(MMIO_BASE+0x0020102C))
#define UART0_CR ((volatile unsigned int*)(MMIO_BASE+0x00201030))
#define UART0_IMSC ((volatile unsigned int*)(MMIO_BASE+0x00201038))
#define UART0_ICR ((volatile unsigned int*)(MMIO_BASE+0x00201044))
/**
* Set baud rate and characteristics (115200 8N1) and map to GPIO
*/
void uart_init()
{
register unsigned int r;
/* initialize UART */
*UART0_CR = 0; // turn off UART0
/* set up clock for consistent divisor values */
mbox[0] = 8*4;
mbox[1] = MBOX_REQUEST;
mbox[2] = MBOX_TAG_SETCLKRATE; // set clock rate
mbox[3] = 12;
mbox[4] = 8;
mbox[5] = 2; // UART clock
mbox[6] = 4000000; // 4Mhz
mbox[7] = MBOX_TAG_LAST;
mbox_call(MBOX_CH_PROP);
/* map UART0 to GPIO pins */
r=*GPFSEL1;
r&=~((7<<12)|(7<<15)); // gpio14, gpio15
r|=(4<<12)|(4<<15); // alt0
*GPFSEL1 = r;
*GPPUD = 0; // enable pins 14 and 15
wait_cycles(150);
*GPPUDCLK0 = (1<<14)|(1<<15);
wait_cycles(150);
*GPPUDCLK0 = 0; // flush GPIO setup
*UART0_ICR = 0x7FF; // clear interrupts
*UART0_IBRD = 2; // 115200 baud
*UART0_FBRD = 0xB;
*UART0_LCRH = 0b11<<5; // 8n1
*UART0_CR = 0x301; // enable Tx, Rx, FIFO
}
/**
* Send a character
*/
void uart_send(unsigned int c) {
/* wait until we can send */
do{asm volatile("nop");}while(*UART0_FR&0x20);
/* write the character to the buffer */
*UART0_DR=c;
}
/**
* Receive a character
*/
char uart_getc() {
char r;
/* wait until something is in the buffer */
do{asm volatile("nop");}while(*UART0_FR&0x10);
/* read it and return */
r=(char)(*UART0_DR);
/* convert carrige return to newline */
return r=='\r'?'\n':r;
}
/**
* Display a string
*/
void uart_puts(char *s) {
while(*s) {
/* convert newline to carrige return + newline */
if(*s=='\n')
uart_send('\r');
uart_send(*s++);
}
}
/**
* Display a binary value in hexadecimal
*/
void uart_hex(unsigned int d) {
unsigned int n;
int c;
for(c=28;c>=0;c-=4) {
// get highest tetrad
n=(d>>c)&0xF;
// 0-9 => '0'-'9', 10-15 => 'A'-'F'
n+=n>9?0x37:0x30;
uart_send(n);
}
}

@ -1,30 +0,0 @@
/*
* Copyright (C) 2018 bzt (bztsrc@github)
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use, copy,
* modify, merge, publish, distribute, sublicense, and/or sell copies
* of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
*/
void uart_init();
void uart_send(unsigned int c);
char uart_getc();
void uart_puts(char *s);
void uart_hex(unsigned int d);

@ -1,43 +0,0 @@
#
# Copyright (C) 2018 bzt (bztsrc@github)
#
# Permission is hereby granted, free of charge, to any person
# obtaining a copy of this software and associated documentation
# files (the "Software"), to deal in the Software without
# restriction, including without limitation the rights to use, copy,
# modify, merge, publish, distribute, sublicense, and/or sell copies
# of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be
# included in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
# HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
# DEALINGS IN THE SOFTWARE.
#
#
SRCS = $(wildcard *.c)
OBJS = $(SRCS:.c=.o)
CFLAGS = -Wall -O2 -ffreestanding -nostdinc -nostdlib -nostartfiles
all: clean kernel8.img
start.o: start.S
aarch64-elf-gcc $(CFLAGS) -c start.S -o start.o
%.o: %.c
aarch64-elf-gcc $(CFLAGS) -c $< -o $@
kernel8.img: start.o $(OBJS)
aarch64-elf-ld -nostdlib -nostartfiles start.o $(OBJS) -T link.ld -o kernel8.elf
aarch64-elf-objcopy -O binary kernel8.elf kernel8.img
clean:
rm kernel8.elf *.o >/dev/null 2>/dev/null || true

@ -1,22 +0,0 @@
Oktatóanyag 0B - Szektor Beolvasás
==================================
Ezidáig minden adatot (kép, font) hozzálinkeltünk a kernelhez. Itt az ideje, hogy adatot olvassunk be
az SD kártyáról. Ebben az oktatóanyagban egy igazi meghajtót implementálunk a szektor beolvasásához.
Sd.h, sd.c
------------
Nos, jó lenne, ha lenne levelesláda szektorok olvasására és írására, de nincs. Ezért nekünk kell direktben
beszélni az EMMC-vel, ami trükkös és unalmas feladat. Különböző kártyákkal is törődnünk kell. De végül,
rendelkezésre áll két funkció.
`sd_init()` inicializálja az EMMC-t SD kártya olvasáshoz.
`sd_readblock(lba,buffer,num)` beolvas num blokkot (szektort) az SD kártyáról a buffer-be lba-tól kezdve.
Main
----
A blokkot a bss szegmens utánra töltjük be, majd kidumpoljuk a konzolra. A beolvasás funkció részletes
üzeneteket ír ki arról, hogy épp mit kommunikál az EMMC vezérlővel.

@ -1,22 +0,0 @@
Tutorial 0B - Read Sector
=========================
So far we have linked our data (pixmap, font) to the kernel image. It is time to read data from the
SD card. For this tutorial we're implementing a real driver for read sector function.
Sd.h, sd.c
------------
Well, it would be nice to have a mailbox for reading and writing sectors, but there isn't. So we have to
talk directly to the EMMC, which is tricky and boring. We have to handle all kinds of cards. But finally,
we have two function.
`sd_init()` initialize EMMC for SD card read.
`sd_readblock(lba,buffer,num)` read num blocks (sectors) from the SD card into buffer starting at sector lba.
Main
----
We read a block after the bss segment in memory, and then we dump it to the console. The read function will
display detailed information on the EMMC communication.

@ -1,81 +0,0 @@
/*
* Copyright (C) 2018 bzt (bztsrc@github)
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use, copy,
* modify, merge, publish, distribute, sublicense, and/or sell copies
* of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
*/
#include "gpio.h"
#define SYSTMR_LO ((volatile unsigned int*)(MMIO_BASE+0x00003004))
#define SYSTMR_HI ((volatile unsigned int*)(MMIO_BASE+0x00003008))
/**
* Wait N CPU cycles (ARM CPU only)
*/
void wait_cycles(unsigned int n)
{
if(n) while(n--) { asm volatile("nop"); }
}
/**
* Wait N microsec (ARM CPU only)
*/
void wait_msec(unsigned int n)
{
register unsigned long f, t, r;
// get the current counter frequency
asm volatile ("mrs %0, cntfrq_el0" : "=r"(f));
// read the current counter
asm volatile ("mrs %0, cntpct_el0" : "=r"(t));
// calculate expire value for counter
t+=((f/1000)*n)/1000;
do{asm volatile ("mrs %0, cntpct_el0" : "=r"(r));}while(r<t);
}
/**
* Get System Timer's counter
*/
unsigned long get_system_timer()
{
unsigned int h=-1, l;
// we must read MMIO area as two separate 32 bit reads
h=*SYSTMR_HI;
l=*SYSTMR_LO;
// we have to repeat it if high word changed during read
if(h!=*SYSTMR_HI) {
h=*SYSTMR_HI;
l=*SYSTMR_LO;
}
// compose long int value
return ((unsigned long) h << 32) | l;
}
/**
* Wait N microsec (with BCM System Timer)
*/
void wait_msec_st(unsigned int n)
{
unsigned long t=get_system_timer();
// we must check if it's non-zero, because qemu does not emulate
// system timer, and returning constant zero would mean infinite loop
if(t) while(get_system_timer() < t+n);
}

@ -1,29 +0,0 @@
/*
* Copyright (C) 2018 bzt (bztsrc@github)
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use, copy,
* modify, merge, publish, distribute, sublicense, and/or sell copies
* of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
*/
void wait_cycles(unsigned int n);
void wait_msec(unsigned int n);
unsigned long get_system_timer();
void wait_msec_st(unsigned int n);

@ -1,45 +0,0 @@
/*
* Copyright (C) 2018 bzt (bztsrc@github)
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use, copy,
* modify, merge, publish, distribute, sublicense, and/or sell copies
* of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
*/
#define MMIO_BASE 0x3F000000
#define GPFSEL0 ((volatile unsigned int*)(MMIO_BASE+0x00200000))
#define GPFSEL1 ((volatile unsigned int*)(MMIO_BASE+0x00200004))
#define GPFSEL2 ((volatile unsigned int*)(MMIO_BASE+0x00200008))
#define GPFSEL3 ((volatile unsigned int*)(MMIO_BASE+0x0020000C))
#define GPFSEL4 ((volatile unsigned int*)(MMIO_BASE+0x00200010))
#define GPFSEL5 ((volatile unsigned int*)(MMIO_BASE+0x00200014))
#define GPSET0 ((volatile unsigned int*)(MMIO_BASE+0x0020001C))
#define GPSET1 ((volatile unsigned int*)(MMIO_BASE+0x00200020))
#define GPCLR0 ((volatile unsigned int*)(MMIO_BASE+0x00200028))
#define GPLEV0 ((volatile unsigned int*)(MMIO_BASE+0x00200034))
#define GPLEV1 ((volatile unsigned int*)(MMIO_BASE+0x00200038))
#define GPEDS0 ((volatile unsigned int*)(MMIO_BASE+0x00200040))
#define GPEDS1 ((volatile unsigned int*)(MMIO_BASE+0x00200044))
#define GPHEN0 ((volatile unsigned int*)(MMIO_BASE+0x00200064))
#define GPHEN1 ((volatile unsigned int*)(MMIO_BASE+0x00200068))
#define GPPUD ((volatile unsigned int*)(MMIO_BASE+0x00200094))
#define GPPUDCLK0 ((volatile unsigned int*)(MMIO_BASE+0x00200098))
#define GPPUDCLK1 ((volatile unsigned int*)(MMIO_BASE+0x0020009C))

Binary file not shown.

@ -1,44 +0,0 @@
/*
* Copyright (C) 2018 bzt (bztsrc@github)
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use, copy,
* modify, merge, publish, distribute, sublicense, and/or sell copies
* of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
*/
SECTIONS
{
. = 0x80000;
.text : { KEEP(*(.text.boot)) *(.text .text.* .gnu.linkonce.t*) }
.rodata : { *(.rodata .rodata.* .gnu.linkonce.r*) }
PROVIDE(_data = .);
.data : { *(.data .data.* .gnu.linkonce.d*) }
.bss (NOLOAD) : {
. = ALIGN(16);
__bss_start = .;
*(.bss .bss.*)
*(COMMON)
__bss_end = .;
}
_end = .;
/DISCARD/ : { *(.comment) *(.gnu*) *(.note*) *(.eh_frame*) }
}
__bss_size = (__bss_end - __bss_start)>>3;

@ -1,50 +0,0 @@
/*
* Copyright (C) 2018 bzt (bztsrc@github)
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use, copy,
* modify, merge, publish, distribute, sublicense, and/or sell copies
* of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
*/
#include "uart.h"
#include "sd.h"
// get the end of bss segment from linker
extern unsigned char _end;
void main()
{
// set up serial console
uart_init();
// initialize EMMC and detect SD card type
if(sd_init()==SD_OK) {
// read the master boot record after our bss segment
if(sd_readblock(0,&_end,1)) {
// dump it to serial console
uart_dump(&_end);
}
}
// echo everything back
while(1) {
uart_send(uart_getc());
}
}

@ -1,63 +0,0 @@
/*
* Copyright (C) 2018 bzt (bztsrc@github)
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use, copy,
* modify, merge, publish, distribute, sublicense, and/or sell copies
* of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
*/
#include "gpio.h"
/* mailbox message buffer */
volatile unsigned int __attribute__((aligned(16))) mbox[36];
#define VIDEOCORE_MBOX (MMIO_BASE+0x0000B880)
#define MBOX_READ ((volatile unsigned int*)(VIDEOCORE_MBOX+0x0))
#define MBOX_POLL ((volatile unsigned int*)(VIDEOCORE_MBOX+0x10))
#define MBOX_SENDER ((volatile unsigned int*)(VIDEOCORE_MBOX+0x14))
#define MBOX_STATUS ((volatile unsigned int*)(VIDEOCORE_MBOX+0x18))
#define MBOX_CONFIG ((volatile unsigned int*)(VIDEOCORE_MBOX+0x1C))
#define MBOX_WRITE ((volatile unsigned int*)(VIDEOCORE_MBOX+0x20))
#define MBOX_RESPONSE 0x80000000
#define MBOX_FULL 0x80000000
#define MBOX_EMPTY 0x40000000
/**
* Make a mailbox call. Returns 0 on failure, non-zero on success
*/
int mbox_call(unsigned char ch)
{
unsigned int r;
/* wait until we can write to the mailbox */
do{asm volatile("nop");}while(*MBOX_STATUS & MBOX_FULL);
/* write the address of our message to the mailbox with channel identifier */
*MBOX_WRITE = (((unsigned int)((unsigned long)&mbox)&~0xF) | (ch&0xF));
/* now wait for the response */
while(1) {
/* is there a response? */
do{asm volatile("nop");}while(*MBOX_STATUS & MBOX_EMPTY);
r=*MBOX_READ;
/* is it a response to our message? */
if((unsigned char)(r&0xF)==ch && (r&~0xF)==(unsigned int)((unsigned long)&mbox))
/* is it a valid successful response? */
return mbox[1]==MBOX_RESPONSE;
}
return 0;
}

@ -1,47 +0,0 @@
/*
* Copyright (C) 2018 bzt (bztsrc@github)
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use, copy,
* modify, merge, publish, distribute, sublicense, and/or sell copies
* of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
*/
/* a properly aligned buffer */
extern volatile unsigned int mbox[36];
#define MBOX_REQUEST 0
/* channels */
#define MBOX_CH_POWER 0
#define MBOX_CH_FB 1
#define MBOX_CH_VUART 2
#define MBOX_CH_VCHIQ 3
#define MBOX_CH_LEDS 4
#define MBOX_CH_BTNS 5
#define MBOX_CH_TOUCH 6
#define MBOX_CH_COUNT 7
#define MBOX_CH_PROP 8
/* tags */
#define MBOX_TAG_SETPOWER 0x28001
#define MBOX_TAG_SETCLKRATE 0x38002
#define MBOX_TAG_LAST 0
int mbox_call(unsigned char ch);

@ -1,355 +0,0 @@
/*
* Copyright (C) 2018 bzt (bztsrc@github)
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use, copy,
* modify, merge, publish, distribute, sublicense, and/or sell copies
* of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
*/
#include "gpio.h"
#include "uart.h"
#include "delays.h"
#include "sd.h"
#define EMMC_ARG2 ((volatile unsigned int*)(MMIO_BASE+0x00300000))
#define EMMC_BLKSIZECNT ((volatile unsigned int*)(MMIO_BASE+0x00300004))
#define EMMC_ARG1 ((volatile unsigned int*)(MMIO_BASE+0x00300008))
#define EMMC_CMDTM ((volatile unsigned int*)(MMIO_BASE+0x0030000C))
#define EMMC_RESP0 ((volatile unsigned int*)(MMIO_BASE+0x00300010))
#define EMMC_RESP1 ((volatile unsigned int*)(MMIO_BASE+0x00300014))
#define EMMC_RESP2 ((volatile unsigned int*)(MMIO_BASE+0x00300018))
#define EMMC_RESP3 ((volatile unsigned int*)(MMIO_BASE+0x0030001C))
#define EMMC_DATA ((volatile unsigned int*)(MMIO_BASE+0x00300020))
#define EMMC_STATUS ((volatile unsigned int*)(MMIO_BASE+0x00300024))
#define EMMC_CONTROL0 ((volatile unsigned int*)(MMIO_BASE+0x00300028))
#define EMMC_CONTROL1 ((volatile unsigned int*)(MMIO_BASE+0x0030002C))
#define EMMC_INTERRUPT ((volatile unsigned int*)(MMIO_BASE+0x00300030))
#define EMMC_INT_MASK ((volatile unsigned int*)(MMIO_BASE+0x00300034))
#define EMMC_INT_EN ((volatile unsigned int*)(MMIO_BASE+0x00300038))
#define EMMC_CONTROL2 ((volatile unsigned int*)(MMIO_BASE+0x0030003C))
#define EMMC_SLOTISR_VER ((volatile unsigned int*)(MMIO_BASE+0x003000FC))
// command flags
#define CMD_NEED_APP 0x80000000
#define CMD_RSPNS_48 0x00020000
#define CMD_ERRORS_MASK 0xfff9c004
#define CMD_RCA_MASK 0xffff0000
// COMMANDs
#define CMD_GO_IDLE 0x00000000
#define CMD_ALL_SEND_CID 0x02010000
#define CMD_SEND_REL_ADDR 0x03020000
#define CMD_CARD_SELECT 0x07030000
#define CMD_SEND_IF_COND 0x08020000
#define CMD_STOP_TRANS 0x0C030000
#define CMD_READ_SINGLE 0x11220010
#define CMD_READ_MULTI 0x12220032
#define CMD_SET_BLOCKCNT 0x17020000
#define CMD_APP_CMD 0x37000000
#define CMD_SET_BUS_WIDTH (0x06020000|CMD_NEED_APP)
#define CMD_SEND_OP_COND (0x29020000|CMD_NEED_APP)
#define CMD_SEND_SCR (0x33220010|CMD_NEED_APP)
// STATUS register settings
#define SR_READ_AVAILABLE 0x00000800
#define SR_DAT_INHIBIT 0x00000002
#define SR_CMD_INHIBIT 0x00000001
#define SR_APP_CMD 0x00000020
// INTERRUPT register settings
#define INT_DATA_TIMEOUT 0x00100000
#define INT_CMD_TIMEOUT 0x00010000
#define INT_READ_RDY 0x00000020
#define INT_CMD_DONE 0x00000001
#define INT_ERROR_MASK 0x017E8000
// CONTROL register settings
#define C0_SPI_MODE_EN 0x00100000
#define C0_HCTL_HS_EN 0x00000004
#define C0_HCTL_DWITDH 0x00000002
#define C1_SRST_DATA 0x04000000
#define C1_SRST_CMD 0x02000000
#define C1_SRST_HC 0x01000000
#define C1_TOUNIT_DIS 0x000f0000
#define C1_TOUNIT_MAX 0x000e0000
#define C1_CLK_GENSEL 0x00000020
#define C1_CLK_EN 0x00000004
#define C1_CLK_STABLE 0x00000002
#define C1_CLK_INTLEN 0x00000001
// SLOTISR_VER values
#define HOST_SPEC_NUM 0x00ff0000
#define HOST_SPEC_NUM_SHIFT 16
#define HOST_SPEC_V3 2
#define HOST_SPEC_V2 1
#define HOST_SPEC_V1 0
// SCR flags
#define SCR_SD_BUS_WIDTH_4 0x00000400
#define SCR_SUPP_SET_BLKCNT 0x02000000
// added by my driver
#define SCR_SUPP_CCS 0x00000001
#define ACMD41_VOLTAGE 0x00ff8000
#define ACMD41_CMD_COMPLETE 0x80000000
#define ACMD41_CMD_CCS 0x40000000
#define ACMD41_ARG_HC 0x51ff8000
unsigned long sd_scr[2], sd_ocr, sd_rca, sd_err, sd_hv;
/**
* Wait for data or command ready
*/
int sd_status(unsigned int mask)
{
int cnt = 500000; while((*EMMC_STATUS & mask) && !(*EMMC_INTERRUPT & INT_ERROR_MASK) && cnt--) wait_msec(1);
return (cnt <= 0 || (*EMMC_INTERRUPT & INT_ERROR_MASK)) ? SD_ERROR : SD_OK;
}
/**
* Wait for interrupt
*/
int sd_int(unsigned int mask)
{
unsigned int r, m=mask | INT_ERROR_MASK;
int cnt = 1000000; while(!(*EMMC_INTERRUPT & m) && cnt--) wait_msec(1);
r=*EMMC_INTERRUPT;
if(cnt<=0 || (r & INT_CMD_TIMEOUT) || (r & INT_DATA_TIMEOUT) ) { *EMMC_INTERRUPT=r; return SD_TIMEOUT; } else
if(r & INT_ERROR_MASK) { *EMMC_INTERRUPT=r; return SD_ERROR; }
*EMMC_INTERRUPT=mask;
return 0;
}
/**
* Send a command
*/
int sd_cmd(unsigned int code, unsigned int arg)
{
int r=0;
sd_err=SD_OK;
if(code&CMD_NEED_APP) {
r=sd_cmd(CMD_APP_CMD|(sd_rca?CMD_RSPNS_48:0),sd_rca);
if(sd_rca && !r) { uart_puts("ERROR: failed to send SD APP command\n"); sd_err=SD_ERROR;return 0;}
code &= ~CMD_NEED_APP;
}
if(sd_status(SR_CMD_INHIBIT)) { uart_puts("ERROR: EMMC busy\n"); sd_err= SD_TIMEOUT;return 0;}
uart_puts("EMMC: Sending command ");uart_hex(code);uart_puts(" arg ");uart_hex(arg);uart_send('\n');
*EMMC_INTERRUPT=*EMMC_INTERRUPT; *EMMC_ARG1=arg; *EMMC_CMDTM=code;
if(code==CMD_SEND_OP_COND) wait_msec(1000); else
if(code==CMD_SEND_IF_COND || code==CMD_APP_CMD) wait_msec(100);
if((r=sd_int(INT_CMD_DONE))) {uart_puts("ERROR: failed to send EMMC command\n");sd_err=r;return 0;}
r=*EMMC_RESP0;
if(code==CMD_GO_IDLE || code==CMD_APP_CMD) return 0; else
if(code==(CMD_APP_CMD|CMD_RSPNS_48)) return r&SR_APP_CMD; else
if(code==CMD_SEND_OP_COND) return r; else
if(code==CMD_SEND_IF_COND) return r==arg? SD_OK : SD_ERROR; else
if(code==CMD_ALL_SEND_CID) {r|=*EMMC_RESP3; r|=*EMMC_RESP2; r|=*EMMC_RESP1; return r; } else
if(code==CMD_SEND_REL_ADDR) {
sd_err=(((r&0x1fff))|((r&0x2000)<<6)|((r&0x4000)<<8)|((r&0x8000)<<8))&CMD_ERRORS_MASK;
return r&CMD_RCA_MASK;
}
return r&CMD_ERRORS_MASK;
// make gcc happy
return 0;
}
/**
* read a block from sd card and return the number of bytes read
* returns 0 on error.
*/
int sd_readblock(unsigned int lba, unsigned char *buffer, unsigned int num)
{
int r,c=0,d;
if(num<1) num=1;
uart_puts("sd_readblock lba ");uart_hex(lba);uart_puts(" num ");uart_hex(num);uart_send('\n');
if(sd_status(SR_DAT_INHIBIT)) {sd_err=SD_TIMEOUT; return 0;}
unsigned int *buf=(unsigned int *)buffer;
if(sd_scr[0] & SCR_SUPP_CCS) {
if(num > 1 && (sd_scr[0] & SCR_SUPP_SET_BLKCNT)) {
sd_cmd(CMD_SET_BLOCKCNT,num);
if(sd_err) return 0;
}
*EMMC_BLKSIZECNT = (num << 16) | 512;
sd_cmd(num == 1 ? CMD_READ_SINGLE : CMD_READ_MULTI,lba);
if(sd_err) return 0;
} else {
*EMMC_BLKSIZECNT = (1 << 16) | 512;
}
while( c < num ) {
if(!(sd_scr[0] & SCR_SUPP_CCS)) {
sd_cmd(CMD_READ_SINGLE,(lba+c)*512);
if(sd_err) return 0;
}
if((r=sd_int(INT_READ_RDY))){uart_puts("\rERROR: Timeout waiting for ready to read\n");sd_err=r;return 0;}
for(d=0;d<128;d++) buf[d] = *EMMC_DATA;
c++; buf+=128;
}
if( num > 1 && !(sd_scr[0] & SCR_SUPP_SET_BLKCNT) && (sd_scr[0] & SCR_SUPP_CCS)) sd_cmd(CMD_STOP_TRANS,0);
return sd_err!=SD_OK || c!=num? 0 : num*512;
}
/**
* set SD clock to frequency in Hz
*/
int sd_clk(unsigned int f)
{
unsigned int d,c=41666666/f,x,s=32,h=0;
int cnt = 100000;
while((*EMMC_STATUS & (SR_CMD_INHIBIT|SR_DAT_INHIBIT)) && cnt--) wait_msec(1);
if(cnt<=0) {
uart_puts("ERROR: timeout waiting for inhibit flag\n");
return SD_ERROR;
}
*EMMC_CONTROL1 &= ~C1_CLK_EN; wait_msec(10);
x=c-1; if(!x) s=0; else {
if(!(x & 0xffff0000u)) { x <<= 16; s -= 16; }
if(!(x & 0xff000000u)) { x <<= 8; s -= 8; }
if(!(x & 0xf0000000u)) { x <<= 4; s -= 4; }
if(!(x & 0xc0000000u)) { x <<= 2; s -= 2; }
if(!(x & 0x80000000u)) { x <<= 1; s -= 1; }
if(s>0) s--;
if(s>7) s=7;
}
if(sd_hv>HOST_SPEC_V2) d=c; else d=(1<<s);
if(d<=2) {d=2;s=0;}
uart_puts("sd_clk divisor ");uart_hex(d);uart_puts(", shift ");uart_hex(s);uart_send('\n');
if(sd_hv>HOST_SPEC_V2) h=(d&0x300)>>2;
d=(((d&0x0ff)<<8)|h);
*EMMC_CONTROL1=(*EMMC_CONTROL1&0xffff003f)|d; wait_msec(10);
*EMMC_CONTROL1 |= C1_CLK_EN; wait_msec(10);
cnt=10000; while(!(*EMMC_CONTROL1 & C1_CLK_STABLE) && cnt--) wait_msec(10);
if(cnt<=0) {
uart_puts("ERROR: failed to get stable clock\n");
return SD_ERROR;
}
return SD_OK;
}
/**
* initialize EMMC to read SDHC card
*/
int sd_init()
{
long r,cnt,ccs=0;
// GPIO_CD
r=*GPFSEL4; r&=~(7<<(7*3)); *GPFSEL4=r;
*GPPUD=2; wait_cycles(150); *GPPUDCLK1=(1<<15); wait_cycles(150); *GPPUD=0; *GPPUDCLK1=0;
r=*GPHEN1; r|=1<<15; *GPHEN1=r;
// GPIO_CLK, GPIO_CMD
r=*GPFSEL4; r|=(7<<(8*3))|(7<<(9*3)); *GPFSEL4=r;
*GPPUD=2; wait_cycles(150); *GPPUDCLK1=(1<<16)|(1<<17); wait_cycles(150); *GPPUD=0; *GPPUDCLK1=0;
// GPIO_DAT0, GPIO_DAT1, GPIO_DAT2, GPIO_DAT3
r=*GPFSEL5; r|=(7<<(0*3)) | (7<<(1*3)) | (7<<(2*3)) | (7<<(3*3)); *GPFSEL5=r;
*GPPUD=2; wait_cycles(150);
*GPPUDCLK1=(1<<18) | (1<<19) | (1<<20) | (1<<21);
wait_cycles(150); *GPPUD=0; *GPPUDCLK1=0;
sd_hv = (*EMMC_SLOTISR_VER & HOST_SPEC_NUM) >> HOST_SPEC_NUM_SHIFT;
uart_puts("EMMC: GPIO set up\n");
// Reset the card.
*EMMC_CONTROL0 = 0; *EMMC_CONTROL1 |= C1_SRST_HC;
cnt=10000; do{wait_msec(10);} while( (*EMMC_CONTROL1 & C1_SRST_HC) && cnt-- );
if(cnt<=0) {
uart_puts("ERROR: failed to reset EMMC\n");
return SD_ERROR;
}
uart_puts("EMMC: reset OK\n");
*EMMC_CONTROL1 |= C1_CLK_INTLEN | C1_TOUNIT_MAX;
wait_msec(10);
// Set clock to setup frequency.
if((r=sd_clk(400000))) return r;
*EMMC_INT_EN = 0xffffffff;
*EMMC_INT_MASK = 0xffffffff;
sd_scr[0]=sd_scr[1]=sd_rca=sd_err=0;
sd_cmd(CMD_GO_IDLE,0);
if(sd_err) return sd_err;
sd_cmd(CMD_SEND_IF_COND,0x000001AA);
if(sd_err) return sd_err;
cnt=6; r=0; while(!(r&ACMD41_CMD_COMPLETE) && cnt--) {
wait_cycles(400);
r=sd_cmd(CMD_SEND_OP_COND,ACMD41_ARG_HC);
uart_puts("EMMC: CMD_SEND_OP_COND returned ");
if(r&ACMD41_CMD_COMPLETE)
uart_puts("COMPLETE ");
if(r&ACMD41_VOLTAGE)
uart_puts("VOLTAGE ");
if(r&ACMD41_CMD_CCS)
uart_puts("CCS ");
uart_hex(r>>32);
uart_hex(r);
uart_send('\n');
if(sd_err!=SD_TIMEOUT && sd_err!=SD_OK ) {
uart_puts("ERROR: EMMC ACMD41 returned error\n");
return sd_err;
}
}
if(!(r&ACMD41_CMD_COMPLETE) || !cnt ) return SD_TIMEOUT;
if(!(r&ACMD41_VOLTAGE)) return SD_ERROR;
if(r&ACMD41_CMD_CCS) ccs=SCR_SUPP_CCS;
sd_cmd(CMD_ALL_SEND_CID,0);
sd_rca = sd_cmd(CMD_SEND_REL_ADDR,0);
uart_puts("EMMC: CMD_SEND_REL_ADDR returned ");
uart_hex(sd_rca>>32);
uart_hex(sd_rca);
uart_send('\n');
if(sd_err) return sd_err;
if((r=sd_clk(25000000))) return r;
sd_cmd(CMD_CARD_SELECT,sd_rca);
if(sd_err) return sd_err;
if(sd_status(SR_DAT_INHIBIT)) return SD_TIMEOUT;
*EMMC_BLKSIZECNT = (1<<16) | 8;
sd_cmd(CMD_SEND_SCR,0);
if(sd_err) return sd_err;
if(sd_int(INT_READ_RDY)) return SD_TIMEOUT;
r=0; cnt=100000; while(r<2 && cnt) {
if( *EMMC_STATUS & SR_READ_AVAILABLE )
sd_scr[r++] = *EMMC_DATA;
else
wait_msec(1);
}
if(r!=2) return SD_TIMEOUT;
if(sd_scr[0] & SCR_SD_BUS_WIDTH_4) {
sd_cmd(CMD_SET_BUS_WIDTH,sd_rca|2);
if(sd_err) return sd_err;
*EMMC_CONTROL0 |= C0_HCTL_DWITDH;
}
// add software flag
uart_puts("EMMC: supports ");
if(sd_scr[0] & SCR_SUPP_SET_BLKCNT)
uart_puts("SET_BLKCNT ");
if(ccs)
uart_puts("CCS ");
uart_send('\n');
sd_scr[0]&=~SCR_SUPP_CCS;
sd_scr[0]|=ccs;
return SD_OK;
}

@ -1,31 +0,0 @@
/*
* Copyright (C) 2018 bzt (bztsrc@github)
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use, copy,
* modify, merge, publish, distribute, sublicense, and/or sell copies
* of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
*/
#define SD_OK 0
#define SD_TIMEOUT -1
#define SD_ERROR -2
int sd_init();
int sd_readblock(unsigned int lba, unsigned char *buffer, unsigned int num);

@ -1,55 +0,0 @@
/*
* Copyright (C) 2018 bzt (bztsrc@github)
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use, copy,
* modify, merge, publish, distribute, sublicense, and/or sell copies
* of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
*/
.section ".text.boot"
.global _start
_start:
// read cpu id, stop slave cores
mrs x1, mpidr_el1
and x1, x1, #3
cbz x1, 2f
// cpu id > 0, stop
1: wfe
b 1b
2: // cpu id == 0
// set stack before our code
ldr x1, =_start
mov sp, x1
// clear bss
ldr x1, =__bss_start
ldr w2, =__bss_size
3: cbz w2, 4f
str xzr, [x1], #8
sub w2, w2, #1
cbnz w2, 3b
// jump to C code, should not return
4: bl main
// for failsafe, halt this core too
b 1b

@ -1,153 +0,0 @@
/*
* Copyright (C) 2018 bzt (bztsrc@github)
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use, copy,
* modify, merge, publish, distribute, sublicense, and/or sell copies
* of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
*/
#include "gpio.h"
#include "mbox.h"
#include "delays.h"
/* PL011 UART registers */
#define UART0_DR ((volatile unsigned int*)(MMIO_BASE+0x00201000))
#define UART0_FR ((volatile unsigned int*)(MMIO_BASE+0x00201018))
#define UART0_IBRD ((volatile unsigned int*)(MMIO_BASE+0x00201024))
#define UART0_FBRD ((volatile unsigned int*)(MMIO_BASE+0x00201028))
#define UART0_LCRH ((volatile unsigned int*)(MMIO_BASE+0x0020102C))
#define UART0_CR ((volatile unsigned int*)(MMIO_BASE+0x00201030))
#define UART0_IMSC ((volatile unsigned int*)(MMIO_BASE+0x00201038))
#define UART0_ICR ((volatile unsigned int*)(MMIO_BASE+0x00201044))
/**
* Set baud rate and characteristics (115200 8N1) and map to GPIO
*/
void uart_init()
{
register unsigned int r;
/* initialize UART */
*UART0_CR = 0; // turn off UART0
/* set up clock for consistent divisor values */
mbox[0] = 8*4;
mbox[1] = MBOX_REQUEST;
mbox[2] = MBOX_TAG_SETCLKRATE; // set clock rate
mbox[3] = 12;
mbox[4] = 8;
mbox[5] = 2; // UART clock
mbox[6] = 4000000; // 4Mhz
mbox[7] = MBOX_TAG_LAST;
mbox_call(MBOX_CH_PROP);
/* map UART0 to GPIO pins */
r=*GPFSEL1;
r&=~((7<<12)|(7<<15)); // gpio14, gpio15
r|=(4<<12)|(4<<15); // alt0
*GPFSEL1 = r;
*GPPUD = 0; // enable pins 14 and 15
wait_cycles(150);
*GPPUDCLK0 = (1<<14)|(1<<15);
wait_cycles(150);
*GPPUDCLK0 = 0; // flush GPIO setup
*UART0_ICR = 0x7FF; // clear interrupts
*UART0_IBRD = 2; // 115200 baud
*UART0_FBRD = 0xB;
*UART0_LCRH = 0b11<<5; // 8n1
*UART0_CR = 0x301; // enable Tx, Rx, FIFO
}
/**
* Send a character
*/
void uart_send(unsigned int c) {
/* wait until we can send */
do{asm volatile("nop");}while(*UART0_FR&0x20);
/* write the character to the buffer */
*UART0_DR=c;
}
/**
* Receive a character
*/
char uart_getc() {
char r;
/* wait until something is in the buffer */
do{asm volatile("nop");}while(*UART0_FR&0x10);
/* read it and return */
r=(char)(*UART0_DR);
/* convert carrige return to newline */
return r=='\r'?'\n':r;
}
/**
* Display a string
*/
void uart_puts(char *s) {
while(*s) {
/* convert newline to carrige return + newline */
if(*s=='\n')
uart_send('\r');
uart_send(*s++);
}
}
/**
* Display a binary value in hexadecimal
*/
void uart_hex(unsigned int d) {
unsigned int n;
int c;
for(c=28;c>=0;c-=4) {
// get highest tetrad
n=(d>>c)&0xF;
// 0-9 => '0'-'9', 10-15 => 'A'-'F'
n+=n>9?0x37:0x30;
uart_send(n);
}
}
/**
* Dump memory
*/
void uart_dump(void *ptr)
{
unsigned long a,b,d;
unsigned char c;
for(a=(unsigned long)ptr;a<(unsigned long)ptr+512;a+=16) {
uart_hex(a); uart_puts(": ");
for(b=0;b<16;b++) {
c=*((unsigned char*)(a+b));
d=(unsigned int)c;d>>=4;d&=0xF;d+=d>9?0x37:0x30;uart_send(d);
d=(unsigned int)c;d&=0xF;d+=d>9?0x37:0x30;uart_send(d);
uart_send(' ');
if(b%4==3)
uart_send(' ');
}
for(b=0;b<16;b++) {
c=*((unsigned char*)(a+b));
uart_send(c<32||c>=127?'.':c);
}
uart_send('\r');
uart_send('\n');
}
}

@ -1,31 +0,0 @@
/*
* Copyright (C) 2018 bzt (bztsrc@github)
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use, copy,
* modify, merge, publish, distribute, sublicense, and/or sell copies
* of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
*/
void uart_init();
void uart_send(unsigned int c);
char uart_getc();
void uart_puts(char *s);
void uart_hex(unsigned int d);
void uart_dump(void *ptr);

@ -1,43 +0,0 @@
#
# Copyright (C) 2018 bzt (bztsrc@github)
#
# Permission is hereby granted, free of charge, to any person
# obtaining a copy of this software and associated documentation
# files (the "Software"), to deal in the Software without
# restriction, including without limitation the rights to use, copy,
# modify, merge, publish, distribute, sublicense, and/or sell copies
# of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be
# included in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
# HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
# DEALINGS IN THE SOFTWARE.
#
#
SRCS = $(wildcard *.c)
OBJS = $(SRCS:.c=.o)
CFLAGS = -Wall -O2 -ffreestanding -nostdinc -nostdlib -nostartfiles
all: clean kernel8.img
start.o: start.S
aarch64-elf-gcc $(CFLAGS) -c start.S -o start.o
%.o: %.c
aarch64-elf-gcc $(CFLAGS) -c $< -o $@
kernel8.img: start.o $(OBJS)
aarch64-elf-ld -nostdlib -nostartfiles start.o $(OBJS) -T link.ld -o kernel8.elf
aarch64-elf-objcopy -O binary kernel8.elf kernel8.img
clean:
rm kernel8.elf *.o >/dev/null 2>/dev/null || true

@ -1,42 +0,0 @@
Oktatóanyag 0C - Könyvtárak
===========================
Most hogy már tudunk szektort beolvasni, ideje értelmezni a fájlrendszert. Ez az oktatóanyag megtanítja,
hogy hogyan listázzuk ki egy FAT16 vagy FAT32 partíció gyökérkönyvtárát.
```sh
$ qemu-system-aarch64 -M raspi3 -drive file=test.dd,if=sd,format=raw -serial stdio
... kimenet törölve az átláthatóság miatt ...
MBR disk identifier: 12345678
FAT partition starts at: 00000008
... kimenet törölve az átláthatóság miatt ...
FAT type: FAT16
FAT number of root diretory entries: 00000200
FAT root directory LBA: 00000034
... kimenet törölve az átláthatóság miatt ...
Attrib Cluster Size Name
...L.. 00000000 00000000 EFI System
....D. 00000003 00000000 FOLDER
.....A 00000171 0000C448 BOOTCODEBIN
.....A 0000018A 000019B3 FIXUP DAT
.....A 0000018E 00001B10 KERNEL8 IMG
.....A 00000192 000005D6 LICENC~1BRO
.....A 00000193 002B2424 START ELF
```
Fat.h, fat.c
------------
Ez elég egyszerű és jól dokumentált művelet. Beolvassuk az MBR-t, megkeressük a partíciónkat, majd
betöltjük az első szektorát (Volume Boot Record). Ebben van az ún. BIOS Parameter Block, ami leírja
a FAT fájlrendszert.
`fat_getpartition()` betölti és értelmezi a partíció első szektorát.
`fat_listdirectory()` kilistázza a fájlrendszer gyökérkönyvtárának tartalmát.
Main
----
Miután inicializájuk az EMMC-t szektorok olvasásához, beolvassuk az első szektort a partícióról. Ha a BPB
egy érvényes FAT fájlrendszert ír le, akkor kilistázzuk a fájlrendszer gyükérkönyvtárát.

@ -1,42 +0,0 @@
Tutorial 0C - Directory
=======================
Now that we can load a sector from the storage, it is time to parse it as a file system. This
tutorial will show you how to list the root directory entries of a FAT16 or FAT32 partition.
```sh
$ qemu-system-aarch64 -M raspi3 -drive file=test.dd,if=sd,format=raw -serial stdio
... output removed for clearity ...
MBR disk identifier: 12345678
FAT partition starts at: 00000008
... output removed for clearity ...
FAT type: FAT16
FAT number of root diretory entries: 00000200
FAT root directory LBA: 00000034
... output removed for clearity ...
Attrib Cluster Size Name
...L.. 00000000 00000000 EFI System
....D. 00000003 00000000 FOLDER
.....A 00000171 0000C448 BOOTCODEBIN
.....A 0000018A 000019B3 FIXUP DAT
.....A 0000018E 00001B10 KERNEL8 IMG
.....A 00000192 000005D6 LICENC~1BRO
.....A 00000193 002B2424 START ELF
```
Fat.h, fat.c
------------
This is easy and pretty well documented. We have to read the MBR, locate our partition, and load
it's first sector (Volume Boot Record). That has the BIOS Parameter Block, which describes the FAT
file system.
`fat_getpartition()` load and check the boot record of the first MBR partition.
`fat_listdirectory()` list root directory entries on the volume.
Main
----
Once we initialize EMMC to read sectors, we load the boot record of the first partition. If the BPB
describes a valid FAT partition, we list the root directory entries in it.

@ -1,81 +0,0 @@
/*
* Copyright (C) 2018 bzt (bztsrc@github)
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use, copy,
* modify, merge, publish, distribute, sublicense, and/or sell copies
* of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
*/
#include "gpio.h"
#define SYSTMR_LO ((volatile unsigned int*)(MMIO_BASE+0x00003004))
#define SYSTMR_HI ((volatile unsigned int*)(MMIO_BASE+0x00003008))
/**
* Wait N CPU cycles (ARM CPU only)
*/
void wait_cycles(unsigned int n)
{
if(n) while(n--) { asm volatile("nop"); }
}
/**
* Wait N microsec (ARM CPU only)
*/
void wait_msec(unsigned int n)
{
register unsigned long f, t, r;
// get the current counter frequency
asm volatile ("mrs %0, cntfrq_el0" : "=r"(f));
// read the current counter
asm volatile ("mrs %0, cntpct_el0" : "=r"(t));
// calculate expire value for counter
t+=((f/1000)*n)/1000;
do{asm volatile ("mrs %0, cntpct_el0" : "=r"(r));}while(r<t);
}
/**
* Get System Timer's counter
*/
unsigned long get_system_timer()
{
unsigned int h=-1, l;
// we must read MMIO area as two separate 32 bit reads
h=*SYSTMR_HI;
l=*SYSTMR_LO;
// we have to repeat it if high word changed during read
if(h!=*SYSTMR_HI) {
h=*SYSTMR_HI;
l=*SYSTMR_LO;
}
// compose long int value
return ((unsigned long) h << 32) | l;
}
/**
* Wait N microsec (with BCM System Timer)
*/
void wait_msec_st(unsigned int n)
{
unsigned long t=get_system_timer();
// we must check if it's non-zero, because qemu does not emulate
// system timer, and returning constant zero would mean infinite loop
if(t) while(get_system_timer() < t+n);
}

@ -1,29 +0,0 @@
/*
* Copyright (C) 2018 bzt (bztsrc@github)
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use, copy,
* modify, merge, publish, distribute, sublicense, and/or sell copies
* of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
*/
void wait_cycles(unsigned int n);
void wait_msec(unsigned int n);
unsigned long get_system_timer();
void wait_msec_st(unsigned int n);

@ -1,172 +0,0 @@
/*
* Copyright (C) 2018 bzt (bztsrc@github)
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use, copy,
* modify, merge, publish, distribute, sublicense, and/or sell copies
* of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
*/
#include "sd.h"
#include "uart.h"
// get the end of bss segment from linker
extern unsigned char _end;
unsigned int partitionlba;
// the BIOS Parameter Block (in Volume Boot Record)
typedef struct {
char jmp[3];
char oem[8];
unsigned short bps;
unsigned char spc;
unsigned short rsc;
unsigned char nf;
unsigned short nr;
unsigned short ts16;
unsigned char media;
unsigned short spf16;
unsigned short spt;
unsigned short nh;
unsigned int hs;
unsigned int ts32;
unsigned int spf32;
unsigned int flg;
unsigned int rc;
char vol[6];
char fst[8];
char dmy[20];
char fst2[8];
} __attribute__((packed)) bpb_t;
// directory entry structure
typedef struct {
char name[8];
char ext[3];
char attr[9];
unsigned short ch;
unsigned int attr2;
unsigned short cl;
unsigned int size;
} __attribute__((packed)) fatdir_t;
/**
* Get the starting LBA address of the first partition
* so that we know where our FAT file system starts, and
* read that volume's BIOS Parameter Block
*/
int fat_getpartition()
{
unsigned char *mbr=&_end;
bpb_t *bpb=(bpb_t*)&_end;
// read the partitioning table
if(sd_readblock(0,&_end,1)) {
// check magic
if(mbr[510]!=0x55 || mbr[511]!=0xAA) {
uart_puts("ERROR: Bad magic in MBR\n");
return 0;
}
// check partition type
if(mbr[0x1C2]!=0xE/*FAT16 LBA*/ && mbr[0x1C2]!=0xC/*FAT32 LBA*/) {
uart_puts("ERROR: Wrong partition type\n");
return 0;
}
uart_puts("MBR disk identifier: ");
uart_hex(*((unsigned int*)((unsigned long)&_end+0x1B8)));
uart_puts("\nFAT partition starts at: ");
partitionlba=*((unsigned int*)((unsigned long)&_end+0x1C6));
uart_hex(partitionlba);
uart_puts("\n");
// read the boot record
if(!sd_readblock(partitionlba,&_end,1)) {
uart_puts("ERROR: Unable to read boot record\n");
return 0;
}
// check file system type. We don't use cluster numbers for that, but magic bytes
if( !(bpb->fst[0]=='F' && bpb->fst[1]=='A' && bpb->fst[2]=='T') &&
!(bpb->fst2[0]=='F' && bpb->fst2[1]=='A' && bpb->fst2[2]=='T')) {
uart_puts("ERROR: Unknown file system type\n");
return 0;
}
uart_puts("FAT type: ");
// if 16 bit sector per fat is zero, then it's a FAT32
uart_puts(bpb->spf16>0?"FAT16":"FAT32");
uart_puts("\n");
return 1;
}
return 0;
}
/**
* List root directory entries in a FAT file system
*/
void fat_listdirectory()
{
bpb_t *bpb=(bpb_t*)&_end;
fatdir_t *dir=(fatdir_t*)&_end;
unsigned int root_sec, s;
// find the root directory's LBA
root_sec=((bpb->spf16?bpb->spf16:bpb->spf32)*bpb->nf)+bpb->rsc;
//WARNING gcc generates bad code for bpb->nr, causing unaligned exception
s=*((unsigned int*)&bpb->nf);
s>>=8;
s&=0xFFFF;
uart_puts("FAT number of root diretory entries: ");
uart_hex(s);
s<<=5;
// now s=bpb->nr*sizeof(fatdir_t));
if(bpb->spf16==0) {
// adjust for FAT32
root_sec+=(bpb->rc-2)*bpb->spc;
}
// add partition LBA
root_sec+=partitionlba;
uart_puts("\nFAT root directory LBA: ");
uart_hex(root_sec);
uart_puts("\n");
// load the root directory
if(sd_readblock(root_sec,(unsigned char*)&_end,s/512+1)) {
uart_puts("\nAttrib Cluster Size Name\n");
// iterate on each entry and print out
for(;dir->name[0]!=0;dir++) {
// is it a valid entry?
if(dir->name[0]==0xE5 || dir->attr[0]==0xF) continue;
// decode attributes
uart_send(dir->attr[0]& 1?'R':'.'); // read-only
uart_send(dir->attr[0]& 2?'H':'.'); // hidden
uart_send(dir->attr[0]& 4?'S':'.'); // system
uart_send(dir->attr[0]& 8?'L':'.'); // volume label
uart_send(dir->attr[0]&16?'D':'.'); // directory
uart_send(dir->attr[0]&32?'A':'.'); // archive
uart_send(' ');
// staring cluster
uart_hex(((unsigned int)dir->ch)<<16|dir->cl);
uart_send(' ');
// size
uart_hex(dir->size);
uart_send(' ');
// filename
dir->attr[0]=0;
uart_puts(dir->name);
uart_puts("\n");
}
} else {
uart_puts("ERROR: Unable to load root directory\n");
}
}

@ -1,27 +0,0 @@
/*
* Copyright (C) 2018 bzt (bztsrc@github)
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use, copy,
* modify, merge, publish, distribute, sublicense, and/or sell copies
* of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
*/
int fat_getpartition();
void fat_listdirectory();

@ -1,45 +0,0 @@
/*
* Copyright (C) 2018 bzt (bztsrc@github)
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use, copy,
* modify, merge, publish, distribute, sublicense, and/or sell copies
* of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
*/
#define MMIO_BASE 0x3F000000
#define GPFSEL0 ((volatile unsigned int*)(MMIO_BASE+0x00200000))
#define GPFSEL1 ((volatile unsigned int*)(MMIO_BASE+0x00200004))
#define GPFSEL2 ((volatile unsigned int*)(MMIO_BASE+0x00200008))
#define GPFSEL3 ((volatile unsigned int*)(MMIO_BASE+0x0020000C))
#define GPFSEL4 ((volatile unsigned int*)(MMIO_BASE+0x00200010))
#define GPFSEL5 ((volatile unsigned int*)(MMIO_BASE+0x00200014))
#define GPSET0 ((volatile unsigned int*)(MMIO_BASE+0x0020001C))
#define GPSET1 ((volatile unsigned int*)(MMIO_BASE+0x00200020))
#define GPCLR0 ((volatile unsigned int*)(MMIO_BASE+0x00200028))
#define GPLEV0 ((volatile unsigned int*)(MMIO_BASE+0x00200034))
#define GPLEV1 ((volatile unsigned int*)(MMIO_BASE+0x00200038))
#define GPEDS0 ((volatile unsigned int*)(MMIO_BASE+0x00200040))
#define GPEDS1 ((volatile unsigned int*)(MMIO_BASE+0x00200044))
#define GPHEN0 ((volatile unsigned int*)(MMIO_BASE+0x00200064))
#define GPHEN1 ((volatile unsigned int*)(MMIO_BASE+0x00200068))
#define GPPUD ((volatile unsigned int*)(MMIO_BASE+0x00200094))
#define GPPUDCLK0 ((volatile unsigned int*)(MMIO_BASE+0x00200098))
#define GPPUDCLK1 ((volatile unsigned int*)(MMIO_BASE+0x0020009C))

Binary file not shown.

@ -1,44 +0,0 @@
/*
* Copyright (C) 2018 bzt (bztsrc@github)
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use, copy,
* modify, merge, publish, distribute, sublicense, and/or sell copies
* of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
*/
SECTIONS
{
. = 0x80000;
.text : { KEEP(*(.text.boot)) *(.text .text.* .gnu.linkonce.t*) }
.rodata : { *(.rodata .rodata.* .gnu.linkonce.r*) }
PROVIDE(_data = .);
.data : { *(.data .data.* .gnu.linkonce.d*) }
.bss (NOLOAD) : {
. = ALIGN(16);
__bss_start = .;
*(.bss .bss.*)
*(COMMON)
__bss_end = .;
}
_end = .;
/DISCARD/ : { *(.comment) *(.gnu*) *(.note*) *(.eh_frame*) }
}
__bss_size = (__bss_end - __bss_start)>>3;

@ -1,50 +0,0 @@
/*
* Copyright (C) 2018 bzt (bztsrc@github)
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use, copy,
* modify, merge, publish, distribute, sublicense, and/or sell copies
* of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
*/
#include "uart.h"
#include "sd.h"
#include "fat.h"
void main()
{
// set up serial console
uart_init();
// initialize EMMC and detect SD card type
if(sd_init()==SD_OK) {
// read the master boot record and find our partition
if(fat_getpartition()) {
// list root directory entries
fat_listdirectory();
} else {
uart_puts("FAT partition not found???\n");
}
}
// echo everything back
while(1) {
uart_send(uart_getc());
}
}

@ -1,63 +0,0 @@
/*
* Copyright (C) 2018 bzt (bztsrc@github)
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use, copy,
* modify, merge, publish, distribute, sublicense, and/or sell copies
* of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
*/
#include "gpio.h"
/* mailbox message buffer */
volatile unsigned int __attribute__((aligned(16))) mbox[36];
#define VIDEOCORE_MBOX (MMIO_BASE+0x0000B880)
#define MBOX_READ ((volatile unsigned int*)(VIDEOCORE_MBOX+0x0))
#define MBOX_POLL ((volatile unsigned int*)(VIDEOCORE_MBOX+0x10))
#define MBOX_SENDER ((volatile unsigned int*)(VIDEOCORE_MBOX+0x14))
#define MBOX_STATUS ((volatile unsigned int*)(VIDEOCORE_MBOX+0x18))
#define MBOX_CONFIG ((volatile unsigned int*)(VIDEOCORE_MBOX+0x1C))
#define MBOX_WRITE ((volatile unsigned int*)(VIDEOCORE_MBOX+0x20))
#define MBOX_RESPONSE 0x80000000
#define MBOX_FULL 0x80000000
#define MBOX_EMPTY 0x40000000
/**
* Make a mailbox call. Returns 0 on failure, non-zero on success
*/
int mbox_call(unsigned char ch)
{
unsigned int r;
/* wait until we can write to the mailbox */
do{asm volatile("nop");}while(*MBOX_STATUS & MBOX_FULL);
/* write the address of our message to the mailbox with channel identifier */
*MBOX_WRITE = (((unsigned int)((unsigned long)&mbox)&~0xF) | (ch&0xF));
/* now wait for the response */
while(1) {
/* is there a response? */
do{asm volatile("nop");}while(*MBOX_STATUS & MBOX_EMPTY);
r=*MBOX_READ;
/* is it a response to our message? */
if((unsigned char)(r&0xF)==ch && (r&~0xF)==(unsigned int)((unsigned long)&mbox))
/* is it a valid successful response? */
return mbox[1]==MBOX_RESPONSE;
}
return 0;
}

@ -1,47 +0,0 @@
/*
* Copyright (C) 2018 bzt (bztsrc@github)
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use, copy,
* modify, merge, publish, distribute, sublicense, and/or sell copies
* of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
*/
/* a properly aligned buffer */
extern volatile unsigned int mbox[36];
#define MBOX_REQUEST 0
/* channels */
#define MBOX_CH_POWER 0
#define MBOX_CH_FB 1
#define MBOX_CH_VUART 2
#define MBOX_CH_VCHIQ 3
#define MBOX_CH_LEDS 4
#define MBOX_CH_BTNS 5
#define MBOX_CH_TOUCH 6
#define MBOX_CH_COUNT 7
#define MBOX_CH_PROP 8
/* tags */
#define MBOX_TAG_SETPOWER 0x28001
#define MBOX_TAG_SETCLKRATE 0x38002
#define MBOX_TAG_LAST 0
int mbox_call(unsigned char ch);

@ -1,355 +0,0 @@
/*
* Copyright (C) 2018 bzt (bztsrc@github)
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use, copy,
* modify, merge, publish, distribute, sublicense, and/or sell copies
* of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
*/
#include "gpio.h"
#include "uart.h"
#include "delays.h"
#include "sd.h"
#define EMMC_ARG2 ((volatile unsigned int*)(MMIO_BASE+0x00300000))
#define EMMC_BLKSIZECNT ((volatile unsigned int*)(MMIO_BASE+0x00300004))
#define EMMC_ARG1 ((volatile unsigned int*)(MMIO_BASE+0x00300008))
#define EMMC_CMDTM ((volatile unsigned int*)(MMIO_BASE+0x0030000C))
#define EMMC_RESP0 ((volatile unsigned int*)(MMIO_BASE+0x00300010))
#define EMMC_RESP1 ((volatile unsigned int*)(MMIO_BASE+0x00300014))
#define EMMC_RESP2 ((volatile unsigned int*)(MMIO_BASE+0x00300018))
#define EMMC_RESP3 ((volatile unsigned int*)(MMIO_BASE+0x0030001C))
#define EMMC_DATA ((volatile unsigned int*)(MMIO_BASE+0x00300020))
#define EMMC_STATUS ((volatile unsigned int*)(MMIO_BASE+0x00300024))
#define EMMC_CONTROL0 ((volatile unsigned int*)(MMIO_BASE+0x00300028))
#define EMMC_CONTROL1 ((volatile unsigned int*)(MMIO_BASE+0x0030002C))
#define EMMC_INTERRUPT ((volatile unsigned int*)(MMIO_BASE+0x00300030))
#define EMMC_INT_MASK ((volatile unsigned int*)(MMIO_BASE+0x00300034))
#define EMMC_INT_EN ((volatile unsigned int*)(MMIO_BASE+0x00300038))
#define EMMC_CONTROL2 ((volatile unsigned int*)(MMIO_BASE+0x0030003C))
#define EMMC_SLOTISR_VER ((volatile unsigned int*)(MMIO_BASE+0x003000FC))
// command flags
#define CMD_NEED_APP 0x80000000
#define CMD_RSPNS_48 0x00020000
#define CMD_ERRORS_MASK 0xfff9c004
#define CMD_RCA_MASK 0xffff0000
// COMMANDs
#define CMD_GO_IDLE 0x00000000
#define CMD_ALL_SEND_CID 0x02010000
#define CMD_SEND_REL_ADDR 0x03020000
#define CMD_CARD_SELECT 0x07030000
#define CMD_SEND_IF_COND 0x08020000
#define CMD_STOP_TRANS 0x0C030000
#define CMD_READ_SINGLE 0x11220010
#define CMD_READ_MULTI 0x12220032
#define CMD_SET_BLOCKCNT 0x17020000
#define CMD_APP_CMD 0x37000000
#define CMD_SET_BUS_WIDTH (0x06020000|CMD_NEED_APP)
#define CMD_SEND_OP_COND (0x29020000|CMD_NEED_APP)
#define CMD_SEND_SCR (0x33220010|CMD_NEED_APP)
// STATUS register settings
#define SR_READ_AVAILABLE 0x00000800
#define SR_DAT_INHIBIT 0x00000002
#define SR_CMD_INHIBIT 0x00000001
#define SR_APP_CMD 0x00000020
// INTERRUPT register settings
#define INT_DATA_TIMEOUT 0x00100000
#define INT_CMD_TIMEOUT 0x00010000
#define INT_READ_RDY 0x00000020
#define INT_CMD_DONE 0x00000001
#define INT_ERROR_MASK 0x017E8000
// CONTROL register settings
#define C0_SPI_MODE_EN 0x00100000
#define C0_HCTL_HS_EN 0x00000004
#define C0_HCTL_DWITDH 0x00000002
#define C1_SRST_DATA 0x04000000
#define C1_SRST_CMD 0x02000000
#define C1_SRST_HC 0x01000000
#define C1_TOUNIT_DIS 0x000f0000
#define C1_TOUNIT_MAX 0x000e0000
#define C1_CLK_GENSEL 0x00000020
#define C1_CLK_EN 0x00000004
#define C1_CLK_STABLE 0x00000002
#define C1_CLK_INTLEN 0x00000001
// SLOTISR_VER values
#define HOST_SPEC_NUM 0x00ff0000
#define HOST_SPEC_NUM_SHIFT 16
#define HOST_SPEC_V3 2
#define HOST_SPEC_V2 1
#define HOST_SPEC_V1 0
// SCR flags
#define SCR_SD_BUS_WIDTH_4 0x00000400
#define SCR_SUPP_SET_BLKCNT 0x02000000
// added by my driver
#define SCR_SUPP_CCS 0x00000001
#define ACMD41_VOLTAGE 0x00ff8000
#define ACMD41_CMD_COMPLETE 0x80000000
#define ACMD41_CMD_CCS 0x40000000
#define ACMD41_ARG_HC 0x51ff8000
unsigned long sd_scr[2], sd_ocr, sd_rca, sd_err, sd_hv;
/**
* Wait for data or command ready
*/
int sd_status(unsigned int mask)
{
int cnt = 500000; while((*EMMC_STATUS & mask) && !(*EMMC_INTERRUPT & INT_ERROR_MASK) && cnt--) wait_msec(1);
return (cnt <= 0 || (*EMMC_INTERRUPT & INT_ERROR_MASK)) ? SD_ERROR : SD_OK;
}
/**
* Wait for interrupt
*/
int sd_int(unsigned int mask)
{
unsigned int r, m=mask | INT_ERROR_MASK;
int cnt = 1000000; while(!(*EMMC_INTERRUPT & m) && cnt--) wait_msec(1);
r=*EMMC_INTERRUPT;
if(cnt<=0 || (r & INT_CMD_TIMEOUT) || (r & INT_DATA_TIMEOUT) ) { *EMMC_INTERRUPT=r; return SD_TIMEOUT; } else
if(r & INT_ERROR_MASK) { *EMMC_INTERRUPT=r; return SD_ERROR; }
*EMMC_INTERRUPT=mask;
return 0;
}
/**
* Send a command
*/
int sd_cmd(unsigned int code, unsigned int arg)
{
int r=0;
sd_err=SD_OK;
if(code&CMD_NEED_APP) {
r=sd_cmd(CMD_APP_CMD|(sd_rca?CMD_RSPNS_48:0),sd_rca);
if(sd_rca && !r) { uart_puts("ERROR: failed to send SD APP command\n"); sd_err=SD_ERROR;return 0;}
code &= ~CMD_NEED_APP;
}
if(sd_status(SR_CMD_INHIBIT)) { uart_puts("ERROR: EMMC busy\n"); sd_err= SD_TIMEOUT;return 0;}
uart_puts("EMMC: Sending command ");uart_hex(code);uart_puts(" arg ");uart_hex(arg);uart_send('\n');
*EMMC_INTERRUPT=*EMMC_INTERRUPT; *EMMC_ARG1=arg; *EMMC_CMDTM=code;
if(code==CMD_SEND_OP_COND) wait_msec(1000); else
if(code==CMD_SEND_IF_COND || code==CMD_APP_CMD) wait_msec(100);
if((r=sd_int(INT_CMD_DONE))) {uart_puts("ERROR: failed to send EMMC command\n");sd_err=r;return 0;}
r=*EMMC_RESP0;
if(code==CMD_GO_IDLE || code==CMD_APP_CMD) return 0; else
if(code==(CMD_APP_CMD|CMD_RSPNS_48)) return r&SR_APP_CMD; else
if(code==CMD_SEND_OP_COND) return r; else
if(code==CMD_SEND_IF_COND) return r==arg? SD_OK : SD_ERROR; else
if(code==CMD_ALL_SEND_CID) {r|=*EMMC_RESP3; r|=*EMMC_RESP2; r|=*EMMC_RESP1; return r; } else
if(code==CMD_SEND_REL_ADDR) {
sd_err=(((r&0x1fff))|((r&0x2000)<<6)|((r&0x4000)<<8)|((r&0x8000)<<8))&CMD_ERRORS_MASK;
return r&CMD_RCA_MASK;
}
return r&CMD_ERRORS_MASK;
// make gcc happy
return 0;
}
/**
* read a block from sd card and return the number of bytes read
* returns 0 on error.
*/
int sd_readblock(unsigned int lba, unsigned char *buffer, unsigned int num)
{
int r,c=0,d;
if(num<1) num=1;
uart_puts("sd_readblock lba ");uart_hex(lba);uart_puts(" num ");uart_hex(num);uart_send('\n');
if(sd_status(SR_DAT_INHIBIT)) {sd_err=SD_TIMEOUT; return 0;}
unsigned int *buf=(unsigned int *)buffer;
if(sd_scr[0] & SCR_SUPP_CCS) {
if(num > 1 && (sd_scr[0] & SCR_SUPP_SET_BLKCNT)) {
sd_cmd(CMD_SET_BLOCKCNT,num);
if(sd_err) return 0;
}
*EMMC_BLKSIZECNT = (num << 16) | 512;
sd_cmd(num == 1 ? CMD_READ_SINGLE : CMD_READ_MULTI,lba);
if(sd_err) return 0;
} else {
*EMMC_BLKSIZECNT = (1 << 16) | 512;
}
while( c < num ) {
if(!(sd_scr[0] & SCR_SUPP_CCS)) {
sd_cmd(CMD_READ_SINGLE,(lba+c)*512);
if(sd_err) return 0;
}
if((r=sd_int(INT_READ_RDY))){uart_puts("\rERROR: Timeout waiting for ready to read\n");sd_err=r;return 0;}
for(d=0;d<128;d++) buf[d] = *EMMC_DATA;
c++; buf+=128;
}
if( num > 1 && !(sd_scr[0] & SCR_SUPP_SET_BLKCNT) && (sd_scr[0] & SCR_SUPP_CCS)) sd_cmd(CMD_STOP_TRANS,0);
return sd_err!=SD_OK || c!=num? 0 : num*512;
}
/**
* set SD clock to frequency in Hz
*/
int sd_clk(unsigned int f)
{
unsigned int d,c=41666666/f,x,s=32,h=0;
int cnt = 100000;
while((*EMMC_STATUS & (SR_CMD_INHIBIT|SR_DAT_INHIBIT)) && cnt--) wait_msec(1);
if(cnt<=0) {
uart_puts("ERROR: timeout waiting for inhibit flag\n");
return SD_ERROR;
}
*EMMC_CONTROL1 &= ~C1_CLK_EN; wait_msec(10);
x=c-1; if(!x) s=0; else {
if(!(x & 0xffff0000u)) { x <<= 16; s -= 16; }
if(!(x & 0xff000000u)) { x <<= 8; s -= 8; }
if(!(x & 0xf0000000u)) { x <<= 4; s -= 4; }
if(!(x & 0xc0000000u)) { x <<= 2; s -= 2; }
if(!(x & 0x80000000u)) { x <<= 1; s -= 1; }
if(s>0) s--;
if(s>7) s=7;
}
if(sd_hv>HOST_SPEC_V2) d=c; else d=(1<<s);
if(d<=2) {d=2;s=0;}
uart_puts("sd_clk divisor ");uart_hex(d);uart_puts(", shift ");uart_hex(s);uart_send('\n');
if(sd_hv>HOST_SPEC_V2) h=(d&0x300)>>2;
d=(((d&0x0ff)<<8)|h);
*EMMC_CONTROL1=(*EMMC_CONTROL1&0xffff003f)|d; wait_msec(10);
*EMMC_CONTROL1 |= C1_CLK_EN; wait_msec(10);
cnt=10000; while(!(*EMMC_CONTROL1 & C1_CLK_STABLE) && cnt--) wait_msec(10);
if(cnt<=0) {
uart_puts("ERROR: failed to get stable clock\n");
return SD_ERROR;
}
return SD_OK;
}
/**
* initialize EMMC to read SDHC card
*/
int sd_init()
{
long r,cnt,ccs=0;
// GPIO_CD
r=*GPFSEL4; r&=~(7<<(7*3)); *GPFSEL4=r;
*GPPUD=2; wait_cycles(150); *GPPUDCLK1=(1<<15); wait_cycles(150); *GPPUD=0; *GPPUDCLK1=0;
r=*GPHEN1; r|=1<<15; *GPHEN1=r;
// GPIO_CLK, GPIO_CMD
r=*GPFSEL4; r|=(7<<(8*3))|(7<<(9*3)); *GPFSEL4=r;
*GPPUD=2; wait_cycles(150); *GPPUDCLK1=(1<<16)|(1<<17); wait_cycles(150); *GPPUD=0; *GPPUDCLK1=0;
// GPIO_DAT0, GPIO_DAT1, GPIO_DAT2, GPIO_DAT3
r=*GPFSEL5; r|=(7<<(0*3)) | (7<<(1*3)) | (7<<(2*3)) | (7<<(3*3)); *GPFSEL5=r;
*GPPUD=2; wait_cycles(150);
*GPPUDCLK1=(1<<18) | (1<<19) | (1<<20) | (1<<21);
wait_cycles(150); *GPPUD=0; *GPPUDCLK1=0;
sd_hv = (*EMMC_SLOTISR_VER & HOST_SPEC_NUM) >> HOST_SPEC_NUM_SHIFT;
uart_puts("EMMC: GPIO set up\n");
// Reset the card.
*EMMC_CONTROL0 = 0; *EMMC_CONTROL1 |= C1_SRST_HC;
cnt=10000; do{wait_msec(10);} while( (*EMMC_CONTROL1 & C1_SRST_HC) && cnt-- );
if(cnt<=0) {
uart_puts("ERROR: failed to reset EMMC\n");
return SD_ERROR;
}
uart_puts("EMMC: reset OK\n");
*EMMC_CONTROL1 |= C1_CLK_INTLEN | C1_TOUNIT_MAX;
wait_msec(10);
// Set clock to setup frequency.
if((r=sd_clk(400000))) return r;
*EMMC_INT_EN = 0xffffffff;
*EMMC_INT_MASK = 0xffffffff;
sd_scr[0]=sd_scr[1]=sd_rca=sd_err=0;
sd_cmd(CMD_GO_IDLE,0);
if(sd_err) return sd_err;
sd_cmd(CMD_SEND_IF_COND,0x000001AA);
if(sd_err) return sd_err;
cnt=6; r=0; while(!(r&ACMD41_CMD_COMPLETE) && cnt--) {
wait_cycles(400);
r=sd_cmd(CMD_SEND_OP_COND,ACMD41_ARG_HC);
uart_puts("EMMC: CMD_SEND_OP_COND returned ");
if(r&ACMD41_CMD_COMPLETE)
uart_puts("COMPLETE ");
if(r&ACMD41_VOLTAGE)
uart_puts("VOLTAGE ");
if(r&ACMD41_CMD_CCS)
uart_puts("CCS ");
uart_hex(r>>32);
uart_hex(r);
uart_send('\n');
if(sd_err!=SD_TIMEOUT && sd_err!=SD_OK ) {
uart_puts("ERROR: EMMC ACMD41 returned error\n");
return sd_err;
}
}
if(!(r&ACMD41_CMD_COMPLETE) || !cnt ) return SD_TIMEOUT;
if(!(r&ACMD41_VOLTAGE)) return SD_ERROR;
if(r&ACMD41_CMD_CCS) ccs=SCR_SUPP_CCS;
sd_cmd(CMD_ALL_SEND_CID,0);
sd_rca = sd_cmd(CMD_SEND_REL_ADDR,0);
uart_puts("EMMC: CMD_SEND_REL_ADDR returned ");
uart_hex(sd_rca>>32);
uart_hex(sd_rca);
uart_send('\n');
if(sd_err) return sd_err;
if((r=sd_clk(25000000))) return r;
sd_cmd(CMD_CARD_SELECT,sd_rca);
if(sd_err) return sd_err;
if(sd_status(SR_DAT_INHIBIT)) return SD_TIMEOUT;
*EMMC_BLKSIZECNT = (1<<16) | 8;
sd_cmd(CMD_SEND_SCR,0);
if(sd_err) return sd_err;
if(sd_int(INT_READ_RDY)) return SD_TIMEOUT;
r=0; cnt=100000; while(r<2 && cnt) {
if( *EMMC_STATUS & SR_READ_AVAILABLE )
sd_scr[r++] = *EMMC_DATA;
else
wait_msec(1);
}
if(r!=2) return SD_TIMEOUT;
if(sd_scr[0] & SCR_SD_BUS_WIDTH_4) {
sd_cmd(CMD_SET_BUS_WIDTH,sd_rca|2);
if(sd_err) return sd_err;
*EMMC_CONTROL0 |= C0_HCTL_DWITDH;
}
// add software flag
uart_puts("EMMC: supports ");
if(sd_scr[0] & SCR_SUPP_SET_BLKCNT)
uart_puts("SET_BLKCNT ");
if(ccs)
uart_puts("CCS ");
uart_send('\n');
sd_scr[0]&=~SCR_SUPP_CCS;
sd_scr[0]|=ccs;
return SD_OK;
}

@ -1,31 +0,0 @@
/*
* Copyright (C) 2018 bzt (bztsrc@github)
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use, copy,
* modify, merge, publish, distribute, sublicense, and/or sell copies
* of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
*/
#define SD_OK 0
#define SD_TIMEOUT -1
#define SD_ERROR -2
int sd_init();
int sd_readblock(unsigned int lba, unsigned char *buffer, unsigned int num);

@ -1,55 +0,0 @@
/*
* Copyright (C) 2018 bzt (bztsrc@github)
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use, copy,
* modify, merge, publish, distribute, sublicense, and/or sell copies
* of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
*/
.section ".text.boot"
.global _start
_start:
// read cpu id, stop slave cores
mrs x1, mpidr_el1
and x1, x1, #3
cbz x1, 2f
// cpu id > 0, stop
1: wfe
b 1b
2: // cpu id == 0
// set stack before our code
ldr x1, =_start
mov sp, x1
// clear bss
ldr x1, =__bss_start
ldr w2, =__bss_size
3: cbz w2, 4f
str xzr, [x1], #8
sub w2, w2, #1
cbnz w2, 3b
// jump to C code, should not return
4: bl main
// for failsafe, halt this core too
b 1b

@ -1,153 +0,0 @@
/*
* Copyright (C) 2018 bzt (bztsrc@github)
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use, copy,
* modify, merge, publish, distribute, sublicense, and/or sell copies
* of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
*/
#include "gpio.h"
#include "mbox.h"
#include "delays.h"
/* PL011 UART registers */
#define UART0_DR ((volatile unsigned int*)(MMIO_BASE+0x00201000))
#define UART0_FR ((volatile unsigned int*)(MMIO_BASE+0x00201018))
#define UART0_IBRD ((volatile unsigned int*)(MMIO_BASE+0x00201024))
#define UART0_FBRD ((volatile unsigned int*)(MMIO_BASE+0x00201028))
#define UART0_LCRH ((volatile unsigned int*)(MMIO_BASE+0x0020102C))
#define UART0_CR ((volatile unsigned int*)(MMIO_BASE+0x00201030))
#define UART0_IMSC ((volatile unsigned int*)(MMIO_BASE+0x00201038))
#define UART0_ICR ((volatile unsigned int*)(MMIO_BASE+0x00201044))
/**
* Set baud rate and characteristics (115200 8N1) and map to GPIO
*/
void uart_init()
{
register unsigned int r;
/* initialize UART */
*UART0_CR = 0; // turn off UART0
/* set up clock for consistent divisor values */
mbox[0] = 8*4;
mbox[1] = MBOX_REQUEST;
mbox[2] = MBOX_TAG_SETCLKRATE; // set clock rate
mbox[3] = 12;
mbox[4] = 8;
mbox[5] = 2; // UART clock
mbox[6] = 4000000; // 4Mhz
mbox[7] = MBOX_TAG_LAST;
mbox_call(MBOX_CH_PROP);
/* map UART0 to GPIO pins */
r=*GPFSEL1;
r&=~((7<<12)|(7<<15)); // gpio14, gpio15
r|=(4<<12)|(4<<15); // alt0
*GPFSEL1 = r;
*GPPUD = 0; // enable pins 14 and 15
wait_cycles(150);
*GPPUDCLK0 = (1<<14)|(1<<15);
wait_cycles(150);
*GPPUDCLK0 = 0; // flush GPIO setup
*UART0_ICR = 0x7FF; // clear interrupts
*UART0_IBRD = 2; // 115200 baud
*UART0_FBRD = 0xB;
*UART0_LCRH = 0b11<<5; // 8n1
*UART0_CR = 0x301; // enable Tx, Rx, FIFO
}
/**
* Send a character
*/
void uart_send(unsigned int c) {
/* wait until we can send */
do{asm volatile("nop");}while(*UART0_FR&0x20);
/* write the character to the buffer */
*UART0_DR=c;
}
/**
* Receive a character
*/
char uart_getc() {
char r;
/* wait until something is in the buffer */
do{asm volatile("nop");}while(*UART0_FR&0x10);
/* read it and return */
r=(char)(*UART0_DR);
/* convert carrige return to newline */
return r=='\r'?'\n':r;
}
/**
* Display a string
*/
void uart_puts(char *s) {
while(*s) {
/* convert newline to carrige return + newline */
if(*s=='\n')
uart_send('\r');
uart_send(*s++);
}
}
/**
* Display a binary value in hexadecimal
*/
void uart_hex(unsigned int d) {
unsigned int n;
int c;
for(c=28;c>=0;c-=4) {
// get highest tetrad
n=(d>>c)&0xF;
// 0-9 => '0'-'9', 10-15 => 'A'-'F'
n+=n>9?0x37:0x30;
uart_send(n);
}
}
/**
* Dump memory
*/
void uart_dump(void *ptr)
{
unsigned long a,b,d;
unsigned char c;
for(a=(unsigned long)ptr;a<(unsigned long)ptr+512;a+=16) {
uart_hex(a); uart_puts(": ");
for(b=0;b<16;b++) {
c=*((unsigned char*)(a+b));
d=(unsigned int)c;d>>=4;d&=0xF;d+=d>9?0x37:0x30;uart_send(d);
d=(unsigned int)c;d&=0xF;d+=d>9?0x37:0x30;uart_send(d);
uart_send(' ');
if(b%4==3)
uart_send(' ');
}
for(b=0;b<16;b++) {
c=*((unsigned char*)(a+b));
uart_send(c<32||c>=127?'.':c);
}
uart_send('\r');
uart_send('\n');
}
}

@ -1,31 +0,0 @@
/*
* Copyright (C) 2018 bzt (bztsrc@github)
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use, copy,
* modify, merge, publish, distribute, sublicense, and/or sell copies
* of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
*/
void uart_init();
void uart_send(unsigned int c);
char uart_getc();
void uart_puts(char *s);
void uart_hex(unsigned int d);
void uart_dump(void *ptr);

@ -1,43 +0,0 @@
#
# Copyright (C) 2018 bzt (bztsrc@github)
#
# Permission is hereby granted, free of charge, to any person
# obtaining a copy of this software and associated documentation
# files (the "Software"), to deal in the Software without
# restriction, including without limitation the rights to use, copy,
# modify, merge, publish, distribute, sublicense, and/or sell copies
# of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be
# included in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
# HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
# DEALINGS IN THE SOFTWARE.
#
#
SRCS = $(wildcard *.c)
OBJS = $(SRCS:.c=.o)
CFLAGS = -Wall -O2 -ffreestanding -nostdinc -nostdlib -nostartfiles
all: clean kernel8.img
start.o: start.S
aarch64-elf-gcc $(CFLAGS) -c start.S -o start.o
%.o: %.c
aarch64-elf-gcc $(CFLAGS) -c $< -o $@
kernel8.img: start.o $(OBJS)
aarch64-elf-ld -nostdlib -nostartfiles start.o $(OBJS) -T link.ld -o kernel8.elf
aarch64-elf-objcopy -O binary kernel8.elf kernel8.img
clean:
rm kernel8.elf *.o >/dev/null 2>/dev/null || true

@ -1,45 +0,0 @@
Oktatóanyag 0D - Fájl Beolvasása
================================
Megtanultuk, hogy kell beolvasni és értelmezni a gyökérkönyvtárat. Ebben az oktatóanyagban fogunk egy fájlt
a gyökérkönyvtárból, és a kluszterláncát végigjárva teljes egészében betöltjük a memóriába.
```sh
$ qemu-system-aarch64 -M raspi3 -drive file=test.dd,if=sd,format=raw -serial stdio
... kimenet törölve az átláthatóság miatt ...
FAT File LICENC~1BRO starts at cluster: 00000192
FAT Bytes per Sector: 00000200
FAT Sectors per Cluster: 00000004
FAT Number of FAT: 00000002
FAT Sectors per FAT: 00000014
FAT Reserved Sectors Count: 00000004
FAT First data sector: 00000054
... kimenet törölve az átláthatóság miatt ...
00085020: 43 6F 70 79 72 69 67 68 74 20 28 63 29 20 32 30 Copyright (c) 20
00085030: 30 36 2C 20 42 72 6F 61 64 63 6F 6D 20 43 6F 72 06, Broadcom Cor
00085040: 70 6F 72 61 74 69 6F 6E 2E 0A 43 6F 70 79 72 69 poration..Copyri
00085050: 67 68 74 20 28 63 29 20 32 30 31 35 2C 20 52 61 ght (c) 2015, Ra
00085060: 73 70 62 65 72 72 79 20 50 69 20 28 54 72 61 64 spberry Pi (Trad
00085070: 69 6E 67 29 20 4C 74 64 0A 41 6C 6C 20 72 69 67 ing) Ltd.All rig
... kimenet törölve az átláthatóság miatt ...
```
Fat.h, fat.c
------------
Ez is elég egyszerű és jól dokumentált. Megkeressük a fájlukhoz tartozó könyvtárbejegyzést, és kivesszük
belóle az induló kluszter számát. Ezután minden egyes klusztert betöltünk miközben végigjárjuk a láncot.
`fat_getpartition()` betölti és értelmezi a partíció első szektorát.
`fat_getcluster(fn)` visszaadja egy adott fájlnévhez tartozó kluszterlánc első tagját.
`fat_readfile(clu)` rbeolvas egy fájlt a memóriába. Visszatérési értéke egy mutató a legelső beolvasott bájtra.
Main
----
Miután inicializájuk az EMMC-t szektorok olvasásához, beolvassuk az első szektort a partícióról. Ha a BPB
egy érvényes FAT fájlrendszert ír le, akkor megkeressük a 'LICENCE.broadcom'-hoz tartozó első kluszter számát.
Ha ilyent nem találunk, akkor a 'kernel8.img'-t keresünk. Ha bármelyiket megtaláltuk, akkor betöltjük és
kidumpoljuk a fájl első 512 bájtját.

@ -1,44 +0,0 @@
Tutorial 0D - Read File
=======================
We learned how to read and parse the root directory. In this tutorial we'll get one file from the
root directory, and walk through the cluster chain to load it entirely into memory.
```sh
$ qemu-system-aarch64 -M raspi3 -drive file=test.dd,if=sd,format=raw -serial stdio
... output removed for clearity ...
FAT File LICENC~1BRO starts at cluster: 00000192
FAT Bytes per Sector: 00000200
FAT Sectors per Cluster: 00000004
FAT Number of FAT: 00000002
FAT Sectors per FAT: 00000014
FAT Reserved Sectors Count: 00000004
FAT First data sector: 00000054
... output removed for clearity ...
00085020: 43 6F 70 79 72 69 67 68 74 20 28 63 29 20 32 30 Copyright (c) 20
00085030: 30 36 2C 20 42 72 6F 61 64 63 6F 6D 20 43 6F 72 06, Broadcom Cor
00085040: 70 6F 72 61 74 69 6F 6E 2E 0A 43 6F 70 79 72 69 poration..Copyri
00085050: 67 68 74 20 28 63 29 20 32 30 31 35 2C 20 52 61 ght (c) 2015, Ra
00085060: 73 70 62 65 72 72 79 20 50 69 20 28 54 72 61 64 spberry Pi (Trad
00085070: 69 6E 67 29 20 4C 74 64 0A 41 6C 6C 20 72 69 67 ing) Ltd.All rig
... output removed for clearity ...
```
Fat.h, fat.c
------------
This is also easy and pretty well documented. We locate the directory entry for our file, and get
the starting cluster number. Then we load each cluster into memory as we walk the cluster chain.
`fat_getpartition()` load and check the boot record of the first MBR partition.
`fat_getcluster(fn)` return the starting cluster for the given filename.
`fat_readfile(clu)` reads a file into memory, returns pointer to the first byte.
Main
----
Once we initialize EMMC to read sectors, we load the boot record of the first partition. If the BPB
describes a valid FAT partition, we find the starting cluster for the file 'LICENCE.broadcom'. If that
not found, we'll look for 'kernel8.img'. If any of these found, we load it and dump it's first 512 bytes.

@ -1,81 +0,0 @@
/*
* Copyright (C) 2018 bzt (bztsrc@github)
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use, copy,
* modify, merge, publish, distribute, sublicense, and/or sell copies
* of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
*/
#include "gpio.h"
#define SYSTMR_LO ((volatile unsigned int*)(MMIO_BASE+0x00003004))
#define SYSTMR_HI ((volatile unsigned int*)(MMIO_BASE+0x00003008))
/**
* Wait N CPU cycles (ARM CPU only)
*/
void wait_cycles(unsigned int n)
{
if(n) while(n--) { asm volatile("nop"); }
}
/**
* Wait N microsec (ARM CPU only)
*/
void wait_msec(unsigned int n)
{
register unsigned long f, t, r;
// get the current counter frequency
asm volatile ("mrs %0, cntfrq_el0" : "=r"(f));
// read the current counter
asm volatile ("mrs %0, cntpct_el0" : "=r"(t));
// calculate expire value for counter
t+=((f/1000)*n)/1000;
do{asm volatile ("mrs %0, cntpct_el0" : "=r"(r));}while(r<t);
}
/**
* Get System Timer's counter
*/
unsigned long get_system_timer()
{
unsigned int h=-1, l;
// we must read MMIO area as two separate 32 bit reads
h=*SYSTMR_HI;
l=*SYSTMR_LO;
// we have to repeat it if high word changed during read
if(h!=*SYSTMR_HI) {
h=*SYSTMR_HI;
l=*SYSTMR_LO;
}
// compose long int value
return ((unsigned long) h << 32) | l;
}
/**
* Wait N microsec (with BCM System Timer)
*/
void wait_msec_st(unsigned int n)
{
unsigned long t=get_system_timer();
// we must check if it's non-zero, because qemu does not emulate
// system timer, and returning constant zero would mean infinite loop
if(t) while(get_system_timer() < t+n);
}

@ -1,29 +0,0 @@
/*
* Copyright (C) 2018 bzt (bztsrc@github)
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use, copy,
* modify, merge, publish, distribute, sublicense, and/or sell copies
* of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
*/
void wait_cycles(unsigned int n);
void wait_msec(unsigned int n);
unsigned long get_system_timer();
void wait_msec_st(unsigned int n);

@ -1,208 +0,0 @@
/*
* Copyright (C) 2018 bzt (bztsrc@github)
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use, copy,
* modify, merge, publish, distribute, sublicense, and/or sell copies
* of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
*/
#include "sd.h"
#include "uart.h"
// get the end of bss segment from linker
extern unsigned char _end;
unsigned int partitionlba;
// the BIOS Parameter Block (in Volume Boot Record)
typedef struct {
char jmp[3];
char oem[8];
unsigned short bps;
unsigned char spc;
unsigned short rsc;
unsigned char nf;
unsigned short nr;
unsigned short ts16;
unsigned char media;
unsigned short spf16;
unsigned short spt;
unsigned short nh;
unsigned int hs;
unsigned int ts32;
unsigned int spf32;
unsigned int flg;
unsigned int rc;
char vol[6];
char fst[8];
char dmy[20];
char fst2[8];
} __attribute__((packed)) bpb_t;
// directory entry structure
typedef struct {
char name[8];
char ext[3];
char attr[9];
unsigned short ch;
unsigned int attr2;
unsigned short cl;
unsigned int size;
} __attribute__((packed)) fatdir_t;
/**
* Get the starting LBA address of the first partition
* so that we know where our FAT file system starts, and
* read that volume's BIOS Parameter Block
*/
int fat_getpartition()
{
unsigned char *mbr=&_end;
bpb_t *bpb=(bpb_t*)&_end;
// read the partitioning table
if(sd_readblock(0,&_end,1)) {
// check magic
if(mbr[510]!=0x55 || mbr[511]!=0xAA) {
uart_puts("ERROR: Bad magic in MBR\n");
return 0;
}
// check partition type
if(mbr[0x1C2]!=0xE/*FAT16 LBA*/ && mbr[0x1C2]!=0xC/*FAT32 LBA*/) {
uart_puts("ERROR: Wrong partition type\n");
return 0;
}
partitionlba=*((unsigned int*)((unsigned long)&_end+0x1C6));
// read the boot record
if(!sd_readblock(partitionlba,&_end,1)) {
uart_puts("ERROR: Unable to read boot record\n");
return 0;
}
// check file system type. We don't use cluster numbers for that, but magic bytes
if( !(bpb->fst[0]=='F' && bpb->fst[1]=='A' && bpb->fst[2]=='T') &&
!(bpb->fst2[0]=='F' && bpb->fst2[1]=='A' && bpb->fst2[2]=='T')) {
uart_puts("ERROR: Unknown file system type\n");
return 0;
}
return 1;
}
return 0;
}
/**
* Find a file in root directory entries
*/
unsigned int fat_getcluster(char *fn)
{
bpb_t *bpb=(bpb_t*)&_end;
fatdir_t *dir=(fatdir_t*)(&_end+512);
unsigned int root_sec, s;
// find the root directory's LBA
root_sec=((bpb->spf16?bpb->spf16:bpb->spf32)*bpb->nf)+bpb->rsc;
//WARNING gcc generates bad code for bpb->nr, causing unaligned exception
s=*((unsigned int*)&bpb->nf);
s>>=8;
s&=0xFFFF;
s<<=5;
// now s=bpb->nr*sizeof(fatdir_t));
if(bpb->spf16==0) {
// adjust for FAT32
root_sec+=(bpb->rc-2)*bpb->spc;
}
// add partition LBA
root_sec+=partitionlba;
// load the root directory
if(sd_readblock(root_sec,(unsigned char*)dir,s/512+1)) {
// iterate on each entry and check if it's the one we're looking for
for(;dir->name[0]!=0;dir++) {
// is it a valid entry?
if(dir->name[0]==0xE5 || dir->attr[0]==0xF) continue;
// filename match?
if(!__builtin_memcmp(dir->name,fn,11)) {
uart_puts("FAT File ");
uart_puts(fn);
uart_puts(" starts at cluster: ");
uart_hex(((unsigned int)dir->ch)<<16|dir->cl);
uart_puts("\n");
// if so, return starting cluster
return ((unsigned int)dir->ch)<<16|dir->cl;
}
}
uart_puts("ERROR: file not found\n");
} else {
uart_puts("ERROR: Unable to load root directory\n");
}
return 0;
}
/**
* Read a file into memory
*/
char *fat_readfile(unsigned int cluster)
{
// BIOS Parameter Block
bpb_t *bpb=(bpb_t*)&_end;
// File allocation tables. We choose between FAT16 and FAT32 dynamically
unsigned int *fat32=(unsigned int*)(&_end+bpb->rsc*512);
unsigned short *fat16=(unsigned short*)fat32;
// Data pointers
unsigned int data_sec, s;
unsigned char *data, *ptr;
// find the LBA of the first data sector
data_sec=((bpb->spf16?bpb->spf16:bpb->spf32)*bpb->nf)+bpb->rsc;
//WARNING gcc generates bad code for bpb->nr, causing unaligned exception
s=*((unsigned int*)&bpb->nf);
s>>=8;
s&=0xFFFF;
s<<=5;
if(bpb->spf16>0) {
// adjust for FAT16
data_sec+=(s+511)>>9;
}
// add partition LBA
data_sec+=partitionlba;
// dump important properties
uart_puts("FAT Bytes per Sector: ");
uart_hex(bpb->bps);
uart_puts("\nFAT Sectors per Cluster: ");
uart_hex(bpb->spc);
uart_puts("\nFAT Number of FAT: ");
uart_hex(bpb->nf);
uart_puts("\nFAT Sectors per FAT: ");
uart_hex((bpb->spf16?bpb->spf16:bpb->spf32));
uart_puts("\nFAT Reserved Sectors Count: ");
uart_hex(bpb->rsc);
uart_puts("\nFAT First data sector: ");
uart_hex(data_sec);
uart_puts("\n");
// load FAT table
s=sd_readblock(partitionlba+1,(unsigned char*)&_end+512,(bpb->spf16?bpb->spf16:bpb->spf32)+bpb->rsc);
// end of FAT in memory
data=ptr=&_end+512+s;
// iterate on cluster chain
while(cluster>1 && cluster<0xFFF8) {
// load all sectors in a cluster
sd_readblock((cluster-2)*bpb->spc+data_sec,ptr,bpb->spc);
// move pointer, sector per cluster * bytes per sector
ptr+=bpb->spc*bpb->bps;
// get the next cluster in chain
cluster=bpb->spf16>0?fat16[cluster]:fat32[cluster];
}
return (char*)data;
}

@ -1,28 +0,0 @@
/*
* Copyright (C) 2018 bzt (bztsrc@github)
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use, copy,
* modify, merge, publish, distribute, sublicense, and/or sell copies
* of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
*/
int fat_getpartition();
unsigned int fat_getcluster(char *fn);
char *fat_readfile(unsigned int cluster);

@ -1,45 +0,0 @@
/*
* Copyright (C) 2018 bzt (bztsrc@github)
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use, copy,
* modify, merge, publish, distribute, sublicense, and/or sell copies
* of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
*/
#define MMIO_BASE 0x3F000000
#define GPFSEL0 ((volatile unsigned int*)(MMIO_BASE+0x00200000))
#define GPFSEL1 ((volatile unsigned int*)(MMIO_BASE+0x00200004))
#define GPFSEL2 ((volatile unsigned int*)(MMIO_BASE+0x00200008))
#define GPFSEL3 ((volatile unsigned int*)(MMIO_BASE+0x0020000C))
#define GPFSEL4 ((volatile unsigned int*)(MMIO_BASE+0x00200010))
#define GPFSEL5 ((volatile unsigned int*)(MMIO_BASE+0x00200014))
#define GPSET0 ((volatile unsigned int*)(MMIO_BASE+0x0020001C))
#define GPSET1 ((volatile unsigned int*)(MMIO_BASE+0x00200020))
#define GPCLR0 ((volatile unsigned int*)(MMIO_BASE+0x00200028))
#define GPLEV0 ((volatile unsigned int*)(MMIO_BASE+0x00200034))
#define GPLEV1 ((volatile unsigned int*)(MMIO_BASE+0x00200038))
#define GPEDS0 ((volatile unsigned int*)(MMIO_BASE+0x00200040))
#define GPEDS1 ((volatile unsigned int*)(MMIO_BASE+0x00200044))
#define GPHEN0 ((volatile unsigned int*)(MMIO_BASE+0x00200064))
#define GPHEN1 ((volatile unsigned int*)(MMIO_BASE+0x00200068))
#define GPPUD ((volatile unsigned int*)(MMIO_BASE+0x00200094))
#define GPPUDCLK0 ((volatile unsigned int*)(MMIO_BASE+0x00200098))
#define GPPUDCLK1 ((volatile unsigned int*)(MMIO_BASE+0x0020009C))

Binary file not shown.

@ -1,44 +0,0 @@
/*
* Copyright (C) 2018 bzt (bztsrc@github)
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use, copy,
* modify, merge, publish, distribute, sublicense, and/or sell copies
* of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
*/
SECTIONS
{
. = 0x80000;
.text : { KEEP(*(.text.boot)) *(.text .text.* .gnu.linkonce.t*) }
.rodata : { *(.rodata .rodata.* .gnu.linkonce.r*) }
PROVIDE(_data = .);
.data : { *(.data .data.* .gnu.linkonce.d*) }
.bss (NOLOAD) : {
. = ALIGN(16);
__bss_start = .;
*(.bss .bss.*)
*(COMMON)
__bss_end = .;
}
_end = .;
/DISCARD/ : { *(.comment) *(.gnu*) *(.note*) *(.eh_frame*) }
}
__bss_size = (__bss_end - __bss_start)>>3;

@ -1,57 +0,0 @@
/*
* Copyright (C) 2018 bzt (bztsrc@github)
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use, copy,
* modify, merge, publish, distribute, sublicense, and/or sell copies
* of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
*/
#include "uart.h"
#include "sd.h"
#include "fat.h"
void main()
{
unsigned int cluster;
// set up serial console
uart_init();
// initialize EMMC and detect SD card type
if(sd_init()==SD_OK) {
// read the master boot record and find our partition
if(fat_getpartition()) {
// find out file in root directory entries
cluster=fat_getcluster("LICENC~1BRO");
if(cluster==0)
cluster=fat_getcluster("KERNEL8 IMG");
if(cluster) {
// read into memory
uart_dump(fat_readfile(cluster));
}
} else {
uart_puts("FAT partition not found???\n");
}
}
// echo everything back
while(1) {
uart_send(uart_getc());
}
}

@ -1,63 +0,0 @@
/*
* Copyright (C) 2018 bzt (bztsrc@github)
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use, copy,
* modify, merge, publish, distribute, sublicense, and/or sell copies
* of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
*/
#include "gpio.h"
/* mailbox message buffer */
volatile unsigned int __attribute__((aligned(16))) mbox[36];
#define VIDEOCORE_MBOX (MMIO_BASE+0x0000B880)
#define MBOX_READ ((volatile unsigned int*)(VIDEOCORE_MBOX+0x0))
#define MBOX_POLL ((volatile unsigned int*)(VIDEOCORE_MBOX+0x10))
#define MBOX_SENDER ((volatile unsigned int*)(VIDEOCORE_MBOX+0x14))
#define MBOX_STATUS ((volatile unsigned int*)(VIDEOCORE_MBOX+0x18))
#define MBOX_CONFIG ((volatile unsigned int*)(VIDEOCORE_MBOX+0x1C))
#define MBOX_WRITE ((volatile unsigned int*)(VIDEOCORE_MBOX+0x20))
#define MBOX_RESPONSE 0x80000000
#define MBOX_FULL 0x80000000
#define MBOX_EMPTY 0x40000000
/**
* Make a mailbox call. Returns 0 on failure, non-zero on success
*/
int mbox_call(unsigned char ch)
{
unsigned int r;
/* wait until we can write to the mailbox */
do{asm volatile("nop");}while(*MBOX_STATUS & MBOX_FULL);
/* write the address of our message to the mailbox with channel identifier */
*MBOX_WRITE = (((unsigned int)((unsigned long)&mbox)&~0xF) | (ch&0xF));
/* now wait for the response */
while(1) {
/* is there a response? */
do{asm volatile("nop");}while(*MBOX_STATUS & MBOX_EMPTY);
r=*MBOX_READ;
/* is it a response to our message? */
if((unsigned char)(r&0xF)==ch && (r&~0xF)==(unsigned int)((unsigned long)&mbox))
/* is it a valid successful response? */
return mbox[1]==MBOX_RESPONSE;
}
return 0;
}

@ -1,47 +0,0 @@
/*
* Copyright (C) 2018 bzt (bztsrc@github)
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use, copy,
* modify, merge, publish, distribute, sublicense, and/or sell copies
* of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
*/
/* a properly aligned buffer */
extern volatile unsigned int mbox[36];
#define MBOX_REQUEST 0
/* channels */
#define MBOX_CH_POWER 0
#define MBOX_CH_FB 1
#define MBOX_CH_VUART 2
#define MBOX_CH_VCHIQ 3
#define MBOX_CH_LEDS 4
#define MBOX_CH_BTNS 5
#define MBOX_CH_TOUCH 6
#define MBOX_CH_COUNT 7
#define MBOX_CH_PROP 8
/* tags */
#define MBOX_TAG_SETPOWER 0x28001
#define MBOX_TAG_SETCLKRATE 0x38002
#define MBOX_TAG_LAST 0
int mbox_call(unsigned char ch);

@ -1,355 +0,0 @@
/*
* Copyright (C) 2018 bzt (bztsrc@github)
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use, copy,
* modify, merge, publish, distribute, sublicense, and/or sell copies
* of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
*/
#include "gpio.h"
#include "uart.h"
#include "delays.h"
#include "sd.h"
#define EMMC_ARG2 ((volatile unsigned int*)(MMIO_BASE+0x00300000))
#define EMMC_BLKSIZECNT ((volatile unsigned int*)(MMIO_BASE+0x00300004))
#define EMMC_ARG1 ((volatile unsigned int*)(MMIO_BASE+0x00300008))
#define EMMC_CMDTM ((volatile unsigned int*)(MMIO_BASE+0x0030000C))
#define EMMC_RESP0 ((volatile unsigned int*)(MMIO_BASE+0x00300010))
#define EMMC_RESP1 ((volatile unsigned int*)(MMIO_BASE+0x00300014))
#define EMMC_RESP2 ((volatile unsigned int*)(MMIO_BASE+0x00300018))
#define EMMC_RESP3 ((volatile unsigned int*)(MMIO_BASE+0x0030001C))
#define EMMC_DATA ((volatile unsigned int*)(MMIO_BASE+0x00300020))
#define EMMC_STATUS ((volatile unsigned int*)(MMIO_BASE+0x00300024))
#define EMMC_CONTROL0 ((volatile unsigned int*)(MMIO_BASE+0x00300028))
#define EMMC_CONTROL1 ((volatile unsigned int*)(MMIO_BASE+0x0030002C))
#define EMMC_INTERRUPT ((volatile unsigned int*)(MMIO_BASE+0x00300030))
#define EMMC_INT_MASK ((volatile unsigned int*)(MMIO_BASE+0x00300034))
#define EMMC_INT_EN ((volatile unsigned int*)(MMIO_BASE+0x00300038))
#define EMMC_CONTROL2 ((volatile unsigned int*)(MMIO_BASE+0x0030003C))
#define EMMC_SLOTISR_VER ((volatile unsigned int*)(MMIO_BASE+0x003000FC))
// command flags
#define CMD_NEED_APP 0x80000000
#define CMD_RSPNS_48 0x00020000
#define CMD_ERRORS_MASK 0xfff9c004
#define CMD_RCA_MASK 0xffff0000
// COMMANDs
#define CMD_GO_IDLE 0x00000000
#define CMD_ALL_SEND_CID 0x02010000
#define CMD_SEND_REL_ADDR 0x03020000
#define CMD_CARD_SELECT 0x07030000
#define CMD_SEND_IF_COND 0x08020000
#define CMD_STOP_TRANS 0x0C030000
#define CMD_READ_SINGLE 0x11220010
#define CMD_READ_MULTI 0x12220032
#define CMD_SET_BLOCKCNT 0x17020000
#define CMD_APP_CMD 0x37000000
#define CMD_SET_BUS_WIDTH (0x06020000|CMD_NEED_APP)
#define CMD_SEND_OP_COND (0x29020000|CMD_NEED_APP)
#define CMD_SEND_SCR (0x33220010|CMD_NEED_APP)
// STATUS register settings
#define SR_READ_AVAILABLE 0x00000800
#define SR_DAT_INHIBIT 0x00000002
#define SR_CMD_INHIBIT 0x00000001
#define SR_APP_CMD 0x00000020
// INTERRUPT register settings
#define INT_DATA_TIMEOUT 0x00100000
#define INT_CMD_TIMEOUT 0x00010000
#define INT_READ_RDY 0x00000020
#define INT_CMD_DONE 0x00000001
#define INT_ERROR_MASK 0x017E8000
// CONTROL register settings
#define C0_SPI_MODE_EN 0x00100000
#define C0_HCTL_HS_EN 0x00000004
#define C0_HCTL_DWITDH 0x00000002
#define C1_SRST_DATA 0x04000000
#define C1_SRST_CMD 0x02000000
#define C1_SRST_HC 0x01000000
#define C1_TOUNIT_DIS 0x000f0000
#define C1_TOUNIT_MAX 0x000e0000
#define C1_CLK_GENSEL 0x00000020
#define C1_CLK_EN 0x00000004
#define C1_CLK_STABLE 0x00000002
#define C1_CLK_INTLEN 0x00000001
// SLOTISR_VER values
#define HOST_SPEC_NUM 0x00ff0000
#define HOST_SPEC_NUM_SHIFT 16
#define HOST_SPEC_V3 2
#define HOST_SPEC_V2 1
#define HOST_SPEC_V1 0
// SCR flags
#define SCR_SD_BUS_WIDTH_4 0x00000400
#define SCR_SUPP_SET_BLKCNT 0x02000000
// added by my driver
#define SCR_SUPP_CCS 0x00000001
#define ACMD41_VOLTAGE 0x00ff8000
#define ACMD41_CMD_COMPLETE 0x80000000
#define ACMD41_CMD_CCS 0x40000000
#define ACMD41_ARG_HC 0x51ff8000
unsigned long sd_scr[2], sd_ocr, sd_rca, sd_err, sd_hv;
/**
* Wait for data or command ready
*/
int sd_status(unsigned int mask)
{
int cnt = 500000; while((*EMMC_STATUS & mask) && !(*EMMC_INTERRUPT & INT_ERROR_MASK) && cnt--) wait_msec(1);
return (cnt <= 0 || (*EMMC_INTERRUPT & INT_ERROR_MASK)) ? SD_ERROR : SD_OK;
}
/**
* Wait for interrupt
*/
int sd_int(unsigned int mask)
{
unsigned int r, m=mask | INT_ERROR_MASK;
int cnt = 1000000; while(!(*EMMC_INTERRUPT & m) && cnt--) wait_msec(1);
r=*EMMC_INTERRUPT;
if(cnt<=0 || (r & INT_CMD_TIMEOUT) || (r & INT_DATA_TIMEOUT) ) { *EMMC_INTERRUPT=r; return SD_TIMEOUT; } else
if(r & INT_ERROR_MASK) { *EMMC_INTERRUPT=r; return SD_ERROR; }
*EMMC_INTERRUPT=mask;
return 0;
}
/**
* Send a command
*/
int sd_cmd(unsigned int code, unsigned int arg)
{
int r=0;
sd_err=SD_OK;
if(code&CMD_NEED_APP) {
r=sd_cmd(CMD_APP_CMD|(sd_rca?CMD_RSPNS_48:0),sd_rca);
if(sd_rca && !r) { uart_puts("ERROR: failed to send SD APP command\n"); sd_err=SD_ERROR;return 0;}
code &= ~CMD_NEED_APP;
}
if(sd_status(SR_CMD_INHIBIT)) { uart_puts("ERROR: EMMC busy\n"); sd_err= SD_TIMEOUT;return 0;}
uart_puts("EMMC: Sending command ");uart_hex(code);uart_puts(" arg ");uart_hex(arg);uart_send('\n');
*EMMC_INTERRUPT=*EMMC_INTERRUPT; *EMMC_ARG1=arg; *EMMC_CMDTM=code;
if(code==CMD_SEND_OP_COND) wait_msec(1000); else
if(code==CMD_SEND_IF_COND || code==CMD_APP_CMD) wait_msec(100);
if((r=sd_int(INT_CMD_DONE))) {uart_puts("ERROR: failed to send EMMC command\n");sd_err=r;return 0;}
r=*EMMC_RESP0;
if(code==CMD_GO_IDLE || code==CMD_APP_CMD) return 0; else
if(code==(CMD_APP_CMD|CMD_RSPNS_48)) return r&SR_APP_CMD; else
if(code==CMD_SEND_OP_COND) return r; else
if(code==CMD_SEND_IF_COND) return r==arg? SD_OK : SD_ERROR; else
if(code==CMD_ALL_SEND_CID) {r|=*EMMC_RESP3; r|=*EMMC_RESP2; r|=*EMMC_RESP1; return r; } else
if(code==CMD_SEND_REL_ADDR) {
sd_err=(((r&0x1fff))|((r&0x2000)<<6)|((r&0x4000)<<8)|((r&0x8000)<<8))&CMD_ERRORS_MASK;
return r&CMD_RCA_MASK;
}
return r&CMD_ERRORS_MASK;
// make gcc happy
return 0;
}
/**
* read a block from sd card and return the number of bytes read
* returns 0 on error.
*/
int sd_readblock(unsigned int lba, unsigned char *buffer, unsigned int num)
{
int r,c=0,d;
if(num<1) num=1;
uart_puts("sd_readblock lba ");uart_hex(lba);uart_puts(" num ");uart_hex(num);uart_send('\n');
if(sd_status(SR_DAT_INHIBIT)) {sd_err=SD_TIMEOUT; return 0;}
unsigned int *buf=(unsigned int *)buffer;
if(sd_scr[0] & SCR_SUPP_CCS) {
if(num > 1 && (sd_scr[0] & SCR_SUPP_SET_BLKCNT)) {
sd_cmd(CMD_SET_BLOCKCNT,num);
if(sd_err) return 0;
}
*EMMC_BLKSIZECNT = (num << 16) | 512;
sd_cmd(num == 1 ? CMD_READ_SINGLE : CMD_READ_MULTI,lba);
if(sd_err) return 0;
} else {
*EMMC_BLKSIZECNT = (1 << 16) | 512;
}
while( c < num ) {
if(!(sd_scr[0] & SCR_SUPP_CCS)) {
sd_cmd(CMD_READ_SINGLE,(lba+c)*512);
if(sd_err) return 0;
}
if((r=sd_int(INT_READ_RDY))){uart_puts("\rERROR: Timeout waiting for ready to read\n");sd_err=r;return 0;}
for(d=0;d<128;d++) buf[d] = *EMMC_DATA;
c++; buf+=128;
}
if( num > 1 && !(sd_scr[0] & SCR_SUPP_SET_BLKCNT) && (sd_scr[0] & SCR_SUPP_CCS)) sd_cmd(CMD_STOP_TRANS,0);
return sd_err!=SD_OK || c!=num? 0 : num*512;
}
/**
* set SD clock to frequency in Hz
*/
int sd_clk(unsigned int f)
{
unsigned int d,c=41666666/f,x,s=32,h=0;
int cnt = 100000;
while((*EMMC_STATUS & (SR_CMD_INHIBIT|SR_DAT_INHIBIT)) && cnt--) wait_msec(1);
if(cnt<=0) {
uart_puts("ERROR: timeout waiting for inhibit flag\n");
return SD_ERROR;
}
*EMMC_CONTROL1 &= ~C1_CLK_EN; wait_msec(10);
x=c-1; if(!x) s=0; else {
if(!(x & 0xffff0000u)) { x <<= 16; s -= 16; }
if(!(x & 0xff000000u)) { x <<= 8; s -= 8; }
if(!(x & 0xf0000000u)) { x <<= 4; s -= 4; }
if(!(x & 0xc0000000u)) { x <<= 2; s -= 2; }
if(!(x & 0x80000000u)) { x <<= 1; s -= 1; }
if(s>0) s--;
if(s>7) s=7;
}
if(sd_hv>HOST_SPEC_V2) d=c; else d=(1<<s);
if(d<=2) {d=2;s=0;}
uart_puts("sd_clk divisor ");uart_hex(d);uart_puts(", shift ");uart_hex(s);uart_send('\n');
if(sd_hv>HOST_SPEC_V2) h=(d&0x300)>>2;
d=(((d&0x0ff)<<8)|h);
*EMMC_CONTROL1=(*EMMC_CONTROL1&0xffff003f)|d; wait_msec(10);
*EMMC_CONTROL1 |= C1_CLK_EN; wait_msec(10);
cnt=10000; while(!(*EMMC_CONTROL1 & C1_CLK_STABLE) && cnt--) wait_msec(10);
if(cnt<=0) {
uart_puts("ERROR: failed to get stable clock\n");
return SD_ERROR;
}
return SD_OK;
}
/**
* initialize EMMC to read SDHC card
*/
int sd_init()
{
long r,cnt,ccs=0;
// GPIO_CD
r=*GPFSEL4; r&=~(7<<(7*3)); *GPFSEL4=r;
*GPPUD=2; wait_cycles(150); *GPPUDCLK1=(1<<15); wait_cycles(150); *GPPUD=0; *GPPUDCLK1=0;
r=*GPHEN1; r|=1<<15; *GPHEN1=r;
// GPIO_CLK, GPIO_CMD
r=*GPFSEL4; r|=(7<<(8*3))|(7<<(9*3)); *GPFSEL4=r;
*GPPUD=2; wait_cycles(150); *GPPUDCLK1=(1<<16)|(1<<17); wait_cycles(150); *GPPUD=0; *GPPUDCLK1=0;
// GPIO_DAT0, GPIO_DAT1, GPIO_DAT2, GPIO_DAT3
r=*GPFSEL5; r|=(7<<(0*3)) | (7<<(1*3)) | (7<<(2*3)) | (7<<(3*3)); *GPFSEL5=r;
*GPPUD=2; wait_cycles(150);
*GPPUDCLK1=(1<<18) | (1<<19) | (1<<20) | (1<<21);
wait_cycles(150); *GPPUD=0; *GPPUDCLK1=0;
sd_hv = (*EMMC_SLOTISR_VER & HOST_SPEC_NUM) >> HOST_SPEC_NUM_SHIFT;
uart_puts("EMMC: GPIO set up\n");
// Reset the card.
*EMMC_CONTROL0 = 0; *EMMC_CONTROL1 |= C1_SRST_HC;
cnt=10000; do{wait_msec(10);} while( (*EMMC_CONTROL1 & C1_SRST_HC) && cnt-- );
if(cnt<=0) {
uart_puts("ERROR: failed to reset EMMC\n");
return SD_ERROR;
}
uart_puts("EMMC: reset OK\n");
*EMMC_CONTROL1 |= C1_CLK_INTLEN | C1_TOUNIT_MAX;
wait_msec(10);
// Set clock to setup frequency.
if((r=sd_clk(400000))) return r;
*EMMC_INT_EN = 0xffffffff;
*EMMC_INT_MASK = 0xffffffff;
sd_scr[0]=sd_scr[1]=sd_rca=sd_err=0;
sd_cmd(CMD_GO_IDLE,0);
if(sd_err) return sd_err;
sd_cmd(CMD_SEND_IF_COND,0x000001AA);
if(sd_err) return sd_err;
cnt=6; r=0; while(!(r&ACMD41_CMD_COMPLETE) && cnt--) {
wait_cycles(400);
r=sd_cmd(CMD_SEND_OP_COND,ACMD41_ARG_HC);
uart_puts("EMMC: CMD_SEND_OP_COND returned ");
if(r&ACMD41_CMD_COMPLETE)
uart_puts("COMPLETE ");
if(r&ACMD41_VOLTAGE)
uart_puts("VOLTAGE ");
if(r&ACMD41_CMD_CCS)
uart_puts("CCS ");
uart_hex(r>>32);
uart_hex(r);
uart_send('\n');
if(sd_err!=SD_TIMEOUT && sd_err!=SD_OK ) {
uart_puts("ERROR: EMMC ACMD41 returned error\n");
return sd_err;
}
}
if(!(r&ACMD41_CMD_COMPLETE) || !cnt ) return SD_TIMEOUT;
if(!(r&ACMD41_VOLTAGE)) return SD_ERROR;
if(r&ACMD41_CMD_CCS) ccs=SCR_SUPP_CCS;
sd_cmd(CMD_ALL_SEND_CID,0);
sd_rca = sd_cmd(CMD_SEND_REL_ADDR,0);
uart_puts("EMMC: CMD_SEND_REL_ADDR returned ");
uart_hex(sd_rca>>32);
uart_hex(sd_rca);
uart_send('\n');
if(sd_err) return sd_err;
if((r=sd_clk(25000000))) return r;
sd_cmd(CMD_CARD_SELECT,sd_rca);
if(sd_err) return sd_err;
if(sd_status(SR_DAT_INHIBIT)) return SD_TIMEOUT;
*EMMC_BLKSIZECNT = (1<<16) | 8;
sd_cmd(CMD_SEND_SCR,0);
if(sd_err) return sd_err;
if(sd_int(INT_READ_RDY)) return SD_TIMEOUT;
r=0; cnt=100000; while(r<2 && cnt) {
if( *EMMC_STATUS & SR_READ_AVAILABLE )
sd_scr[r++] = *EMMC_DATA;
else
wait_msec(1);
}
if(r!=2) return SD_TIMEOUT;
if(sd_scr[0] & SCR_SD_BUS_WIDTH_4) {
sd_cmd(CMD_SET_BUS_WIDTH,sd_rca|2);
if(sd_err) return sd_err;
*EMMC_CONTROL0 |= C0_HCTL_DWITDH;
}
// add software flag
uart_puts("EMMC: supports ");
if(sd_scr[0] & SCR_SUPP_SET_BLKCNT)
uart_puts("SET_BLKCNT ");
if(ccs)
uart_puts("CCS ");
uart_send('\n');
sd_scr[0]&=~SCR_SUPP_CCS;
sd_scr[0]|=ccs;
return SD_OK;
}

@ -1,31 +0,0 @@
/*
* Copyright (C) 2018 bzt (bztsrc@github)
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use, copy,
* modify, merge, publish, distribute, sublicense, and/or sell copies
* of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
*/
#define SD_OK 0
#define SD_TIMEOUT -1
#define SD_ERROR -2
int sd_init();
int sd_readblock(unsigned int lba, unsigned char *buffer, unsigned int num);

@ -1,55 +0,0 @@
/*
* Copyright (C) 2018 bzt (bztsrc@github)
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use, copy,
* modify, merge, publish, distribute, sublicense, and/or sell copies
* of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
*/
.section ".text.boot"
.global _start
_start:
// read cpu id, stop slave cores
mrs x1, mpidr_el1
and x1, x1, #3
cbz x1, 2f
// cpu id > 0, stop
1: wfe
b 1b
2: // cpu id == 0
// set stack before our code
ldr x1, =_start
mov sp, x1
// clear bss
ldr x1, =__bss_start
ldr w2, =__bss_size
3: cbz w2, 4f
str xzr, [x1], #8
sub w2, w2, #1
cbnz w2, 3b
// jump to C code, should not return
4: bl main
// for failsafe, halt this core too
b 1b

@ -1,153 +0,0 @@
/*
* Copyright (C) 2018 bzt (bztsrc@github)
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use, copy,
* modify, merge, publish, distribute, sublicense, and/or sell copies
* of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
*/
#include "gpio.h"
#include "mbox.h"
#include "delays.h"
/* PL011 UART registers */
#define UART0_DR ((volatile unsigned int*)(MMIO_BASE+0x00201000))
#define UART0_FR ((volatile unsigned int*)(MMIO_BASE+0x00201018))
#define UART0_IBRD ((volatile unsigned int*)(MMIO_BASE+0x00201024))
#define UART0_FBRD ((volatile unsigned int*)(MMIO_BASE+0x00201028))
#define UART0_LCRH ((volatile unsigned int*)(MMIO_BASE+0x0020102C))
#define UART0_CR ((volatile unsigned int*)(MMIO_BASE+0x00201030))
#define UART0_IMSC ((volatile unsigned int*)(MMIO_BASE+0x00201038))
#define UART0_ICR ((volatile unsigned int*)(MMIO_BASE+0x00201044))
/**
* Set baud rate and characteristics (115200 8N1) and map to GPIO
*/
void uart_init()
{
register unsigned int r;
/* initialize UART */
*UART0_CR = 0; // turn off UART0
/* set up clock for consistent divisor values */
mbox[0] = 8*4;
mbox[1] = MBOX_REQUEST;
mbox[2] = MBOX_TAG_SETCLKRATE; // set clock rate
mbox[3] = 12;
mbox[4] = 8;
mbox[5] = 2; // UART clock
mbox[6] = 4000000; // 4Mhz
mbox[7] = MBOX_TAG_LAST;
mbox_call(MBOX_CH_PROP);
/* map UART0 to GPIO pins */
r=*GPFSEL1;
r&=~((7<<12)|(7<<15)); // gpio14, gpio15
r|=(4<<12)|(4<<15); // alt0
*GPFSEL1 = r;
*GPPUD = 0; // enable pins 14 and 15
wait_cycles(150);
*GPPUDCLK0 = (1<<14)|(1<<15);
wait_cycles(150);
*GPPUDCLK0 = 0; // flush GPIO setup
*UART0_ICR = 0x7FF; // clear interrupts
*UART0_IBRD = 2; // 115200 baud
*UART0_FBRD = 0xB;
*UART0_LCRH = 0b11<<5; // 8n1
*UART0_CR = 0x301; // enable Tx, Rx, FIFO
}
/**
* Send a character
*/
void uart_send(unsigned int c) {
/* wait until we can send */
do{asm volatile("nop");}while(*UART0_FR&0x20);
/* write the character to the buffer */
*UART0_DR=c;
}
/**
* Receive a character
*/
char uart_getc() {
char r;
/* wait until something is in the buffer */
do{asm volatile("nop");}while(*UART0_FR&0x10);
/* read it and return */
r=(char)(*UART0_DR);
/* convert carrige return to newline */
return r=='\r'?'\n':r;
}
/**
* Display a string
*/
void uart_puts(char *s) {
while(*s) {
/* convert newline to carrige return + newline */
if(*s=='\n')
uart_send('\r');
uart_send(*s++);
}
}
/**
* Display a binary value in hexadecimal
*/
void uart_hex(unsigned int d) {
unsigned int n;
int c;
for(c=28;c>=0;c-=4) {
// get highest tetrad
n=(d>>c)&0xF;
// 0-9 => '0'-'9', 10-15 => 'A'-'F'
n+=n>9?0x37:0x30;
uart_send(n);
}
}
/**
* Dump memory
*/
void uart_dump(void *ptr)
{
unsigned long a,b,d;
unsigned char c;
for(a=(unsigned long)ptr;a<(unsigned long)ptr+512;a+=16) {
uart_hex(a); uart_puts(": ");
for(b=0;b<16;b++) {
c=*((unsigned char*)(a+b));
d=(unsigned int)c;d>>=4;d&=0xF;d+=d>9?0x37:0x30;uart_send(d);
d=(unsigned int)c;d&=0xF;d+=d>9?0x37:0x30;uart_send(d);
uart_send(' ');
if(b%4==3)
uart_send(' ');
}
for(b=0;b<16;b++) {
c=*((unsigned char*)(a+b));
uart_send(c<32||c>=127?'.':c);
}
uart_send('\r');
uart_send('\n');
}
}

@ -1,31 +0,0 @@
/*
* Copyright (C) 2018 bzt (bztsrc@github)
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use, copy,
* modify, merge, publish, distribute, sublicense, and/or sell copies
* of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
*/
void uart_init();
void uart_send(unsigned int c);
char uart_getc();
void uart_puts(char *s);
void uart_hex(unsigned int d);
void uart_dump(void *ptr);

@ -1,52 +0,0 @@
#
# Copyright (C) 2018 bzt (bztsrc@github)
#
# Permission is hereby granted, free of charge, to any person
# obtaining a copy of this software and associated documentation
# files (the "Software"), to deal in the Software without
# restriction, including without limitation the rights to use, copy,
# modify, merge, publish, distribute, sublicense, and/or sell copies
# of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be
# included in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
# HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
# DEALINGS IN THE SOFTWARE.
#
#
SRCS = $(wildcard *.c)
OBJS = $(SRCS:.c=.o)
CFLAGS = -Wall -O2 -ffreestanding -nostdinc -nostdlib -nostartfiles
all: clean kernel8.img
start.o: start.S
aarch64-elf-gcc $(CFLAGS) -c start.S -o start.o
%.o: %.c
aarch64-elf-gcc $(CFLAGS) -c $< -o $@
tar:
tar -cf ramdisk *.md *.c *.h
cpio:
ls *.md *.c *.h | cpio -H hpodc -o >ramdisk
rd.o: ramdisk
aarch64-elf-ld -r -b binary -o rd.o ramdisk
kernel8.img: start.o rd.o $(OBJS)
aarch64-elf-ld -nostdlib -nostartfiles start.o rd.o $(OBJS) -T link.ld -o kernel8.elf
aarch64-elf-objcopy -O binary kernel8.elf kernel8.img
clean:
rm kernel8.elf *.o >/dev/null 2>/dev/null || true

@ -1,60 +0,0 @@
Oktatóanyag 0E - Kezdeti memória lemez
======================================
Sok OS használ kezdeti memória lemezt (initrd) hogy fájlokat töltsön be induláskor. Szükségét éreztem egy
ilyen oktatóanyagnak, mivel a legtöbb hobby OS fejlesztőnek fingja sincs, hogy kell ezt rendesen csinálni.
Először is, nem fogjuk újra feltalálni a spanyol viaszt és kiagyalni egy új formátumot, amihez aztán egy
szörnyű kreátor programot heggesztünk. Helyette a POSIX szabvány `tar` archíválót és a `cpio` parancsot
fogjuk használni. Előbbi egyértelműbb, utúbbit a Linux is használja.
A tar formátuma pofonegyszerű, először jön egy 512 bájtos fejléc a fájl adataival, majd ezt követi a fájl
tartalma nullákkal kiegészítve, hogy a hossza 512-vel osztható legyen. Ez ismétlődik minden egyes fájlra az archívban.
A cpio nagyon hasonló, csak változó hosszúságú fejléccel operál, és nincs a fájl tartalma kiegészítve.
Ha szeretnél tömörített initrd-t, akkor javaslom például a [tinf](https://bitbucket.org/jibsen/tinf) könyvtárat
a kicsomagoláshoz. A kitömörített adatot az itt ismertetett módszerrel olvashatod.
Másodszor, a betöltéshez több lehetőségünk is van:
### Betöltjük a fájlt saját magunk
Ehhez használhatod a `fat_readfile()` funkciót az előző oktatóanyagból. Ebben az esetben az initrd címét visszaadja
a függvény.
### Megkéred a GPU-t hogy töltse be neked
Aztán használhatod a `config.txt`-t hogy utasítsd a start.elf-et az initrd betöltésére. Ez azért jó, mert ehhez
nem kell SD kártya olvasó és FAT értelmező, így a kerneled jóval kissebb lesz. Ami a
[config.txt](https://www.raspberrypi.org/documentation/configuration/config-txt/boot.md) parancsait illeti,
két lehetőséged is van:
`ramfsfile=(fájlnév)` - ez betölti a (fájlnév) nevű fájlt mindjárt a kerneled után. Az initrd-d kezdőcíme
ekkor a *&_end* cimke lesz, amit a linker szkriptben definiáltunk.
`initramfs (fájlnév) (cím)` - a megadott címre tölti be a (fájlnév) nevű fájlt. A kezdőcíme ekkor *(cím)* lesz.
### Statikus linkelés
Nem túl praktikus, mivel mindig újra kell fordítani a kernelt, ha változtatni akarsz az initrd tartalmán. Azonban
ez a legegyszerűbb módszer, és hogy átlátható legyen az oktatóanyag, ezért ezt választottam. Az initrd-d
kezdőcímét ez esetben a *_binary_ramdisk_start* cimke szolgáltatja.
Makefile
--------
Hozzáadtam egy rd.o-t létrehozó szabályt, ami object fájllá konvertálja az archívot. Ezen kívül lett két
új szabály:
`make tar` ami *tar* formátumban hozza létre az archívumot
`make cpio` ami pedig *cpio hpodc* formátumot használ.
Ezért amikor fordítani szeretnél, vagy a `make tar all`, vagy a `make cpio all` parancsot kell használnod.
Initrd.h, initrd.c
------------------
`initrd_list(buf)` kilistázza a bufferben lévő archív tartalmát. A formátumát automatikusan detektálja.
Main
----
Inicializáljuk a konzolt, majd átadjuk az initrd kezdőcímét a listázónak.

@ -1,59 +0,0 @@
Tutorial 0E - Initial RamDisk
=============================
Many OS uses initial ramdisk to load files into memory during boot. I felt the need for such
a tutorial as most hobby OS developer's never learned how to do this properly.
First of all, we're not going to reinvent the wheel and come up with a new format and an awful
image creator tool. We're going to use the POSIX standard `tar` utility and the `cpio` utility
to create our initrd. The former is more straightforward, the latter is used by Linux.
Tar's format is really simple, first comes an 512 bytes long header with file meta information, followed by the
file contents padded with zeros to round up to be multiple of 512 bytes. This repeats for every file in the archive.
Cpio is very similar but it has a variable length header and file content is not padded.
If you want a compressed initrd, you can use for example the [tinf](https://bitbucket.org/jibsen/tinf) library to
inflate. The uncompressed buffer can be parsed by the method described here.
Second, about loading your ramdisk into memory, we have several options:
### Load a file on our own
You can use the `fat_readfile()` from the previous tutorial. In that case your initrd's address
will be returned by the function.
### Ask the GPU to do so
You can use `config.txt` to tell start.elf to load the initrd for you. With this you won't need
any SD card reader or FAT parser at all, resulting in a much smaller kernel. As for the
[config.txt](https://www.raspberrypi.org/documentation/configuration/config-txt/boot.md),
you have two options:
`ramfsfile=(filename)` - this will load (filename) after your kernel. You can access it at the label
*&_end* defined by our linker script.
`initramfs (filename) (address)` - load (filename) into a specified location. You can access it at *(address)*.
### Statically link
This is not very practical because you have to build your kernel every time you want to change the initrd. But
it is the simplest method, and to keep this tutorial simple we'll use this method. You can access the initrd by
the label *_binary_ramdisk_start*.
Makefile
--------
I've added an rd.o rule to convert the archive into an object file. I've also added
`make tar` which will create an archive in *tar* format
`make cpio` which will create a *cpio hpodc* archive.
So when you compile, you either have to use `make tar all` or `make cpio all`.
Initrd.h, initrd.c
------------------
`initrd_list(buf)` list the contents of an archive in the buffer. Detects the format automatically.
Main
----
We initialize console and then pass the initrd buffer to lister.

@ -1,81 +0,0 @@
/*
* Copyright (C) 2018 bzt (bztsrc@github)
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use, copy,
* modify, merge, publish, distribute, sublicense, and/or sell copies
* of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
*/
#include "gpio.h"
#define SYSTMR_LO ((volatile unsigned int*)(MMIO_BASE+0x00003004))
#define SYSTMR_HI ((volatile unsigned int*)(MMIO_BASE+0x00003008))
/**
* Wait N CPU cycles (ARM CPU only)
*/
void wait_cycles(unsigned int n)
{
if(n) while(n--) { asm volatile("nop"); }
}
/**
* Wait N microsec (ARM CPU only)
*/
void wait_msec(unsigned int n)
{
register unsigned long f, t, r;
// get the current counter frequency
asm volatile ("mrs %0, cntfrq_el0" : "=r"(f));
// read the current counter
asm volatile ("mrs %0, cntpct_el0" : "=r"(t));
// calculate expire value for counter
t+=((f/1000)*n)/1000;
do{asm volatile ("mrs %0, cntpct_el0" : "=r"(r));}while(r<t);
}
/**
* Get System Timer's counter
*/
unsigned long get_system_timer()
{
unsigned int h=-1, l;
// we must read MMIO area as two separate 32 bit reads
h=*SYSTMR_HI;
l=*SYSTMR_LO;
// we have to repeat it if high word changed during read
if(h!=*SYSTMR_HI) {
h=*SYSTMR_HI;
l=*SYSTMR_LO;
}
// compose long int value
return ((unsigned long) h << 32) | l;
}
/**
* Wait N microsec (with BCM System Timer)
*/
void wait_msec_st(unsigned int n)
{
unsigned long t=get_system_timer();
// we must check if it's non-zero, because qemu does not emulate
// system timer, and returning constant zero would mean infinite loop
if(t) while(get_system_timer() < t+n);
}

@ -1,29 +0,0 @@
/*
* Copyright (C) 2018 bzt (bztsrc@github)
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use, copy,
* modify, merge, publish, distribute, sublicense, and/or sell copies
* of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
*/
void wait_cycles(unsigned int n);
void wait_msec(unsigned int n);
unsigned long get_system_timer();
void wait_msec_st(unsigned int n);

@ -1,45 +0,0 @@
/*
* Copyright (C) 2018 bzt (bztsrc@github)
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use, copy,
* modify, merge, publish, distribute, sublicense, and/or sell copies
* of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
*/
#define MMIO_BASE 0x3F000000
#define GPFSEL0 ((volatile unsigned int*)(MMIO_BASE+0x00200000))
#define GPFSEL1 ((volatile unsigned int*)(MMIO_BASE+0x00200004))
#define GPFSEL2 ((volatile unsigned int*)(MMIO_BASE+0x00200008))
#define GPFSEL3 ((volatile unsigned int*)(MMIO_BASE+0x0020000C))
#define GPFSEL4 ((volatile unsigned int*)(MMIO_BASE+0x00200010))
#define GPFSEL5 ((volatile unsigned int*)(MMIO_BASE+0x00200014))
#define GPSET0 ((volatile unsigned int*)(MMIO_BASE+0x0020001C))
#define GPSET1 ((volatile unsigned int*)(MMIO_BASE+0x00200020))
#define GPCLR0 ((volatile unsigned int*)(MMIO_BASE+0x00200028))
#define GPLEV0 ((volatile unsigned int*)(MMIO_BASE+0x00200034))
#define GPLEV1 ((volatile unsigned int*)(MMIO_BASE+0x00200038))
#define GPEDS0 ((volatile unsigned int*)(MMIO_BASE+0x00200040))
#define GPEDS1 ((volatile unsigned int*)(MMIO_BASE+0x00200044))
#define GPHEN0 ((volatile unsigned int*)(MMIO_BASE+0x00200064))
#define GPHEN1 ((volatile unsigned int*)(MMIO_BASE+0x00200068))
#define GPPUD ((volatile unsigned int*)(MMIO_BASE+0x00200094))
#define GPPUDCLK0 ((volatile unsigned int*)(MMIO_BASE+0x00200098))
#define GPPUDCLK1 ((volatile unsigned int*)(MMIO_BASE+0x0020009C))

@ -1,136 +0,0 @@
/*
* Copyright (C) 2018 bzt (bztsrc@github)
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use, copy,
* modify, merge, publish, distribute, sublicense, and/or sell copies
* of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
*/
#include "uart.h"
/* POSIX ustar header format */
typedef struct { /* byte offset */
char name[100]; /* 0 */
char mode[8]; /* 100 */
char uid[8]; /* 108 */
char gid[8]; /* 116 */
char size[12]; /* 124 */
char mtime[12]; /* 136 */
char chksum[8]; /* 148 */
char typeflag; /* 156 */
char linkname[100]; /* 157 */
char magic[6]; /* 257 */
char version[2]; /* 263 */
char uname[32]; /* 265 */
char gname[32]; /* 297 */
char devmajor[8]; /* 329 */
char devminor[8]; /* 337 */
char prefix[167]; /* 345 */
} __attribute__((packed)) tar_t;
/* cpio hpodc format */
typedef struct {
char magic[6]; /* Magic header '070707'. */
char dev[6]; /* device number. */
char ino[6]; /* "i-node" number. */
char mode[6]; /* Permisions. */
char uid[6]; /* User ID. */
char gid[6]; /* Group ID. */
char nlink[6]; /* Number of hard links. */
char rdev[6]; /* device major/minor number. */
char mtime[11]; /* Modification time. */
char namesize[6]; /* Length of filename in bytes. */
char filesize[11]; /* File size. */
} __attribute__((packed)) cpio_t;
/**
* Helper function to convert ASCII octal number into binary
* s string
* n number of digits
*/
int oct2bin(char *s, int n)
{
int r=0;
while(n-->0) {
r<<=3;
r+=*s++-'0';
}
return r;
}
/**
* List the contents of an archive
*/
void initrd_list(char *buf)
{
char *types[]={"regular", "link ", "symlnk", "chrdev", "blkdev", "dircty", "fifo ", "??? "};
uart_puts("Type Offset Size Access rights\tFilename\n");
// iterate on archive's contents
while(!__builtin_memcmp(buf+257,"ustar",5)) {
// if it's an ustar archive
tar_t *header=(tar_t*)buf;
int fs=oct2bin(header->size,11);
// print out meta information
uart_puts(types[header->typeflag-'0']);
uart_send(' ');
uart_send(' ');
uart_hex((unsigned int)((unsigned long)buf)+sizeof(tar_t));
uart_send(' ');
uart_hex(fs); // file size in hex
uart_send(' ');
uart_puts(header->mode); // access bits in octal
uart_send(' ');
uart_puts(header->uname); // owner
uart_send('.');
uart_puts(header->gname); // group
uart_send('\t');
uart_puts(buf); // filename
if(header->typeflag=='2') {
uart_puts(" -> "); // symlink target
uart_puts(header->linkname);
}
uart_puts("\n");
// jump to the next file
buf+=(((fs+511)/512)+1)*512;
}
// if it's a cpio archive. Cpio also has a trailer entry
while(!__builtin_memcmp(buf,"070707",6) && __builtin_memcmp(buf+sizeof(cpio_t),"TRAILER!!",9)) {
cpio_t *header = (cpio_t*)buf;
int ns=oct2bin(header->namesize,6);
int fs=oct2bin(header->filesize,11);
// print out meta information
uart_hex(oct2bin(header->mode,6)); // mode (access rights + type)
uart_send(' ');
uart_hex((unsigned int)((unsigned long)buf)+sizeof(cpio_t)+ns);
uart_send(' ');
uart_hex(fs); // file size in hex
uart_send(' ');
uart_hex(oct2bin(header->uid,6)); // user id in hex
uart_send('.');
uart_hex(oct2bin(header->gid,6)); // group id in hex
uart_send('\t');
uart_puts(buf+sizeof(cpio_t)); // filename
uart_puts("\n");
// jump to the next file
buf+=(sizeof(cpio_t)+ns+fs);
}
}

@ -1,26 +0,0 @@
/*
* Copyright (C) 2018 bzt (bztsrc@github)
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use, copy,
* modify, merge, publish, distribute, sublicense, and/or sell copies
* of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
*/
void initrd_list(char *buf);

Binary file not shown.

@ -1,44 +0,0 @@
/*
* Copyright (C) 2018 bzt (bztsrc@github)
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use, copy,
* modify, merge, publish, distribute, sublicense, and/or sell copies
* of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
*/
SECTIONS
{
. = 0x80000;
.text : { KEEP(*(.text.boot)) *(.text .text.* .gnu.linkonce.t*) }
.rodata : { *(.rodata .rodata.* .gnu.linkonce.r*) }
PROVIDE(_data = .);
.data : { *(.data .data.* .gnu.linkonce.d*) }
.bss (NOLOAD) : {
. = ALIGN(16);
__bss_start = .;
*(.bss .bss.*)
*(COMMON)
__bss_end = .;
}
_end = .;
/DISCARD/ : { *(.comment) *(.gnu*) *(.note*) *(.eh_frame*) }
}
__bss_size = (__bss_end - __bss_start)>>3;

@ -1,44 +0,0 @@
/*
* Copyright (C) 2018 bzt (bztsrc@github)
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use, copy,
* modify, merge, publish, distribute, sublicense, and/or sell copies
* of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
*/
#include "uart.h"
#include "initrd.h"
// import our bitchunk from rd.o
extern volatile unsigned char _binary_ramdisk_start;
void main()
{
// set up serial console
uart_init();
// list contents of an archive
initrd_list((char*)&_binary_ramdisk_start);
// echo everything back
while(1) {
uart_send(uart_getc());
}
}

@ -1,63 +0,0 @@
/*
* Copyright (C) 2018 bzt (bztsrc@github)
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use, copy,
* modify, merge, publish, distribute, sublicense, and/or sell copies
* of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
*/
#include "gpio.h"
/* mailbox message buffer */
volatile unsigned int __attribute__((aligned(16))) mbox[36];
#define VIDEOCORE_MBOX (MMIO_BASE+0x0000B880)
#define MBOX_READ ((volatile unsigned int*)(VIDEOCORE_MBOX+0x0))
#define MBOX_POLL ((volatile unsigned int*)(VIDEOCORE_MBOX+0x10))
#define MBOX_SENDER ((volatile unsigned int*)(VIDEOCORE_MBOX+0x14))
#define MBOX_STATUS ((volatile unsigned int*)(VIDEOCORE_MBOX+0x18))
#define MBOX_CONFIG ((volatile unsigned int*)(VIDEOCORE_MBOX+0x1C))
#define MBOX_WRITE ((volatile unsigned int*)(VIDEOCORE_MBOX+0x20))
#define MBOX_RESPONSE 0x80000000
#define MBOX_FULL 0x80000000
#define MBOX_EMPTY 0x40000000
/**
* Make a mailbox call. Returns 0 on failure, non-zero on success
*/
int mbox_call(unsigned char ch)
{
unsigned int r;
/* wait until we can write to the mailbox */
do{asm volatile("nop");}while(*MBOX_STATUS & MBOX_FULL);
/* write the address of our message to the mailbox with channel identifier */
*MBOX_WRITE = (((unsigned int)((unsigned long)&mbox)&~0xF) | (ch&0xF));
/* now wait for the response */
while(1) {
/* is there a response? */
do{asm volatile("nop");}while(*MBOX_STATUS & MBOX_EMPTY);
r=*MBOX_READ;
/* is it a response to our message? */
if((unsigned char)(r&0xF)==ch && (r&~0xF)==(unsigned int)((unsigned long)&mbox))
/* is it a valid successful response? */
return mbox[1]==MBOX_RESPONSE;
}
return 0;
}

@ -1,47 +0,0 @@
/*
* Copyright (C) 2018 bzt (bztsrc@github)
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use, copy,
* modify, merge, publish, distribute, sublicense, and/or sell copies
* of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
*/
/* a properly aligned buffer */
extern volatile unsigned int mbox[36];
#define MBOX_REQUEST 0
/* channels */
#define MBOX_CH_POWER 0
#define MBOX_CH_FB 1
#define MBOX_CH_VUART 2
#define MBOX_CH_VCHIQ 3
#define MBOX_CH_LEDS 4
#define MBOX_CH_BTNS 5
#define MBOX_CH_TOUCH 6
#define MBOX_CH_COUNT 7
#define MBOX_CH_PROP 8
/* tags */
#define MBOX_TAG_SETPOWER 0x28001
#define MBOX_TAG_SETCLKRATE 0x38002
#define MBOX_TAG_LAST 0
int mbox_call(unsigned char ch);

@ -1,55 +0,0 @@
/*
* Copyright (C) 2018 bzt (bztsrc@github)
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use, copy,
* modify, merge, publish, distribute, sublicense, and/or sell copies
* of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
*/
.section ".text.boot"
.global _start
_start:
// read cpu id, stop slave cores
mrs x1, mpidr_el1
and x1, x1, #3
cbz x1, 2f
// cpu id > 0, stop
1: wfe
b 1b
2: // cpu id == 0
// set stack before our code
ldr x1, =_start
mov sp, x1
// clear bss
ldr x1, =__bss_start
ldr w2, =__bss_size
3: cbz w2, 4f
str xzr, [x1], #8
sub w2, w2, #1
cbnz w2, 3b
// jump to C code, should not return
4: bl main
// for failsafe, halt this core too
b 1b

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

Loading…
Cancel
Save