|  | @@ -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 |  }
 |