deb59d299ff69eb9c0068c794f75c8fd70fd4e14
[rpi-open-firmware.git] / arm_chainloader / loader.cc
1 /*=============================================================================
2 Copyright (C) 2016 Kristina Brooks
3 All rights reserved.
4
5 This program is free software; you can redistribute it and/or
6 modify it under the terms of the GNU General Public License
7 as published by the Free Software Foundation; either version 2
8 of the License, or (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 FILE DESCRIPTION
16 Second stage bootloader.
17
18 =============================================================================*/
19
20 #include <drivers/fatfs/ff.h>
21 #include <chainloader.h>
22 #include <drivers/mailbox.hpp>
23 #include <libfdt.h>
24 #include <memory_map.h>
25
26 #define logf(fmt, ...) printf("[LDR:%s]: " fmt, __FUNCTION__, ##__VA_ARGS__);
27
28 FATFS g_BootVolumeFs;
29
30 #define ROOT_VOLUME_PREFIX "0:"
31 #define DTB_LOAD_ADDRESS 0x20000000
32 #define KERNEL_LOAD_ADDRESS 0x2000000
33
34 extern "C" {
35 void boot_linux(int zero, int machineID, void* dtb, void* kernel);
36 }
37
38 static_assert((MEM_USABLE_START+0x800000) < KERNEL_LOAD_ADDRESS,
39 "memory layout would not allow for kernel to be loaded at KERNEL_LOAD_ADDRESS, please check memory_map.h");
40
41 struct LoaderImpl {
42 inline bool file_exists(const char* path) {
43 return f_stat(path, NULL) == FR_OK;
44 }
45
46 bool read_file(const char* path, uint8_t*& dest, size_t& size, bool should_alloc = true) {
47 /* ensure file exists first */
48 if(!file_exists(path))
49 return false;
50
51 /* read entire file into buffer */
52 FIL fp;
53 f_open(&fp, path, FA_READ);
54
55 unsigned int len = f_size(&fp);
56
57 if(should_alloc) {
58 uint8_t* buffer = new uint8_t[len];
59 dest = buffer;
60 }
61
62 logf("%s: reading %d bytes to 0x%X (allocated=%d) ...\n", path, len, (unsigned int)dest, should_alloc);
63
64 size = len;
65
66 f_read(&fp, dest, len, &len);
67 f_close(&fp);
68
69 return true;
70 }
71
72 inline bool read_file(const char* path, uint8_t*& dest, bool should_alloc = true) {
73 size_t size;
74 return read_file(path, dest, size, should_alloc);
75 }
76
77 uint8_t* load_fdt(const char* filename, uint8_t* cmdline) {
78 /* read device tree blob */
79 uint8_t* fdt = reinterpret_cast<uint8_t*>(DTB_LOAD_ADDRESS);
80 size_t sz;
81
82 if(!read_file(filename, fdt, sz, false)) {
83 panic("error reading fdt");
84 }
85
86 void* v_fdt = reinterpret_cast<void*>(fdt);
87
88 int res;
89
90 if ((res = fdt_check_header(v_fdt)) != 0) {
91 panic("fdt blob invalid, fdt_check_header returned %d", res);
92 }
93
94 /* pass in command line args */
95 res = fdt_open_into(v_fdt, v_fdt, sz + 4096);
96 logf("fdt_open_into(): %d\n", res);
97
98 int node = fdt_path_offset(v_fdt, "/chosen");
99 logf("/chosen node: %d\n", node);
100 if (node < 0)
101 return NULL;
102 res = fdt_setprop(v_fdt, node, "bootargs", cmdline, strlen((char*) cmdline) + 1);
103 logf("fdt_setprop(): %d\n", res);
104
105 /* pass in a memory map, skipping first meg for bootcode */
106 int memory = fdt_path_offset(v_fdt, "/memory");
107 if(memory < 0)
108 return NULL;
109
110 /* start the memory map at 1M/16 and grow continuous for 256M
111 * TODO: does this disrupt I/O? */
112
113 char dtype[] = "memory";
114 //uint32_t memmap[] = { 0x10000, 0x20000000 };
115 //uint8_t memmap[] = { 0x00, 0x00, 0x01, 0x00,
116 // 0x00, 0x00, 0x00, 0x20 };
117 uint8_t memmap[] = { 0x00, 0x00, 0x10, 0x00,
118 0x10, 0x00, 0x00, 0x00 };
119
120 res = fdt_setprop(v_fdt, memory, "reg", (void*) memmap, sizeof(memmap));
121 //res = fdt_setprop(v_fdt, memory, "device_type", dtype, strlen(dtype) + 1);
122 logf("fdt_setprop(): %d\n", res);
123
124 logf("valid fdt loaded at 0x%X\n", (unsigned int)fdt);
125
126 return fdt;
127 }
128
129 LoaderImpl() {
130 logf("Mounting boot partitiion ...\n");
131 FRESULT r = f_mount(&g_BootVolumeFs, ROOT_VOLUME_PREFIX, 1);
132 if (r != FR_OK) {
133 panic("failed to mount boot partition, error: %d", (int)r);
134 }
135 logf("Boot partition mounted!\n");
136
137 size_t sz;
138
139 /* dump cmdline.txt for test */
140 uint8_t* cmdline;
141
142 if(!read_file("cmdline.txt", cmdline, sz)) {
143 panic("error reading cmdline");
144 }
145
146 /* nul terminate it */
147 cmdline[sz - 1] = 0;
148 logf("kernel cmdline: %s\n", cmdline);
149
150 /* load flat device tree */
151 uint8_t* fdt = load_fdt("rpi.dtb", cmdline);
152 if (!fdt) {
153 panic("fdt pointer is null");
154 }
155
156 /* after load_fdt is done with it, we don't need it anymore */
157 delete[] cmdline;
158
159 /* read the kernel -- necessarily at fixed address */
160 uint8_t* zImage = reinterpret_cast<uint8_t*>(KERNEL_LOAD_ADDRESS);
161
162 if(!read_file("zImage", zImage, sz, false)) {
163 panic("error reading zImage");
164 }
165
166 logf("zImage loaded at 0x%X\n", (unsigned int)zImage);
167
168 logf("First few of zImage.. %X%X%X%X\n", zImage[0], zImage[1], zImage[2], zImage[3]);
169
170 /* flush the cache */
171 logf("Flushing....\n")
172 for (uint8_t* i = zImage; i < zImage + sz; i += 32) {
173 __asm__ __volatile__ ("mcr p15,0,%0,c7,c10,1" : : "r" (i) : "memory");
174 }
175
176 /* fire away */
177 logf("Jumping to the Linux kernel...\n");
178
179 /* this should never return */
180 logf("FDT loaded at %x\n", (unsigned int) fdt);
181 logf("First few of fdt... %X%X%X%X\n", fdt[0], fdt[1], fdt[2], fdt[3]);
182 boot_linux(0, ~0, fdt, zImage);
183 }
184 };
185
186 static LoaderImpl STATIC_APP g_Loader {};
This page took 0.08787 seconds and 4 git commands to generate.