xref: /haiku/src/tools/fixup_next_boot_floppy/fixup_next_boot_floppy.c (revision ab51e305e9038ecf754050be0f78016b4ff389a8)
1 /*
2  * Copyright 2020, François Revol, revol@free.fr.
3  * Distributed under the terms of the MIT License.
4  */
5 
6 #include <fcntl.h>
7 #include <stddef.h>
8 #include <stdio.h>
9 #include <stdint.h>
10 #include <unistd.h>
11 #include <arpa/inet.h>
12 
13 #include <disklabel.h>
14 
15 /* for now we actually write all of the disk label here. */
16 
17 #define DL_SIZE (offsetof(struct disk_label, dl_un.DL_v3_checksum) \
18 	+ sizeof(uint16_t))
19 #define SUM_CNT (offsetof(struct disk_label, dl_un.DL_v3_checksum) \
20 	/ sizeof(uint16_t))
21 
22 #define H2B32 htonl
23 #define H2B16 htons
24 #define B2H16 ntohs
25 
26 
27 // see https://unix.superglobalmegacorp.com/darwin01/newsrc/machdep/i386/checksum_16.c.html
checksum_16(uint16_t * p,int count)28 static uint16_t checksum_16(uint16_t *p, int count)
29 {
30 	uint32_t sum = 0;
31 	for (;count--;)
32 		sum += B2H16(*p++);
33 	// sum both shorts
34 	sum = (sum & 0x0ffff) + (sum >> 16);
35 	if (sum > 65535)
36 		sum -= 65535;
37 	return sum;
38 }
39 
40 
main(int argc,char ** argv)41 int main(int argc, char **argv)
42 {
43 	int fd;
44 	uint16_t sum;
45 	int labelOffsets[] = { 0, 15, 30, 45 };
46 	// HACK: for now we force a single label plus the bootlock at 8kb
47 	// (min offset the ROM allows) to fit before the tgz
48 	int numLabels = 1; // sizeof(labelOffsets) / sizeof(int);
49 	uint32_t bootBlockStart = 0x8; // usually 0x20
50 
51 	struct disk_label disklabel = {
52 		H2B32(DL_V3),
53 		H2B32(0),
54 		H2B32(0),
55 		"HaikuBoot",//"NextBoot",
56 		H2B32(0),
57 		// dl_tag, we use 'HAIK'
58 		H2B32(0x4841494b), // H2B32(0xa991637a),
59 		"Sony MPX-111N 2880-512", // same as NS image, not sure it matters
60 		"removable_rw_floppy",
61 		H2B32(1024), // !! 1024 bytes / sector !!
62 		H2B32(2),
63 		H2B32(9),
64 		H2B32(80),
65 		H2B32(300),
66 		H2B16(96),
67 		H2B16(0),
68 		H2B16(0),
69 		H2B16(0),
70 		H2B16(0),
71 		H2B16(0),
72 		// boot blocks in 1024 bytes sectors
73 		H2B32(bootBlockStart),H2B32(0xffffffff),
74 		"haiku_loader", // "fdmach"
75 		"schredder", // "silly"
76 		'a', 'b',
77 		// partitions
78 		{
79 			// Nextstep uses this:
80 			//{ H2B32(0), H2B32(0x540), H2B16(0x2000), H2B16(0x400), 't',
81 			//	H2B16(0x20), H2B16(0x800), 0, 1, "", 1, "4.3BSD"},
82 			// XXX: should we fake an fs anyway?
83 			{ H2B32(-1), H2B32(-1), H2B16(-1), H2B16(-1), 0,
84 				H2B16(-1), H2B16(-1), -1, 0, "", 0, ""},
85 			{ H2B32(-1), H2B32(-1), H2B16(-1), H2B16(-1), 0,
86 				H2B16(-1), H2B16(-1), -1, 0, "", 0, ""},
87 			{ H2B32(-1), H2B32(-1), H2B16(-1), H2B16(-1), 0,
88 				H2B16(-1), H2B16(-1), -1, 0, "", 0, ""},
89 			{ H2B32(-1), H2B32(-1), H2B16(-1), H2B16(-1), 0,
90 				H2B16(-1), H2B16(-1), -1, 0, "", 0, ""},
91 			{ H2B32(-1), H2B32(-1), H2B16(-1), H2B16(-1), 0,
92 				H2B16(-1), H2B16(-1), -1, 0, "", 0, ""},
93 			{ H2B32(-1), H2B32(-1), H2B16(-1), H2B16(-1), 0,
94 				H2B16(-1), H2B16(-1), -1, 0, "", 0, ""},
95 			{ H2B32(-1), H2B32(-1), H2B16(-1), H2B16(-1), 0,
96 				H2B16(-1), H2B16(-1), -1, 0, "", 0, ""},
97 			{ H2B32(-1), H2B32(-1), H2B16(-1), H2B16(-1), 0,
98 				H2B16(-1), H2B16(-1), -1, 0, "", 0, ""}
99 		},
100 		{ 0 },
101 		0
102 	};
103 	fd = open(argv[1], O_RDWR);
104 	if (fd < 0) {
105 		perror("open");
106 		return 1;
107 	}
108 	//XXX: support simple checksum of existing label?
109 #if 0
110 	if (read(fd, bootblock, DL_SIZE) < DL_SIZE) {
111 		perror("read");
112 		return 1;
113 	}
114 #endif
115 
116 	// TODO: take boot block offsets as arg?
117 
118 	sum = checksum_16((uint16_t *)&disklabel, SUM_CNT);
119 	fprintf(stderr, "checksum: 0x%04x\n", sum);
120 	disklabel.dl_un.DL_v3_checksum = H2B16(sum);
121 
122 	for (unsigned int i = 0; i < numLabels; i++) {
123 		/* also write copies elsewhere, note we don't update the checksum */
124 		disklabel.dl_label_blkno = H2B32(labelOffsets[i]);
125 		/* oddly this field seems to use 512 bytes sectors */
126 		lseek(fd, labelOffsets[i] * 0x200LL, SEEK_SET);
127 		write(fd, &disklabel, DL_SIZE);
128 	}
129 
130 	// TODO: patch the bootblock text segment to include the tgz
131 
132 	return 0;
133 }
134