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
28static 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
41int 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