1/*-
2 * Copyright (c) 1999 Global Technology Associates, Inc.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS
18 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
19 * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
20 * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
21 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
22 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
23 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
24 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 */
26
27#include <sys/cdefs.h>
28__FBSDID("$FreeBSD$");
29
30#include <sys/types.h>
31#include <sys/reboot.h>
32#include <sys/inflate.h>
33
34#include "kgzldr.h"
35
36#define KGZ_HEAD   0xa          /* leading bytes to ignore */
37#define KGZ_TAIL   0x8          /* trailing bytes to ignore */
38
39#define E_FMT  1		/* Error: Invalid format */
40#define E_MEM  2		/* Error: Out of memory */
41
42struct kgz_hdr {
43    char	ident[4];	/* identification */
44    uint32_t	dload;		/* decoded image load address */
45    uint32_t	dsize;		/* decoded image size */
46    uint32_t	isize;		/* image size in memory */
47    uint32_t	entry;		/* program entry point */
48    uint32_t	nsize;		/* encoded image size */
49};
50extern struct kgz_hdr kgz;	/* header */
51extern uint8_t kgz_ndata[];	/* encoded image */
52
53static const char *const msg[] = {
54    "done",
55    "invalid format",
56    "out of memory"
57};
58
59static const u_char *ip;        /* input pointer */
60static u_char *op;              /* output pointer */
61
62static struct inflate infl;	/* inflate() parameters */
63
64static int decode(void);
65static int input(void *);
66static int output(void *, u_char *, u_long);
67
68/*
69 * Uncompress and boot a kernel.
70 */
71int
72boot(int howto)
73{
74    int err;
75
76    kgz_con = howto & RB_SERIAL ? KGZ_SIO : KGZ_CRT;
77    putstr("Uncompressing ... ");
78    err = decode();
79    putstr(msg[err]);
80    putstr("\n");
81    if (err) {
82        putstr("System halted");
83	for (;;)
84	    ;
85    }
86    return err;
87}
88
89/*
90 * Interface with inflate() to uncompress the data.
91 */
92static int
93decode(void)
94{
95    static u_char slide[GZ_WSIZE];
96    int err;
97
98    ip = kgz_ndata + KGZ_HEAD;
99    op = (u_char *)kgz.dload;
100    infl.gz_input = input;
101    infl.gz_output = output;
102    infl.gz_slide = slide;
103    err = inflate(&infl);
104    return err ? err == 3 ? E_MEM : E_FMT : 0;
105}
106
107/*
108 * Read a byte.
109 */
110static int
111input(void *dummy)
112{
113    if ((size_t)(ip - kgz_ndata) + KGZ_TAIL > kgz.nsize)
114        return GZ_EOF;
115    return *ip++;
116}
117
118/*
119 * Write some bytes.
120 */
121static int
122output(void *dummy, u_char * ptr, u_long len)
123{
124    if (op - (u_char *)kgz.dload + len > kgz.dsize)
125        return -1;
126    while (len--)
127        *op++ = *ptr++;
128    return 0;
129}
130