|
@@ -56,28 +56,82 @@ struct multiboot_header {
|
56
|
56
|
};
|
57
|
57
|
|
58
|
58
|
static struct multiboot_header *mbheader;
|
|
59
|
+static unsigned int mbimgoffset, mboffset;
|
|
60
|
+static unsigned char mbbuffer[12];
|
59
|
61
|
|
60
|
62
|
static struct multiboot_info mbinfo;
|
61
|
63
|
|
62
|
|
-static void multiboot_probe(unsigned char *data, int len)
|
|
64
|
+static void multiboot_init(void)
|
|
65
|
+{
|
|
66
|
+ mbheader = NULL;
|
|
67
|
+ mbimgoffset = 0;
|
|
68
|
+ mboffset = 0;
|
|
69
|
+}
|
|
70
|
+
|
|
71
|
+/* Remember this probing function is actually different from the usual probing
|
|
72
|
+ * functions, since the Multiboot header is somewhere in the first 8KB of the
|
|
73
|
+ * image and it is byte aligned, but there is not much more known about how to
|
|
74
|
+ * find it. In the Etherboot context the most complicated issue is that the
|
|
75
|
+ * image has to be processed block-by-block, with unknown block size and no
|
|
76
|
+ * guarantees about block alignment with respect to the image. */
|
|
77
|
+static void multiboot_peek(unsigned char *data, int len)
|
63
|
78
|
{
|
64
|
|
- int offset;
|
65
|
79
|
struct multiboot_header *h;
|
66
|
80
|
|
67
|
|
- /* Multiboot spec requires the header to be in first 8KB of the image */
|
68
|
|
- if (len > 8192)
|
69
|
|
- len = 8192;
|
|
81
|
+ /* If we have already searched the first 8KB of the image or if we have
|
|
82
|
+ * already found a valid Multiboot header, skip this code. */
|
|
83
|
+ if ((mboffset == 12) || (mbimgoffset >= 8192))
|
|
84
|
+ return;
|
|
85
|
+
|
|
86
|
+ if (mbimgoffset + len >= 8192)
|
|
87
|
+ len = 8192 - mbimgoffset;
|
70
|
88
|
|
71
|
|
- for (offset = 0; offset < len; offset += 4) {
|
72
|
|
- h = (struct multiboot_header *) (data + offset);
|
73
|
|
- if (h->magic == MULTIBOOT_HEADER_MAGIC
|
74
|
|
- && h->magic + h->flags + h->checksum == 0) {
|
75
|
|
- printf("/Multiboot");
|
76
|
|
- mbheader = h;
|
77
|
|
- return;
|
78
|
|
- }
|
79
|
|
- }
|
80
|
|
- mbheader = 0;
|
|
89
|
+ /* This piece of code is pretty stupid, since it always copies data, even
|
|
90
|
+ * if it is word aligned. This shouldn't matter too much on platforms that
|
|
91
|
+ * use the Multiboot spec, since the processors are usually reasonably fast
|
|
92
|
+ * and this code is only executed for the first 8KB of the image. Feel
|
|
93
|
+ * free to improve it, but be prepared to write quite a lot of code that
|
|
94
|
+ * deals with non-aligned data with respect to the image to load. */
|
|
95
|
+ while (len > 0) {
|
|
96
|
+ mbimgoffset++;
|
|
97
|
+ memcpy(mbbuffer + mboffset, data, 1);
|
|
98
|
+ mboffset++;
|
|
99
|
+ data++;
|
|
100
|
+ len--;
|
|
101
|
+ if (mboffset == 4) {
|
|
102
|
+ /* Accumulated a word into the buffer. */
|
|
103
|
+ h = (struct multiboot_header *)mbbuffer;
|
|
104
|
+ if (h->magic != MULTIBOOT_HEADER_MAGIC) {
|
|
105
|
+ /* Wrong magic, this cannot be the start of the header. */
|
|
106
|
+ mboffset = 0;
|
|
107
|
+ }
|
|
108
|
+ } else if (mboffset == 12) {
|
|
109
|
+ /* Accumulated the minimum header data into the buffer. */
|
|
110
|
+ h = (struct multiboot_header *)mbbuffer;
|
|
111
|
+ if (h->magic + h->flags + h->checksum != 0) {
|
|
112
|
+ /* Checksum error, not a valid header. Check for a possible
|
|
113
|
+ * header starting in the current flag/checksum field. */
|
|
114
|
+ if (h->flags == MULTIBOOT_HEADER_MAGIC) {
|
|
115
|
+ mboffset -= 4;
|
|
116
|
+ memmove(mbbuffer, mbbuffer + 4, mboffset);
|
|
117
|
+ } else if (h->checksum == MULTIBOOT_HEADER_MAGIC) {
|
|
118
|
+ mboffset -= 8;
|
|
119
|
+ memmove(mbbuffer, mbbuffer + 8, mboffset);
|
|
120
|
+ } else {
|
|
121
|
+ mboffset = 0;
|
|
122
|
+ }
|
|
123
|
+ } else {
|
|
124
|
+ printf("Multiboot... ");
|
|
125
|
+ mbheader = h;
|
|
126
|
+ if ((h->flags & 0xfffc) != 0) {
|
|
127
|
+ printf("\nERROR: Unsupported Multiboot requirements flags\n");
|
|
128
|
+ longjmp(restart_etherboot, -2);
|
|
129
|
+ }
|
|
130
|
+ break;
|
|
131
|
+ }
|
|
132
|
+ }
|
|
133
|
+ }
|
|
134
|
+ mbimgoffset += len;
|
81
|
135
|
}
|
82
|
136
|
|
83
|
137
|
static inline void multiboot_boot(unsigned long entry)
|
|
@@ -94,7 +148,7 @@ static inline void multiboot_boot(unsigned long entry)
|
94
|
148
|
* strings of the maximum size are possible. Note this buffer
|
95
|
149
|
* can overrun if a stupid file name is chosen. Oh well. */
|
96
|
150
|
c = cmdline;
|
97
|
|
- for (i = 0; KERNEL_BUF[i] != 0; i++) {
|
|
151
|
+ for (i = 0; KERNEL_BUF[i] != '\0'; i++) {
|
98
|
152
|
switch (KERNEL_BUF[i]) {
|
99
|
153
|
case ' ':
|
100
|
154
|
case '\\':
|
|
@@ -106,6 +160,11 @@ static inline void multiboot_boot(unsigned long entry)
|
106
|
160
|
}
|
107
|
161
|
*c++ = KERNEL_BUF[i];
|
108
|
162
|
}
|
|
163
|
+ if (addparam != NULL) {
|
|
164
|
+ *c++ = ' ';
|
|
165
|
+ memcpy(c, addparam, addparamlen);
|
|
166
|
+ c += addparamlen;
|
|
167
|
+ }
|
109
|
168
|
(void)sprintf(c, " -retaddr %#lX", virt_to_phys(xend32));
|
110
|
169
|
|
111
|
170
|
mbinfo.flags = MULTIBOOT_MMAP_VALID | MULTIBOOT_MEM_VALID |MULTIBOOT_CMDLINE_VALID;
|
|
@@ -139,5 +198,11 @@ static inline void multiboot_boot(unsigned long entry)
|
139
|
198
|
os_regs.eax = 0x2BADB002;
|
140
|
199
|
os_regs.ebx = virt_to_phys(&mbinfo);
|
141
|
200
|
xstart32(entry);
|
142
|
|
- longjmp(restart_etherboot, -2);
|
|
201
|
+ /* A Multiboot kernel by default never returns - there is nothing in the
|
|
202
|
+ * specification about what happens to the boot loader after the kernel has
|
|
203
|
+ * been started. Thus if the kernel returns it is definitely aware of the
|
|
204
|
+ * semantics involved (i.e. the "-retaddr" parameter). Do not treat this
|
|
205
|
+ * as an error, but restart with a fresh DHCP request in order to activate
|
|
206
|
+ * the menu again in case one is used. */
|
|
207
|
+ longjmp(restart_etherboot, 2);
|
143
|
208
|
}
|