Browse Source

Merge from Etherboot 5.4

tags/v0.9.3
Michael Brown 18 years ago
parent
commit
9b18017296
2 changed files with 83 additions and 18 deletions
  1. 1
    1
      src/arch/i386/core/elf.c
  2. 82
    17
      src/arch/i386/core/multiboot_loader.c

+ 1
- 1
src/arch/i386/core/elf.c View File

74
 	notes.nf1.n_descsz = sizeof(notes.nf1_bootp_data);
74
 	notes.nf1.n_descsz = sizeof(notes.nf1_bootp_data);
75
 	notes.nf1.n_type   = EB_BOOTP_DATA;
75
 	notes.nf1.n_type   = EB_BOOTP_DATA;
76
 	CP(notes.nf1_name,   EB_PARAM_NOTE);
76
 	CP(notes.nf1_name,   EB_PARAM_NOTE);
77
-	notes.nf1_bootp_data = virt_to_phys(BOOTP_DATA_ADDR);
77
+	notes.nf1_bootp_data = virt_to_phys(&bootp_data);
78
 
78
 
79
 	notes.nf2.n_namesz = sizeof(EB_PARAM_NOTE);
79
 	notes.nf2.n_namesz = sizeof(EB_PARAM_NOTE);
80
 	notes.nf2.n_descsz = sizeof(notes.nf2_header);
80
 	notes.nf2.n_descsz = sizeof(notes.nf2_header);

+ 82
- 17
src/arch/i386/core/multiboot_loader.c View File

56
 };
56
 };
57
 
57
 
58
 static struct multiboot_header *mbheader;
58
 static struct multiboot_header *mbheader;
59
+static unsigned int mbimgoffset, mboffset;
60
+static unsigned char mbbuffer[12];
59
 
61
 
60
 static struct multiboot_info mbinfo;
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
     struct multiboot_header *h;
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
 static inline void multiboot_boot(unsigned long entry)
137
 static inline void multiboot_boot(unsigned long entry)
94
 	 * strings of the maximum size are possible.  Note this buffer
148
 	 * strings of the maximum size are possible.  Note this buffer
95
 	 * can overrun if a stupid file name is chosen.  Oh well.  */
149
 	 * can overrun if a stupid file name is chosen.  Oh well.  */
96
 	c = cmdline;
150
 	c = cmdline;
97
-	for (i = 0; KERNEL_BUF[i] != 0; i++) {
151
+	for (i = 0; KERNEL_BUF[i] != '\0'; i++) {
98
 		switch (KERNEL_BUF[i]) {
152
 		switch (KERNEL_BUF[i]) {
99
 		case ' ':
153
 		case ' ':
100
 		case '\\':
154
 		case '\\':
106
 		}
160
 		}
107
 		*c++ = KERNEL_BUF[i];
161
 		*c++ = KERNEL_BUF[i];
108
 	}
162
 	}
163
+	if (addparam != NULL) {
164
+		*c++ = ' ';
165
+		memcpy(c, addparam, addparamlen);
166
+		c += addparamlen;
167
+	}
109
 	(void)sprintf(c, " -retaddr %#lX", virt_to_phys(xend32));
168
 	(void)sprintf(c, " -retaddr %#lX", virt_to_phys(xend32));
110
 
169
 
111
 	mbinfo.flags = MULTIBOOT_MMAP_VALID | MULTIBOOT_MEM_VALID |MULTIBOOT_CMDLINE_VALID;
170
 	mbinfo.flags = MULTIBOOT_MMAP_VALID | MULTIBOOT_MEM_VALID |MULTIBOOT_CMDLINE_VALID;
139
 	os_regs.eax = 0x2BADB002;
198
 	os_regs.eax = 0x2BADB002;
140
 	os_regs.ebx = virt_to_phys(&mbinfo);
199
 	os_regs.ebx = virt_to_phys(&mbinfo);
141
 	xstart32(entry);
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
 }

Loading…
Cancel
Save