1119482Sobrien/*- 248907Srnordier * Copyright (c) 1999 Global Technology Associates, Inc. 348907Srnordier * All rights reserved. 448907Srnordier * 548907Srnordier * Redistribution and use in source and binary forms, with or without 648907Srnordier * modification, are permitted provided that the following conditions 748907Srnordier * are met: 848907Srnordier * 1. Redistributions of source code must retain the above copyright 948907Srnordier * notice, this list of conditions and the following disclaimer. 1048907Srnordier * 2. Redistributions in binary form must reproduce the above copyright 1148907Srnordier * notice, this list of conditions and the following disclaimer in the 1248907Srnordier * documentation and/or other materials provided with the distribution. 1348907Srnordier * 1448907Srnordier * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS``AS IS'' AND 1548907Srnordier * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1648907Srnordier * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 1748907Srnordier * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS 1848907Srnordier * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, 1948907Srnordier * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT 2048907Srnordier * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 2148907Srnordier * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 2248907Srnordier * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 2348907Srnordier * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 2448907Srnordier * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 2548907Srnordier */ 2648907Srnordier 27119482Sobrien#include <sys/cdefs.h> 28119482Sobrien__FBSDID("$FreeBSD$"); 29119482Sobrien 3048907Srnordier#include <sys/types.h> 3148907Srnordier#include <sys/reboot.h> 3248907Srnordier#include <sys/inflate.h> 3348907Srnordier 3448907Srnordier#include "kgzldr.h" 3548907Srnordier 3648907Srnordier#define KGZ_HEAD 0xa /* leading bytes to ignore */ 3748907Srnordier#define KGZ_TAIL 0x8 /* trailing bytes to ignore */ 3848907Srnordier 3948907Srnordier#define E_FMT 1 /* Error: Invalid format */ 4048907Srnordier#define E_MEM 2 /* Error: Out of memory */ 4148907Srnordier 4248907Srnordierstruct kgz_hdr { 4348907Srnordier char ident[4]; /* identification */ 4448907Srnordier uint32_t dload; /* decoded image load address */ 4548907Srnordier uint32_t dsize; /* decoded image size */ 4648907Srnordier uint32_t isize; /* image size in memory */ 4748907Srnordier uint32_t entry; /* program entry point */ 4848907Srnordier uint32_t nsize; /* encoded image size */ 4948907Srnordier}; 5048907Srnordierextern struct kgz_hdr kgz; /* header */ 5148907Srnordierextern uint8_t kgz_ndata[]; /* encoded image */ 5248907Srnordier 5348907Srnordierstatic const char *const msg[] = { 5448907Srnordier "done", 5548907Srnordier "invalid format", 5648907Srnordier "out of memory" 5748907Srnordier}; 5848907Srnordier 5948907Srnordierstatic const u_char *ip; /* input pointer */ 6048907Srnordierstatic u_char *op; /* output pointer */ 6148907Srnordier 6248907Srnordierstatic struct inflate infl; /* inflate() parameters */ 6348907Srnordier 6448907Srnordierstatic int decode(void); 6548907Srnordierstatic int input(void *); 6648907Srnordierstatic int output(void *, u_char *, u_long); 6748907Srnordier 6848907Srnordier/* 6948907Srnordier * Uncompress and boot a kernel. 7048907Srnordier */ 7148907Srnordierint 7248907Srnordierboot(int howto) 7348907Srnordier{ 7448907Srnordier int err; 7548907Srnordier 7648907Srnordier kgz_con = howto & RB_SERIAL ? KGZ_SIO : KGZ_CRT; 7748907Srnordier putstr("Uncompressing ... "); 7848907Srnordier err = decode(); 7948907Srnordier putstr(msg[err]); 8048907Srnordier putstr("\n"); 8148907Srnordier if (err) { 8248907Srnordier putstr("System halted"); 8348907Srnordier for (;;) 8448907Srnordier ; 8548907Srnordier } 8648907Srnordier return err; 8748907Srnordier} 8848907Srnordier 8948907Srnordier/* 9048907Srnordier * Interface with inflate() to uncompress the data. 9148907Srnordier */ 9248907Srnordierstatic int 9348907Srnordierdecode(void) 9448907Srnordier{ 9548907Srnordier static u_char slide[GZ_WSIZE]; 9648907Srnordier int err; 9748907Srnordier 9848907Srnordier ip = kgz_ndata + KGZ_HEAD; 9948907Srnordier op = (u_char *)kgz.dload; 10048907Srnordier infl.gz_input = input; 10148907Srnordier infl.gz_output = output; 10248907Srnordier infl.gz_slide = slide; 10348907Srnordier err = inflate(&infl); 10448907Srnordier return err ? err == 3 ? E_MEM : E_FMT : 0; 10548907Srnordier} 10648907Srnordier 10748907Srnordier/* 10848907Srnordier * Read a byte. 10948907Srnordier */ 11048907Srnordierstatic int 11148907Srnordierinput(void *dummy) 11248907Srnordier{ 11348907Srnordier if ((size_t)(ip - kgz_ndata) + KGZ_TAIL > kgz.nsize) 11448907Srnordier return GZ_EOF; 11548907Srnordier return *ip++; 11648907Srnordier} 11748907Srnordier 11848907Srnordier/* 11948907Srnordier * Write some bytes. 12048907Srnordier */ 12148907Srnordierstatic int 12248907Srnordieroutput(void *dummy, u_char * ptr, u_long len) 12348907Srnordier{ 12448907Srnordier if (op - (u_char *)kgz.dload + len > kgz.dsize) 12548907Srnordier return -1; 12648907Srnordier while (len--) 12748907Srnordier *op++ = *ptr++; 12848907Srnordier return 0; 12948907Srnordier} 130