diff --git a/14_raspbootin64/Makefile b/14_raspbootin64/Makefile new file mode 100644 index 00000000..f6ba7559 --- /dev/null +++ b/14_raspbootin64/Makefile @@ -0,0 +1,43 @@ +# +# 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 diff --git a/14_raspbootin64/OLVASSEL.md b/14_raspbootin64/OLVASSEL.md new file mode 100644 index 00000000..3a31fb94 --- /dev/null +++ b/14_raspbootin64/OLVASSEL.md @@ -0,0 +1,40 @@ +Oktatóanyag 15 - Raspbootin64 +============================= + +Mivel folyton iragatni az SD kártyát strapás, és nem tesz jót a kártyának, ezért egy olyan kernel8.img-t készítünk, +ami a soros vonalról fogja betölteni az igazi kernel8.img-t. + +Ez az oktatóanyag a jól ismert [raspbootin](https://github.com/mrvn/raspbootin) átírása 64 bitre. +A betöltőprogram egyik felét adja csak, a kernel fogadót, ami az RPi-n fut. A másik fél, a PC-n futó küldő, +megtalálható az eredeti forrásban [raspbootcom](https://github.com/mrvn/raspbootin/raspbootcom) néven. +Ha Windowsos gépekről is szeretnél kernelt küldeni, akkor javaslom inkább a John Cronin féle átiratot, a +[raspbootin-server](https://github.com/jncronin/rpi-boot/blob/master/raspbootin-server.c)-t, ami natív Win32 API-t használ. + +Hogy az új kernelt ugyanoda tölthessük be, el kell mozdítanunk a kódunkat az útból. Ezt chain loading-nak hívják, amikor +az első kód ugyanarra a címre tölti be a második kódot, ezért az utóbbi azt hiszi, a firmware töltötte be. +Hogy ezt megvalósítsuk, egy alacsonyabb címre linkeljük a kódot, és mivel a GPU ettől függetlenül a 0x80000-ra tölt be, +nekünk kell a módosított címre másolnunk magunkat. Fontos, hogy ezalatt csak relatív címzést használhatunk. Amikor +végeztünk, a 0x80000-as címen lévő memóriának használaton kívülinek kell lennie. Ajánlott a kódunkat minimalizálni, mivel +úgyis figyelmen kívül hagyja az újonnan betöltendő kód. Ezért kivettem az `uart_puts()` eljárást, így a teljes méret +1024 bájt alá csökkent. Ezt a következő paranccsal ellenőriztem: + +```sh +$ aarch64-elf-readelf -s kernel8.elf | grep __bss_end + 21: 000000000007ffd0 0 NOTYPE GLOBAL DEFAULT 4 __bss_end +``` + +Start +----- + +Hozzáadtam egy ciklust, ami átmásolja a kódunkat arra a címre, ahová vártuk, hogy betöltődjön. + +Linker +------ + +Másik címre linkelünk ebben a példában. Hasonlóan a bss méret kiszámításához, ugyanúgy meghatározzuk a kód +méretét is, amit másolnunk kell. + +Main +---- + +Kiírjuk, hogy 'RBIN64', majd beolvassuk az új kernelt a soros vonalról, és átadjuk rá a vezérlést. diff --git a/14_raspbootin64/README.md b/14_raspbootin64/README.md new file mode 100644 index 00000000..f7cc86d7 --- /dev/null +++ b/14_raspbootin64/README.md @@ -0,0 +1,40 @@ +Tutorial 15 - Raspbootin64 +========================== + +Because changing SD card is boring and also to avoid potential SD card damage, we create a kernel8.img that will +load the real kernel8.img over serial. + +This tutorial is a rewrite of the well known serial boot loader, [raspbootin](https://github.com/mrvn/raspbootin) in 64 bit. +I only provide one part of the loader, the kernel receiver, which runs on the RPi. For the other +part, the sender, which runs on your PC see the original [raspbootcom](https://github.com/mrvn/raspbootin/raspbootcom) utility. +If you want to send kernels from a Windows machine, I suggest to take a look at John Cronin's rewrite, +[raspbootin-server](https://github.com/jncronin/rpi-boot/blob/master/raspbootin-server.c) which can be compiled for the Win32 API. + +In order to load the new kernel to the same address, we have to move ourself out of the way. It's called chain +loading: one code loads the next code to the same position in memory, therefore the latter thinks it was loaded +by the firmware. To implement that we use a different linking address this time, and since GPU loads us to 0x80000 +regardless, we have to copy our code to that link address. That's important that we can only use relative addresses +while doing so. When we're done, the memory at 0x80000 must be free to use. We also should minimize the size of the +loader, since it will be regarded by the newlt loaded code anyway. By removing `uart_puts()` I've managed to shrink the +size below 1024 bytes. I've checked that with: + +```sh +$ aarch64-elf-readelf -s kernel8.elf | grep __bss_end + 21: 000000000007ffd0 0 NOTYPE GLOBAL DEFAULT 4 __bss_end +``` + +Start +----- + +Added a loop to relocate our code to the address it should have been loaded to. + +Linker +------ + +We use a different linking address this time. Similarly to bss size calculation, we calculate our code's size to +know how many bytes we have to copy. + +Main +---- + +We print 'RBIN64', receive the new kernel over serial, and jump to it. diff --git a/14_raspbootin64/gpio.h b/14_raspbootin64/gpio.h new file mode 100644 index 00000000..52fa671d --- /dev/null +++ b/14_raspbootin64/gpio.h @@ -0,0 +1,45 @@ +/* + * 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)) diff --git a/14_raspbootin64/kernel8.img b/14_raspbootin64/kernel8.img new file mode 100755 index 00000000..0c1a13b1 Binary files /dev/null and b/14_raspbootin64/kernel8.img differ diff --git a/14_raspbootin64/link.ld b/14_raspbootin64/link.ld new file mode 100644 index 00000000..1259029c --- /dev/null +++ b/14_raspbootin64/link.ld @@ -0,0 +1,46 @@ +/* + * 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 - 1024; + PROVIDE(_code = .); + .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; +__loader_size = (_end - _code)>>3; diff --git a/14_raspbootin64/main.c b/14_raspbootin64/main.c new file mode 100644 index 00000000..ec4acb38 --- /dev/null +++ b/14_raspbootin64/main.c @@ -0,0 +1,75 @@ +/* + * 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" + +// import our start address from linker +extern char _start; + +void main() +{ + int size=0; + char *kernel=(char*)&_start; + + // set up serial console + uart_init(); + + // say hello. To reduce loader size I removed uart_puts() +again: + uart_send('R'); + uart_send('B'); + uart_send('I'); + uart_send('N'); + uart_send('6'); + uart_send('4'); + uart_send('\r'); + uart_send('\n'); + // notify raspbootcom to send the kernel + uart_send(3); + uart_send(3); + uart_send(3); + + // read the kernel's size + size=uart_getc(); + size|=uart_getc()<<8; + size|=uart_getc()<<16; + size|=uart_getc()<<24; + + // send negative or positive acknowledge + if(size<64 || size>1024*1024) { + // size error + uart_send('S'); + uart_send('E'); + goto again; + } + uart_send('O'); + uart_send('K'); + + // read the kernel + while(size--) *kernel++ = uart_getc(); + + // jump to the new kernel + asm volatile ("b 0x80000"); +} diff --git a/14_raspbootin64/mbox.c b/14_raspbootin64/mbox.c new file mode 100644 index 00000000..a7220834 --- /dev/null +++ b/14_raspbootin64/mbox.c @@ -0,0 +1,63 @@ +/* + * 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[8]; + +#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; +} diff --git a/14_raspbootin64/mbox.h b/14_raspbootin64/mbox.h new file mode 100644 index 00000000..09844dea --- /dev/null +++ b/14_raspbootin64/mbox.h @@ -0,0 +1,47 @@ +/* + * 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_GETSERIAL 0x10004 +#define MBOX_TAG_SETCLKRATE 0x38002 +#define MBOX_TAG_LAST 0 + +int mbox_call(unsigned char ch); diff --git a/14_raspbootin64/start.S b/14_raspbootin64/start.S new file mode 100644 index 00000000..b795341c --- /dev/null +++ b/14_raspbootin64/start.S @@ -0,0 +1,64 @@ +/* + * 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 + + // relocate our code from load address to link address + ldr x1, =0x80000 + ldr x2, =_start + ldr w3, =__loader_size +1: ldr x4, [x1], #8 + str x4, [x2], #8 + sub w3, w3, #1 + cbnz w3, 1b + + // 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 diff --git a/14_raspbootin64/uart.c b/14_raspbootin64/uart.c new file mode 100644 index 00000000..5bd2b123 --- /dev/null +++ b/14_raspbootin64/uart.c @@ -0,0 +1,99 @@ +/* + * 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" + +/* 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 + r=150; while(r--) { asm volatile("nop"); } + *GPPUDCLK0 = (1<<14)|(1<<15); + r=150; while(r--) { asm volatile("nop"); } + *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; +} diff --git a/14_raspbootin64/uart.h b/14_raspbootin64/uart.h new file mode 100644 index 00000000..99b2be48 --- /dev/null +++ b/14_raspbootin64/uart.h @@ -0,0 +1,30 @@ +/* + * 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);