Clone a tag rather than SeaBIOS stable branch HEAD
[coreboot.git] / payloads / bayou / self.c
1 /*
2  * This file is part of the bayou project.
3  *
4  * Copyright (C) 2008 Advanced Micro Devices, Inc.
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License version 2 as
8  * published by the Free Software Foundation.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
18  */
19
20 #include "bayou.h"
21 #include "self.h"
22
23 static int nop_decompress(void *dst, void *src, int len)
24 {
25         memcpy(dst, src, len);
26         return len;
27 }
28
29 #ifdef CONFIG_LZMA
30 extern int ulzma(u8 *, u8 *);
31
32 static int lzma_decompress(void *dst, void *src, int len)
33 {
34         return ulzma((u8 *) src, (u8 *) dst);
35 }
36 #endif
37
38 #ifdef CONFIG_NRV2B
39 extern int unrv2b(u8 *, u8 *, unsigned long *);
40
41 static int nrv2b_decompress(void *dst, void *src, int len)
42 {
43         unsigned long l = (u32) len;
44         return unrv2b(src, dst, &l);
45 }
46 #endif
47
48 static int zeros_decompress(void *dst, void *src, int len)
49 {
50         memset(dst, 0, len);
51         return len;
52 }
53
54 int self_get_params(u8 *fptr, u8 **params)
55 {
56         struct self_segment *seg = (struct self_segment *)fptr;
57
58         while (seg->type != SELF_TYPE_ENTRY) {
59                 if (seg->type == 0)
60                         return -1;
61
62                 if (seg->type == SELF_TYPE_PARAMS) {
63                         *params = (u8 *) (fptr + seg->offset);
64                         return seg->len;
65                 }
66
67                 seg++;
68         }
69
70         *params = NULL;
71
72         return 0;
73 }
74
75 int verify_self(u8 *ptr)
76 {
77         struct self_segment *seg = (struct self_segment *)ptr;
78
79         switch (seg->type) {
80         case SELF_TYPE_CODE:
81         case SELF_TYPE_DATA:
82         case SELF_TYPE_BSS:
83         case SELF_TYPE_PARAMS:
84         case SELF_TYPE_ENTRY:
85                 return 1;
86         }
87
88         return 0;
89 }
90
91 int self_load_and_run(struct payload *p, int *ret)
92 {
93         struct self_segment *seg = (struct self_segment *)p->fptr;
94         int (*dcmp) (void *, void *, int);
95         int dlen;
96
97         switch (p->stat.compression) {
98 #ifdef CONFIG_LZMA
99         case ALGO_LZMA:
100                 dcmp = lzma_decompress;
101                 break;
102 #endif
103 #ifdef CONFIG_NRV2B
104         case ALGO_NRV2B:
105                 dcmp = nrv2b_decompress;
106                 break;
107 #endif
108         case ALGO_ZEROES:
109                 dcmp = zeros_decompress;
110                 break;
111         case ALGO_NONE:
112                 dcmp = nop_decompress;
113         default:
114                 printf("E: Unsupported decompression type\n");
115                 return -1;
116         }
117
118         while (1) {
119                 u32 laddr = (u32) (seg->load_addr & 0xFFFFFFFF);
120
121                 switch (seg->type) {
122                 case SELF_TYPE_CODE:
123                 case SELF_TYPE_DATA:
124                         dlen = dcmp((void *)laddr,
125                                     (void *)p->fptr + seg->offset, seg->len);
126
127                         if (dlen < seg->mem_len) {
128                                 memset((void *)(laddr + dlen), 0,
129                                        seg->mem_len - dlen);
130                         }
131                         break;
132
133                 case SELF_TYPE_BSS:
134                         memset((void *)laddr, 0, seg->len);
135                         break;
136                 case SELF_TYPE_ENTRY:
137                         *ret = exec(laddr, 0, NULL);
138                         return 0;
139                 default:
140                         break;
141                 }
142
143                 seg++;
144         }
145
146         return -1;
147 }