]> git.sesse.net Git - pistorm/blob - platforms/amiga/piscsi/piscsi.c
[WIP] Pile of stuff
[pistorm] / platforms / amiga / piscsi / piscsi.c
1 #include <stdio.h>
2 #include <stdint.h>
3 #include <stdlib.h>
4 #include <string.h>
5 #include <fcntl.h>
6 #include <unistd.h>
7 #include <endian.h>
8 #include "piscsi.h"
9 #include "piscsi-enums.h"
10 #include "../hunk-reloc.h"
11 #include "../../../config_file/config_file.h"
12 #include "../../../gpio/ps_protocol.h"
13
14 // Comment this line to restore debug output:
15 //#define printf(...)
16
17 #ifdef FAKESTORM
18 #define lseek64 lseek
19 #endif
20
21 extern struct emulator_config *cfg;
22 extern void stop_cpu_emulation(uint8_t disasm_cur);
23
24 struct piscsi_dev devs[8];
25 uint8_t piscsi_cur_drive = 0;
26 uint32_t piscsi_u32[4];
27 uint32_t piscsi_dbg[8];
28 uint32_t piscsi_rom_size = 0;
29 uint8_t *piscsi_rom_ptr;
30
31 extern unsigned char ac_piscsi_rom[];
32
33 static const char *op_type_names[4] = {
34     "BYTE",
35     "WORD",
36     "LONGWORD",
37     "MEM",
38 };
39
40 //static const char *partition_marker = "PART";
41
42 struct hunk_info piscsi_hinfo;
43 struct hunk_reloc piscsi_hreloc[256];
44
45 void piscsi_init() {
46     for (int i = 0; i < 8; i++) {
47         devs[i].fd = -1;
48         devs[i].lba = 0;
49         devs[i].c = devs[i].h = devs[i].s = 0;
50     }
51
52     FILE *in = fopen("./platforms/amiga/piscsi/piscsi.rom", "rb");
53     if (in == NULL) {
54         printf("[PISCSI] Could not open PISCSI Boot ROM file for reading.\n");
55         // Zero out the boot ROM offset from the autoconfig ROM.
56         ac_piscsi_rom[20] = 0;
57         ac_piscsi_rom[21] = 0;
58         ac_piscsi_rom[22] = 0;
59         ac_piscsi_rom[23] = 0;
60         return;
61     }
62     fseek(in, 0, SEEK_END);
63     piscsi_rom_size = ftell(in);
64     fseek(in, 0, SEEK_SET);
65     piscsi_rom_ptr = malloc(piscsi_rom_size);
66     fread(piscsi_rom_ptr, piscsi_rom_size, 1, in);
67     fclose(in);
68
69     // Parse the hunks in the device driver to find relocation offsets
70     in = fopen("./platforms/amiga/piscsi/device_driver_amiga/pi-scsi.device", "rb");
71     fseek(in, 0x0, SEEK_SET);
72     process_hunks(in, &piscsi_hinfo, piscsi_hreloc);
73
74     fclose(in);
75     printf("[PISCSI] Loaded Boot ROM.\n");
76 }
77
78 void piscsi_find_partitions(struct piscsi_dev *d) {
79     int fd = d->fd;
80     char *block = malloc(512);
81     int cur_partition = 0;
82     uint8_t tmp;
83
84     if (!d->rdb || d->rdb->rdb_PartitionList == 0) {
85         printf("[PISCSI] No partitions on disk.\n");
86         return;
87     }
88
89     lseek(fd, be32toh(d->rdb->rdb_PartitionList) * 512, SEEK_SET);
90 next_partition:;
91     read(fd, block, 512);
92
93     struct PartitionBlock *pb = (struct PartitionBlock *)block;
94     tmp = pb->pb_DriveName[0];
95     pb->pb_DriveName[tmp + 1] = 0x00;
96     printf("Partition %d: %s\n", cur_partition, pb->pb_DriveName + 1);
97     d->pb[cur_partition] = pb;
98
99     if (d->pb[cur_partition]->pb_Next != 0xFFFFFFFF) {
100         uint64_t next = be32toh(pb->pb_Next);
101         block = malloc(512);
102         lseek64(fd, next * 512, SEEK_SET);
103         cur_partition++;
104         printf("Next partition at block %d.\n", be32toh(pb->pb_Next));
105         goto next_partition;
106     }
107     printf("No more partitions on disk.\n");
108
109     return;
110 }
111
112 int piscsi_parse_rdb(struct piscsi_dev *d) {
113     int fd = d->fd;
114     int i = 0;
115     uint8_t *block = malloc(512);
116
117     lseek(fd, 0, SEEK_SET);
118     for (i = 0; i < RDB_BLOCK_LIMIT; i++) {
119         read(fd, block, 512);
120         uint32_t first = be32toh(*((uint32_t *)&block[0]));
121         if (first == RDB_IDENTIFIER)
122             goto rdb_found;
123         else {
124             printf("Block %d is not RDB, looking for %.8X, found %.8X\n", i, RDB_IDENTIFIER, first);
125         }
126     }
127     goto no_rdb_found;
128 rdb_found:;
129     struct RigidDiskBlock *rdb = (struct RigidDiskBlock *)block;
130     printf("[PISCSI] RDB found at block %d.\n", i);
131     d->c = be32toh(rdb->rdb_Cylinders);
132     d->h = be32toh(rdb->rdb_Heads);
133     d->s = be32toh(rdb->rdb_Sectors);
134     printf("[PISCSI] RDB - first partition at block %d.\n", be32toh(rdb->rdb_PartitionList));
135     d->rdb = rdb;
136     sprintf(d->rdb->rdb_DriveInitName, "pi-scsi.device");
137     return 0;
138
139 no_rdb_found:;
140     if (block)
141         free(block);
142
143     return -1;
144 }
145
146 void piscsi_map_drive(char *filename, uint8_t index) {
147     if (index > 7) {
148         printf("[PISCSI] Drive index %d out of range.\nUnable to map file %s to drive.\n", index, filename);
149         return;
150     }
151
152     int32_t tmp_fd = open(filename, O_RDWR);
153     if (tmp_fd == -1) {
154         printf("[PISCSI] Failed to open file %s, could not map drive %d.\n", filename, index);
155         return;
156     }
157
158     struct piscsi_dev *d = &devs[index];
159
160     uint64_t file_size = lseek(tmp_fd, 0, SEEK_END);
161     d->fs = file_size;
162     d->fd = tmp_fd;
163     lseek(tmp_fd, 0, SEEK_SET);
164     printf("[PISCSI] Map %d: [%s] - %llu bytes.\n", index, filename, file_size);
165
166     if (piscsi_parse_rdb(d) == -1) {
167         printf("[PISCSI] No RDB found on disk, making up some CHS values.\n");
168         d->h = 64;
169         d->s = 63;
170         d->c = (file_size / 512) / (d->s * d->h);
171     }
172     printf("[PISCSI] CHS: %d %d %d\n", d->c, d->h, d->s);
173
174     piscsi_find_partitions(d);
175     //stop_cpu_emulation(1);
176 }
177
178 void piscsi_unmap_drive(uint8_t index) {
179     if (devs[index].fd != -1) {
180         printf("[PISCSI] Unmapped drive %d.\n", index);
181         close (devs[index].fd);
182         devs[index].fd = -1;
183     }
184 }
185
186 char *io_cmd_name(int index) {
187     switch (index) {
188         case CMD_INVALID: return "INVALID";
189         case CMD_RESET: return "RESET";
190         case CMD_READ: return "READ";
191         case CMD_WRITE: return "WRITE";
192         case CMD_UPDATE: return "UPDATE";
193         case CMD_CLEAR: return "CLEAR";
194         case CMD_STOP: return "STOP";
195         case CMD_START: return "START";
196         case CMD_FLUSH: return "FLUSH";
197         case TD_MOTOR: return "TD_MOTOR";
198         case TD_SEEK: return "SEEK";
199         case TD_FORMAT: return "FORMAT";
200         case TD_REMOVE: return "REMOVE";
201         case TD_CHANGENUM: return "CHANGENUM";
202         case TD_CHANGESTATE: return "CHANGESTATE";
203         case TD_PROTSTATUS: return "PROTSTATUS";
204         case TD_RAWREAD: return "RAWREAD";
205         case TD_RAWWRITE: return "RAWWRITE";
206         case TD_GETDRIVETYPE: return "GETDRIVETYPE";
207         case TD_GETNUMTRACKS: return "GETNUMTRACKS";
208         case TD_ADDCHANGEINT: return "ADDCHANGEINT";
209         case TD_REMCHANGEINT: return "REMCHANGEINT";
210         case TD_GETGEOMETRY: return "GETGEOMETRY";
211         case TD_EJECT: return "EJECT";
212         case TD_LASTCOMM: return "LASTCOMM/READ64";
213         case TD_WRITE64: return "WRITE64";
214         case HD_SCSICMD: return "HD_SCSICMD";
215         case NSCMD_DEVICEQUERY: return "NSCMD_DEVICEQUERY";
216         case NSCMD_TD_READ64: return "NSCMD_TD_READ64";
217         case NSCMD_TD_WRITE64: return "NSCMD_TD_WRITE64";
218         case NSCMD_TD_FORMAT64: return "NSCMD_TD_FORMAT64";
219
220         default:
221             return "!!!Unhandled IO command";
222     }
223 }
224
225 char *scsi_cmd_name(int index) {
226     switch(index) {
227         case 0x00: return "TEST UNIT READY";
228         case 0x12: return "INQUIRY";
229         case 0x08: return "READ (6)";
230         case 0x0A: return "WRITE (6)";
231         case 0x28: return "READ (10)";
232         case 0x2A: return "WRITE (10)";
233         case 0x25: return "READ CAPACITY";
234         case 0x1A: return "MODE SENSE";
235         case 0x37: return "READ DEFECT DATA";
236         default:
237             return "!!!Unhandled SCSI command";
238     }
239 }
240
241 void print_piscsi_debug_message(int index) {
242     switch (index) {
243         case DBG_INIT:
244             printf("[PISCSI] Initializing devices.\n");
245             break;
246         case DBG_OPENDEV:
247             printf("[PISCSI] Opening device %d (%d). Flags: %d (%.2X)\n", piscsi_dbg[0], piscsi_dbg[1], piscsi_dbg[2], piscsi_dbg[2]);
248             break;
249         case DBG_CLEANUP:
250             printf("[PISCSI] Cleaning up.\n");
251             break;
252         case DBG_CHS:
253             printf("[PISCSI] C/H/S: %d / %d / %d\n", piscsi_dbg[0], piscsi_dbg[1], piscsi_dbg[2]);
254             break;
255         case DBG_BEGINIO:
256             printf("[PISCSI] BeginIO: io_Command: %d - io_Flags = %d - quick: %d\n", piscsi_dbg[0], piscsi_dbg[1], piscsi_dbg[2]);
257             break;
258         case DBG_ABORTIO:
259             printf("[PISCSI] AbortIO!\n");
260             break;
261         case DBG_SCSICMD:
262             printf("[PISCSI] SCSI Command %d (%s)\n", piscsi_dbg[1], scsi_cmd_name(piscsi_dbg[1]));
263             printf("Len: %d - %.2X %.2X %.2X - Command Length: %d\n", piscsi_dbg[0], piscsi_dbg[1], piscsi_dbg[2], piscsi_dbg[3], piscsi_dbg[4]);
264             break;
265         case DBG_SCSI_UNKNOWN_MODESENSE:
266             printf("SCSI: Unknown modesense %.4X\n", piscsi_dbg[0]);
267             break;
268         case DBG_SCSI_UNKNOWN_COMMAND:
269             printf("SCSI: Unknown command %.4X\n", piscsi_dbg[0]);
270             break;
271         case DBG_SCSIERR:
272             printf("SCSI: An error occured: %.4X\n", piscsi_dbg[0]);
273             break;
274         case DBG_IOCMD:
275             printf("[PISCSI] IO Command %d (%s)\n", piscsi_dbg[0], io_cmd_name(piscsi_dbg[0]));
276             break;
277         case DBG_IOCMD_UNHANDLED:
278             printf("[PISCSI] WARN: IO command %.4X (%s) is unhandled by driver.\n", piscsi_dbg[0], io_cmd_name(piscsi_dbg[0]));
279     }
280 }
281
282 void handle_piscsi_write(uint32_t addr, uint32_t val, uint8_t type) {
283     int32_t r;
284
285     struct piscsi_dev *d = &devs[piscsi_cur_drive];
286
287     uint16_t cmd = (addr & 0xFFFF);
288
289     switch (cmd) {
290         case PISCSI_CMD_READ64:
291         case PISCSI_CMD_READ:
292             d = &devs[val];
293             if (d->fd == -1) {
294                 printf ("[PISCSI] BUG: Attempted read from unmapped drive %d.\n", piscsi_cur_drive);
295                 break;
296             }
297
298             if (cmd == PISCSI_CMD_READ) {
299                 printf("[PISCSI] %d byte READ from block %d to address %.8X\n", piscsi_u32[1], piscsi_u32[0], piscsi_u32[2]);
300                 d->lba = piscsi_u32[0];
301                 lseek(d->fd, (piscsi_u32[0] * 512), SEEK_SET);
302             }
303             else {
304                 uint64_t src = piscsi_u32[3];
305                 src = (src << 32) | piscsi_u32[0];
306                 printf("[PISCSI] %d byte READ64 from block %lld to address %.8X\n", piscsi_u32[1], (src / 512), piscsi_u32[2]);
307                 d->lba = (src / 512);
308                 lseek64(d->fd, src, SEEK_SET);
309             }
310
311             r = get_mapped_item_by_address(cfg, piscsi_u32[2]);
312             if (r != -1 && cfg->map_type[r] == MAPTYPE_RAM) {
313                 printf("[PISCSI] \"DMA\" Read goes to mapped range %d.\n", r);
314                 read(d->fd, cfg->map_data[r] + piscsi_u32[2] - cfg->map_offset[r], piscsi_u32[1]);
315             }
316             else {
317                 printf("[PISCSI] No mapped range found for read.\n");
318                 uint8_t c = 0;
319                 for (uint32_t i = 0; i < piscsi_u32[1]; i++) {
320                     read(d->fd, &c, 1);
321                     write8(piscsi_u32[2] + i, (uint32_t)c);
322                 }
323             }
324             break;
325         case PISCSI_CMD_WRITE64:
326         case PISCSI_CMD_WRITE:
327             d = &devs[val];
328             if (d->fd == -1) {
329                 printf ("[PISCSI] BUG: Attempted write to unmapped drive %d.\n", piscsi_cur_drive);
330                 break;
331             }
332
333             if (cmd == PISCSI_CMD_WRITE) {
334                 printf("[PISCSI] %d byte WRITE to block %d from address %.8X\n", piscsi_u32[1], piscsi_u32[0], piscsi_u32[2]);
335                 d->lba = piscsi_u32[0];
336                 lseek(d->fd, (piscsi_u32[0] * 512), SEEK_SET);
337             }
338             else {
339                 uint64_t src = piscsi_u32[3];
340                 src = (src << 32) | piscsi_u32[0];
341                 printf("[PISCSI] %d byte WRITE64 to block %lld from address %.8X\n", piscsi_u32[1], (src / 512), piscsi_u32[2]);
342                 d->lba = (src / 512);
343                 lseek64(d->fd, src, SEEK_SET);
344             }
345
346             r = get_mapped_item_by_address(cfg, piscsi_u32[2]);
347             if (r != -1) {
348                 printf("[PISCSI] \"DMA\" Write comes from mapped range %d.\n", r);
349                 write(d->fd, cfg->map_data[r] + piscsi_u32[2] - cfg->map_offset[r], piscsi_u32[1]);
350             }
351             else {
352                 printf("[PISCSI] No mapped range found for write.\n");
353                 uint8_t c = 0;
354                 for (uint32_t i = 0; i < piscsi_u32[1]; i++) {
355                     c = read8(piscsi_u32[2] + i);
356                     write(d->fd, &c, 1);
357                 }
358             }
359             break;
360         case PISCSI_CMD_ADDR1: case PISCSI_CMD_ADDR2: case PISCSI_CMD_ADDR3: case PISCSI_CMD_ADDR4: {
361             int i = ((addr & 0xFFFF) - PISCSI_CMD_ADDR1) / 4;
362             piscsi_u32[i] = val;
363             break;
364         }
365         case PISCSI_CMD_DRVNUM:
366             if (val != 0) {
367                 if (val < 10) // Kludge for GiggleDisk
368                     piscsi_cur_drive = val;
369                 else if (val >= 10 && val % 10 != 0)
370                     piscsi_cur_drive = 255;
371                 else
372                     piscsi_cur_drive = val / 10;
373             }
374             else
375                 piscsi_cur_drive = val;
376             printf("[PISCSI] (%s) Drive number set to %d (%d)\n", op_type_names[type], piscsi_cur_drive, val);
377             break;
378         case PISCSI_CMD_DEBUGME:
379             printf("[PISCSI] DebugMe triggered (%d).\n", val);
380             stop_cpu_emulation(1);
381             break;
382         case PISCSI_CMD_DRIVER: {
383             printf("[PISCSI] Driver copy/patch called, destination address %.8X.\n", val);
384             int r = get_mapped_item_by_address(cfg, val);
385             if (r != -1) {
386                 uint32_t addr = val - cfg->map_offset[r];
387                 uint8_t *dst_data = cfg->map_data[r];
388                 memcpy(dst_data + addr, piscsi_rom_ptr + 0x400, 0x3C00);
389
390                 piscsi_hinfo.base_offset = val;
391                 
392                 reloc_hunks(piscsi_hreloc, dst_data + addr, &piscsi_hinfo);
393                 stop_cpu_emulation(1);
394             }
395             else {
396                 for (int i = 0; i < 0x3C00; i++) {
397                     uint8_t src = piscsi_rom_ptr[0x400 + i];
398                     write8(addr + i, src);
399                 }
400             }
401             break;
402         }
403         case PISCSI_DBG_VAL1: case PISCSI_DBG_VAL2: case PISCSI_DBG_VAL3: case PISCSI_DBG_VAL4:
404         case PISCSI_DBG_VAL5: case PISCSI_DBG_VAL6: case PISCSI_DBG_VAL7: case PISCSI_DBG_VAL8: {
405             int i = ((addr & 0xFFFF) - PISCSI_DBG_VAL1) / 4;
406             piscsi_dbg[i] = val;
407             break;
408         }
409         case PISCSI_DBG_MSG:
410             print_piscsi_debug_message(val);
411             break;
412         default:
413             printf("[PISCSI] WARN: Unhandled %s register write to %.8X: %d\n", op_type_names[type], addr, val);
414             break;
415     }
416 }
417
418 #define PIB 0x00
419
420 uint32_t handle_piscsi_read(uint32_t addr, uint8_t type) {
421     if (type) {}
422
423     if ((addr & 0xFFFF) >= PISCSI_CMD_ROM) {
424         uint32_t romoffs = (addr & 0xFFFF) - PISCSI_CMD_ROM;
425         if (romoffs < (piscsi_rom_size + PIB)) {
426             //printf("[PISCSI] %s read from Boot ROM @$%.4X (%.8X): ", op_type_names[type], romoffs, addr);
427             uint32_t v = 0;
428             switch (type) {
429                 case OP_TYPE_BYTE:
430                     v = piscsi_rom_ptr[romoffs - PIB];
431                     //printf("%.2X\n", v);
432                     break;
433                 case OP_TYPE_WORD:
434                     v = be16toh(*((uint16_t *)&piscsi_rom_ptr[romoffs - PIB]));
435                     //printf("%.4X\n", v);
436                     break;
437                 case OP_TYPE_LONGWORD:
438                     v = be32toh(*((uint32_t *)&piscsi_rom_ptr[romoffs - PIB]));
439                     //printf("%.8X\n", v);
440                     break;
441             }
442             return v;
443         }
444         return 0;
445     }
446     
447     switch (addr & 0xFFFF) {
448         case PISCSI_CMD_DRVTYPE:
449             if (devs[piscsi_cur_drive].fd == -1) {
450                 printf("[PISCSI] %s Read from DRVTYPE %d, drive not attached.\n", op_type_names[type], piscsi_cur_drive);
451                 return 0;
452             }
453             printf("[PISCSI] %s Read from DRVTYPE %d, drive attached.\n", op_type_names[type], piscsi_cur_drive);
454             return 1;
455             break;
456         case PISCSI_CMD_DRVNUM:
457             return piscsi_cur_drive;
458             break;
459         case PISCSI_CMD_CYLS:
460             printf("[PISCSI] %s Read from CYLS %d: %d\n", op_type_names[type], piscsi_cur_drive, devs[piscsi_cur_drive].c);
461             return devs[piscsi_cur_drive].c;
462             break;
463         case PISCSI_CMD_HEADS:
464             printf("[PISCSI] %s Read from HEADS %d: %d\n", op_type_names[type], piscsi_cur_drive, devs[piscsi_cur_drive].h);
465             return devs[piscsi_cur_drive].h;
466             break;
467         case PISCSI_CMD_SECS:
468             printf("[PISCSI] %s Read from SECS %d: %d\n", op_type_names[type], piscsi_cur_drive, devs[piscsi_cur_drive].s);
469             return devs[piscsi_cur_drive].s;
470             break;
471         case PISCSI_CMD_BLOCKS: {
472             uint32_t blox = devs[piscsi_cur_drive].fs / 512;
473             printf("[PISCSI] %s Read from BLOCKS %d: %d\n", op_type_names[type], piscsi_cur_drive, (uint32_t)(devs[piscsi_cur_drive].fs / 512));
474             printf("fs: %lld (%d)\n", devs[piscsi_cur_drive].fs, blox);
475             return blox;
476             break;
477         }
478         default:
479             printf("[PISCSI] Unhandled %s register read from %.8X\n", op_type_names[type], addr);
480             break;
481     }
482
483     return 0;
484 }