Repository navigation
Expand file tree
/
Copy pathboot.c
More file actions
153 lines (123 loc) · 4.69 KB
/
Copy pathboot.c
File metadata and controls
153 lines (123 loc) · 4.69 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (c) 2026, Umer Uddin <umer.uddin@mentallysanemainliners.org>
*/
#include <stdint.h>
#include <drivers/mmc.h>
#include <drivers/nor_flash.h>
#include <drivers/serial.h>
#include <drivers/timer.h>
#include <linux/kernel.h>
#include <printf.h>
#include <bootmode.h>
#include <image_format.h>
#include <fel.h>
struct boot_file_head *egon_head = (void *)0x00020000;
image_header_t image_header = {};
uint64_t boot_addr = 0;
static void load_images_mmc(void) {
uint64_t start_block = (egon_head->boot_media == SUNXI_BOOTED_FROM_MMC0_HIGH) ? 512 : 16;
start_block += (egon_head->length / 512);
printf("Loading image header\n");
if (mmc_read_blocks(start_block, 1, &image_header) != 0) {
printf("Failed to read image header\n");
while (1);
}
printf("Image header: magic=%08x\n", image_header.magic);
if (image_header.magic != IMG_MAGIC) {
printf("Invalid image magic\n");
while (1);
}
if (image_header.cnt > IMG_MAX_ENTRIES) {
printf("Too many image entries: %u\n", image_header.cnt);
while (1);
}
for (uint32_t i = 0; i < image_header.cnt; i++) {
image_entry_t *entry = &image_header.entries[i];
printf("Entry %d: name=%s, load_addr=0x%llx, size=%llu, offset_blocks=%llu\n",
i, entry->name, entry->load_addr, entry->size, entry->offset_blocks);
// First image always takes priority.
if (i == 0)
boot_addr = entry->load_addr;
if(mmc_read_blocks(start_block + entry->offset_blocks, DIV_ROUND_UP(entry->size, 512), (void *)entry->load_addr) != 0) {
printf("Failed to read image block\n");
while (1);
}
printf("Loaded image %s to 0x%llx\n", entry->name, entry->load_addr);
}
printf("Jumping to image at 0x%llx\n", boot_addr);
((void (*)(void))boot_addr)();
}
static void load_images_nor_flash(void) {
uint64_t start_block = (egon_head->length / 512);
printf("Loading image header from NOR flash\n");
if (spi_nor_read_blocks(start_block, 1, &image_header) != 0) {
printf("Failed to read image header from NOR flash\n");
while (1);
}
printf("Image header: magic=%08x\n", image_header.magic);
if (image_header.magic != IMG_MAGIC) {
printf("Invalid image magic\n");
while (1);
}
if (image_header.cnt > IMG_MAX_ENTRIES) {
printf("Too many image entries: %u\n", image_header.cnt);
while (1);
}
for (uint32_t i = 0; i < image_header.cnt; i++) {
image_entry_t *entry = &image_header.entries[i];
printf("Entry %d: name=%s, load_addr=0x%llx, size=%llu, offset_blocks=%llu\n",
i, entry->name, entry->load_addr, entry->size, entry->offset_blocks);
// First image always takes priority.
if (i == 0)
boot_addr = entry->load_addr;
if(spi_nor_read_blocks(start_block + entry->offset_blocks, DIV_ROUND_UP(entry->size, 512), (void *)entry->load_addr) != 0) {
printf("Failed to read image block from NOR flash\n");
while (1);
}
printf("Loaded image %s to 0x%llx\n", entry->name, entry->load_addr);
}
printf("Jumping to image at 0x%llx\n", boot_addr);
((void (*)(void))boot_addr)();
}
void wait_enter_fel(int boot_source) {
char c = '\x00';
if(boot_source == SUNXI_INVALID_BOOT_SOURCE)
return;
printf("Press F to enter FEL mode within 0.5 seconds...\n");
// Wait 0.5s for F, enter fel if done.
for (int i = 0; i < (0.5 * 1000 * 1000); i++) {
uart_getc(&c);
if (c == 'F' || c == 'f') {
printf("Entering FEL mode... (SP: 0x%x, LR: 0x%x)\n", fel_stash.sp, fel_stash.lr);
return_to_fel(fel_stash.sp, fel_stash.lr);
}
udelay(1);
}
}
void load_and_boot_images(uint64_t dram_size, int boot_source) {
printf("Updating SPL header...\n");
egon_head->spl_signature[3] = SPL_DRAM_HEADER_VERSION;
egon_head->dram_size = dram_size >> 20;
switch (boot_source) {
case SUNXI_BOOTED_FROM_MMC0:
case SUNXI_BOOTED_FROM_MMC0_HIGH:
printf("Booted from SD card\n");
printf("Loading image from SD card...\n");
load_images_mmc();
break;
case SUNXI_INVALID_BOOT_SOURCE:
printf("Booted from FEL\n");
printf("Returning to FEL mode, SP: 0x%x, LR: 0x%x\n", fel_stash.sp, fel_stash.lr);
return_to_fel(fel_stash.sp, fel_stash.lr);
break;
case SUNXI_BOOTED_FROM_SPI:
printf("Booted from SPI NOR flash\n");
printf("Loading image from SPI NOR flash...\n");
load_images_nor_flash();
break;
default:
printf("Unsupported boot source: %d\n", boot_source);
break;
}
}