1 /******************************************************************************
2  * xg_private.c
3  *
4  * Helper functions for the rest of the library.
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation;
9  * version 2.1 of the License.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; If not, see <http://www.gnu.org/licenses/>.
18  */
19 
20 #include <stdlib.h>
21 #include <unistd.h>
22 #include <zlib.h>
23 
24 #include "xg_private.h"
25 
xc_read_image(xc_interface * xch,const char * filename,unsigned long * size)26 char *xc_read_image(xc_interface *xch,
27                     const char *filename, unsigned long *size)
28 {
29     int kernel_fd = -1;
30     gzFile kernel_gfd = NULL;
31     char *image = NULL, *tmp;
32     unsigned int bytes;
33 
34     if ( (filename == NULL) || (size == NULL) )
35         return NULL;
36 
37     if ( (kernel_fd = open(filename, O_RDONLY)) < 0 )
38     {
39         PERROR("Could not open kernel image '%s'", filename);
40         goto out;
41     }
42 
43     if ( (kernel_gfd = gzdopen(kernel_fd, "rb")) == NULL )
44     {
45         PERROR("Could not allocate decompression state for state file");
46         goto out;
47     }
48 
49     *size = 0;
50 
51 #define CHUNK 1*1024*1024
52     while(1)
53     {
54         if ( (tmp = realloc(image, *size + CHUNK)) == NULL )
55         {
56             PERROR("Could not allocate memory for kernel image");
57             free(image);
58             image = NULL;
59             goto out;
60         }
61         image = tmp;
62 
63         bytes = gzread(kernel_gfd, image + *size, CHUNK);
64         switch (bytes)
65         {
66         case -1:
67             PERROR("Error reading kernel image");
68             free(image);
69             image = NULL;
70             goto out;
71         case 0: /* EOF */
72             if ( *size == 0 )
73             {
74                 PERROR("Could not read kernel image");
75                 free(image);
76                 image = NULL;
77             }
78             goto out;
79         default:
80             *size += bytes;
81             break;
82         }
83     }
84 #undef CHUNK
85 
86  out:
87     if ( image )
88     {
89         /* Shrink allocation to fit image. */
90         tmp = realloc(image, *size);
91         if ( tmp )
92             image = tmp;
93     }
94 
95     if ( kernel_gfd != NULL )
96         gzclose(kernel_gfd);
97     else if ( kernel_fd >= 0 )
98         close(kernel_fd);
99     return image;
100 }
101 
xc_inflate_buffer(xc_interface * xch,const char * in_buf,unsigned long in_size,unsigned long * out_size)102 char *xc_inflate_buffer(xc_interface *xch,
103                         const char *in_buf, unsigned long in_size,
104                         unsigned long *out_size)
105 {
106     int           sts;
107     z_stream      zStream;
108     unsigned long out_len;
109     char         *out_buf;
110 
111     /* Not compressed? Then return the original buffer. */
112     if ( ((unsigned char)in_buf[0] != 0x1F) ||
113          ((unsigned char)in_buf[1] != 0x8B) )
114     {
115         if ( out_size != NULL )
116             *out_size = in_size;
117         return (char *)in_buf;
118     }
119 
120     out_len = (unsigned char)in_buf[in_size-4] +
121         (256 * ((unsigned char)in_buf[in_size-3] +
122                 (256 * ((unsigned char)in_buf[in_size-2] +
123                         (256 * (unsigned char)in_buf[in_size-1])))));
124 
125     memset(&zStream, 0, sizeof(zStream));
126     out_buf = malloc(out_len + 16);        /* Leave a little extra space */
127     if ( out_buf == NULL )
128     {
129         ERROR("Error mallocing buffer\n");
130         return NULL;
131     }
132 
133     zStream.next_in = (unsigned char *)in_buf;
134     zStream.avail_in = in_size;
135     zStream.next_out = (unsigned char *)out_buf;
136     zStream.avail_out = out_len+16;
137     sts = inflateInit2(&zStream, (MAX_WBITS+32)); /* +32 means "handle gzip" */
138     if ( sts != Z_OK )
139     {
140         ERROR("inflateInit failed, sts %d\n", sts);
141         free(out_buf);
142         return NULL;
143     }
144 
145     /* Inflate in one pass/call */
146     sts = inflate(&zStream, Z_FINISH);
147     inflateEnd(&zStream);
148     if ( sts != Z_STREAM_END )
149     {
150         ERROR("inflate failed, sts %d\n", sts);
151         free(out_buf);
152         return NULL;
153     }
154 
155     if ( out_size != NULL )
156         *out_size = out_len;
157 
158     return out_buf;
159 }
160 
161 /*******************/
162 
pin_table(xc_interface * xch,unsigned int type,unsigned long mfn,uint32_t dom)163 int pin_table(
164     xc_interface *xch, unsigned int type, unsigned long mfn, uint32_t dom)
165 {
166     struct mmuext_op op;
167 
168     op.cmd = type;
169     op.arg1.mfn = mfn;
170 
171     if ( xc_mmuext_op(xch, &op, 1, dom) < 0 )
172         return 1;
173 
174     return 0;
175 }
176 
177 /* This is shared between save and restore, and may generally be useful. */
csum_page(void * page)178 unsigned long csum_page(void *page)
179 {
180     int i;
181     unsigned long *p = page;
182     unsigned long long sum=0;
183 
184     for ( i = 0; i < (PAGE_SIZE/sizeof(unsigned long)); i++ )
185         sum += p[i];
186 
187     return sum ^ (sum>>32);
188 }
189 
190 /*
191  * Local variables:
192  * mode: C
193  * c-file-style: "BSD"
194  * c-basic-offset: 4
195  * tab-width: 4
196  * indent-tabs-mode: nil
197  * End:
198  */
199