]> git.sesse.net Git - pistorm/blob - platforms/amiga/hunk-reloc.c
3b92e339af17249d5aea002f1ec1c94dbab75e33
[pistorm] / platforms / amiga / hunk-reloc.c
1 // SPDX-License-Identifier: MIT
2
3 #include <stdio.h>
4 #include <stdint.h>
5 #include <stdlib.h>
6 #include <string.h>
7 #include <unistd.h>
8 #include <endian.h>
9 #include "hunk-reloc.h"
10 #include "piscsi/piscsi-enums.h"
11
12 #ifdef FAKESTORM
13 #define lseek64 lseek
14 #endif
15
16 #define DEBUG(...)
17 //#define DEBUG printf
18
19 #define BE(val) be32toh(val)
20 #define BE16(val) be16toh(val)
21
22 #define READLW(a, b) fread(&a, 4, 1, b); a = be32toh(a);
23 #define READW(a, b) fread(&a, 2, 1, b); a = be16toh(a);
24
25 uint32_t lw = 0;
26 static uint32_t file_offset = 0, add_size = 0;
27
28 char *hunk_id_name(uint32_t index) {
29     switch (index) {
30         case HUNKTYPE_HEADER:
31             return "HUNK_HEADER";
32         case HUNKTYPE_CODE:
33             return "HUNK_CODE";
34         case HUNKTYPE_HUNK_RELOC32:
35             return "HUNK_RELOC32";
36         case HUNKTYPE_SYMBOL:
37             return "HUNK_SYMBOL";
38         case HUNKTYPE_BSS:
39             return "HUNK_BSS";
40         case HUNKTYPE_DATA:
41             return "HUNK_DATA";
42         case HUNKTYPE_END:
43             return "HUNK_END";
44         default:
45             return "UNKNOWN HUNK TYPE";
46     }
47 }
48
49 int process_hunk(uint32_t index, struct hunk_info *info, FILE *f, struct hunk_reloc *r) {
50     if (!f)
51         return -1;
52     
53     uint32_t discard = 0, cur_hunk = 0, offs32 = 0;
54     
55     switch (index) {
56         case HUNKTYPE_HEADER:
57             DEBUG("Processing hunk header.\n");
58             do {
59                 READLW(discard, f);
60                 if (discard) {
61                     info->libnames[info->num_libs] = malloc(discard * 4);
62                     fread(info->libnames[info->num_libs], discard, 4, f);
63                     info->num_libs++;
64                 }
65             } while (discard);
66             
67             READLW(info->table_size, f);
68             DEBUG("Table size: %d\n", info->table_size);
69             READLW(info->first_hunk, f);
70             READLW(info->last_hunk, f);
71             info->num_hunks = (info->last_hunk - info->first_hunk) + 1;
72             DEBUG("First: %d Last: %d Num: %d\n", info->first_hunk, info->last_hunk, info->num_hunks);
73             info->hunk_sizes = malloc(info->num_hunks * 4);
74             info->hunk_offsets = malloc(info->num_hunks * 4);
75             for (uint32_t i = 0; i < info->table_size; i++) {
76                 READLW(info->hunk_sizes[i], f);
77                 DEBUG("Hunk %d: %d (%.8X)\n", i, info->hunk_sizes[i] * 4, info->hunk_sizes[i] * 4);
78             }
79             return 0;
80             break;
81         case HUNKTYPE_CODE:
82             DEBUG("Hunk %d: CODE.\n", info->current_hunk);
83             READLW(discard, f);
84             info->hunk_offsets[info->current_hunk] = ftell(f) - file_offset;
85             DEBUG("Code hunk size: %d (%.8X)\n", discard * 4, discard * 4);
86             fseek(f, discard * 4, SEEK_CUR);
87             return 0;
88             break;
89         case HUNKTYPE_HUNK_RELOC32:
90             DEBUG("Hunk %d: RELOC32.\n", info->current_hunk);
91             DEBUG("Processing Reloc32 hunk.\n");
92             do {
93                 READLW(discard, f);
94                 if (discard && discard != 0xFFFFFFFF) {
95                     READLW(cur_hunk, f);
96                     DEBUG("Relocating %d offsets pointing to hunk %d.\n", discard, cur_hunk);
97                     for(uint32_t i = 0; i < discard; i++) {
98                         READLW(offs32, f);
99                         DEBUG("#%d: @%.8X in hunk %d\n", i + 1, offs32, cur_hunk);
100                         r[info->reloc_hunks].offset = offs32;
101                         r[info->reloc_hunks].src_hunk = info->current_hunk;
102                         r[info->reloc_hunks].target_hunk = cur_hunk;
103                         info->reloc_hunks++;
104                     }
105                 }
106             } while(discard);
107             return 0;
108             break;
109         case HUNKTYPE_SYMBOL:
110             DEBUG("Hunk %d: SYMBOL.\n", info->current_hunk);
111             DEBUG("Processing Symbol hunk.\n");
112             READLW(discard, f);
113             do {
114                 if (discard) {
115                     char sstr[256];
116                     memset(sstr, 0x00, 256);
117                     fread(sstr, discard, 4, f);
118                     READLW(discard, f);
119                     DEBUG("Symbol: %s - %.8X\n", sstr, discard);
120                 }
121                 READLW(discard, f);
122             } while (discard);
123             return 0;
124             break;
125         case HUNKTYPE_BSS:
126             DEBUG("Hunk %d: BSS.\n", info->current_hunk);
127             READLW(discard, f);
128             info->hunk_offsets[info->current_hunk] = ftell(f) - file_offset;
129             DEBUG("Skipping BSS hunk. Size: %d\n", discard * 4);
130             add_size += (discard * 4);
131             return 0;
132         case HUNKTYPE_DATA:
133             DEBUG("Hunk %d: DATA.\n", info->current_hunk);
134             READLW(discard, f);
135             info->hunk_offsets[info->current_hunk] = ftell(f) - file_offset;
136             DEBUG("Skipping data hunk. Size: %d.\n", discard * 4);
137             fseek(f, discard * 4, SEEK_CUR);
138             return 0;
139             break;
140         case HUNKTYPE_END:
141             DEBUG("END: Ending hunk %d.\n", info->current_hunk);
142             info->current_hunk++;
143             return 0;
144             break;
145         default:
146             DEBUG("Unknown hunk type %.8X! Can't process!\n", index);
147             break;
148     }
149
150     return -1;
151 }
152
153 void reloc_hunk(struct hunk_reloc *h, uint8_t *buf, struct hunk_info *i) {
154     uint32_t rel = i->hunk_offsets[h->target_hunk];
155     uint32_t *src_ptr = (uint32_t *)(&buf[i->hunk_offsets[h->src_hunk] + h->offset]);
156
157     uint32_t src = be32toh(*src_ptr);
158     uint32_t dst = src + i->base_offset + rel;
159     DEBUG("%.8X -> %.8X\n", src, dst);
160     *src_ptr = htobe32(dst);
161 }
162
163 void process_hunks(FILE *in, struct hunk_info *h_info, struct hunk_reloc *r, uint32_t offset) {
164     READLW(lw, in);
165     DEBUG("Hunk ID: %.8X (%s)\n", lw, hunk_id_name(lw));
166
167     file_offset = offset;
168     add_size = 0;
169
170     while (!feof(in) && process_hunk(lw, h_info, in, r) != -1) {
171         READLW(lw, in);
172         if (feof(in)) goto end_parse;
173         DEBUG("Hunk ID: %.8X (%s)\n", lw, hunk_id_name(lw));
174         DEBUG("File pos: %.8lX\n", ftell(in) - file_offset);
175     }
176     end_parse:;
177     DEBUG("Done processing hunks.\n");
178 }
179
180 void reloc_hunks(struct hunk_reloc *r, uint8_t *buf, struct hunk_info *h_info) {
181     DEBUG("Relocating %d offsets.\n", h_info->reloc_hunks);
182     for (uint32_t i = 0; i < h_info->reloc_hunks; i++) {
183         DEBUG("Relocating offset %d.\n", i);
184         reloc_hunk(&r[i], buf, h_info);
185     }
186     DEBUG("Done relocating offsets.\n");
187 }
188
189 struct LoadSegBlock {
190     uint32_t   lsb_ID;
191     uint32_t   lsb_SummedLongs;
192     int32_t    lsb_ChkSum;
193     uint32_t   lsb_HostID;
194     uint32_t   lsb_Next;
195     uint32_t   lsb_LoadData[PISCSI_MAX_BLOCK_SIZE / 4];
196 };
197 #define LOADSEG_IDENTIFIER 0x4C534547
198
199 int load_lseg(int fd, uint8_t **buf_p, struct hunk_info *i, struct hunk_reloc *relocs, uint32_t block_size) {
200     if (fd == -1)
201         return -1;
202     
203     if (block_size == 0)
204         block_size = 512;
205
206     uint8_t *block = malloc(block_size);
207     uint32_t next_blk = 0;
208     struct LoadSegBlock *lsb = (struct LoadSegBlock *)block;
209
210     read(fd, block, block_size);
211     if (BE(lsb->lsb_ID) != LOADSEG_IDENTIFIER) {
212         DEBUG("[LOAD_LSEG] Attempted to load a non LSEG-block: %.8X", BE(lsb->lsb_ID));
213         goto fail;
214     }
215
216     char *filename = "data/lsegout.bin";
217     FILE *out = fopen(filename, "wb+");
218
219     DEBUG("[LOAD_LSEG] LSEG data:\n");
220     DEBUG("[LOAD_LSEG] Longs: %d HostID: %d\n", BE(lsb->lsb_SummedLongs), BE(lsb->lsb_HostID));
221     DEBUG("[LOAD_LSEG] Next: %d LoadData: %p\n", BE(lsb->lsb_Next), (void *)lsb->lsb_LoadData);
222     next_blk = BE(lsb->lsb_Next);
223     do {
224         next_blk = BE(lsb->lsb_Next);
225         fwrite(lsb->lsb_LoadData, 1, block_size - 20, out);
226         lseek64(fd, next_blk * block_size, SEEK_SET);
227         read(fd, block, block_size);
228     } while (next_blk != 0xFFFFFFFF);
229     
230     uint32_t file_size = ftell(out);
231     fseek(out, 0, SEEK_SET);
232     uint8_t *buf = malloc(file_size + 1024);
233     fread(buf, file_size, 1, out);
234     fseek(out, 0, SEEK_SET);
235     process_hunks(out, i, relocs, 0x0);
236
237     fclose(out);
238     *buf_p = buf;
239     i->byte_size = file_size;
240     i->alloc_size = file_size + add_size;
241
242     return 0;
243
244 fail:;
245     if (block)
246         free(block);
247
248     return -1;
249 }