1/*
2 * Copyright (C) 2020 Adrien Destugues <pulkomandy@pulkomandy.tk>
3 *
4 * Distributed under terms of the MIT license.
5 */
6
7
8#ifdef _BOOT_MODE
9#	include <boot/partitions.h>
10#else
11#	include <DiskDeviceTypes.h>
12#endif
13
14#include <ByteOrder.h>
15#include <ddm_modules.h>
16#include <util/kernel_cpp.h>
17#include <KernelExport.h>
18#include <stdint.h>
19#include <string.h>
20
21
22//#define TRACE_SUN_PARTITION
23#ifdef TRACE_SUN_PARTITION
24#	define TRACE(x) dprintf x
25#else
26#	define TRACE(x) ;
27#endif
28
29#define SUN_PARTITION_MODULE_NAME "partitioning_systems/sun/v1"
30#define SUN_PARTITION_NAME "Sun volume table of contents"
31
32
33static uint16_t kMainSignature = 0xDABE;
34static uint32_t kVtocSignature = 0x600DDEEE;
35static uint32_t kVtocVersion = 1;
36static off_t kSectorSize = 512;
37
38
39struct sun_vtoc {
40	char diskName[128];
41	struct {
42		uint32_t version;
43		char volumeName[8];
44		uint16_t partitionCount;
45		struct {
46			uint16_t type;
47			uint16_t flags;
48		} partitions[8];
49		uint8_t bootinfo[12];
50		uint8_t reserved[2];
51		uint32_t signature;
52		uint8_t reserved2[38];
53		uint32_t timestamp[8];
54	} __attribute__((packed)) vtoc;
55	uint16_t write_skip;
56	uint16_t read_skip;
57	uint8_t reserved[154];
58	uint16_t diskSpeed;
59	uint16_t cylinders;
60	uint16_t alternates;
61	uint8_t reserved2[4];
62	uint16_t interleave;
63	uint16_t dataCylinders;
64	uint16_t alternateCylinders;
65	uint16_t heads;
66	uint16_t sectorsPerTrack;
67	uint8_t reserved3[4];
68	struct {
69		uint32_t startCylinder;
70		uint32_t sectorCount;
71	} partitions[8];
72	uint16_t signature;
73	uint16_t checksum;
74} __attribute__((packed));
75
76
77//	#pragma mark -
78//	Sun VTOC public module interface
79
80
81static status_t
82sun_std_ops(int32 op, ...)
83{
84	switch (op) {
85		case B_MODULE_INIT:
86		case B_MODULE_UNINIT:
87			return B_OK;
88	}
89
90	return B_ERROR;
91}
92
93
94static float
95sun_identify_partition(int fd, partition_data *partition, void **_cookie)
96{
97	uint8 buffer[512];
98	ssize_t bytesRead = read_pos(fd, 0, buffer, sizeof(buffer));
99	sun_vtoc *vtoc = (sun_vtoc *)buffer;
100	if (bytesRead < (ssize_t)sizeof(buffer)) {
101		TRACE(("%s: read error: %ld\n", __FUNCTION__, bytesRead));
102		return B_ERROR;
103	}
104
105	if (vtoc->signature == B_HOST_TO_BENDIAN_INT16(kMainSignature)
106		&& vtoc->vtoc.signature == B_HOST_TO_BENDIAN_INT32(kVtocSignature)
107		&& vtoc->vtoc.version == B_HOST_TO_BENDIAN_INT32(kVtocVersion)) {
108		// TODO verify the checksum
109
110		uint16_t partitionCount
111			= B_BENDIAN_TO_HOST_INT16(vtoc->vtoc.partitionCount);
112		TRACE(("Found %d partitions\n", partitionCount));
113
114		if (partitionCount > 8)
115			return B_ERROR;
116
117		vtoc = new sun_vtoc();
118		memcpy(vtoc, buffer, sizeof(sun_vtoc));
119		*_cookie = (void *)vtoc;
120
121		bool hasParent = (get_parent_partition(partition->id) != NULL);
122		if (!hasParent)
123			return 0.61; // Larger than iso9660
124		else
125			return 0.3;
126	}
127
128	return B_ERROR;
129}
130
131
132static status_t
133sun_scan_partition(int fd, partition_data *partition, void *cookie)
134{
135	sun_vtoc *vtoc = (sun_vtoc *)cookie;
136
137	partition->status = B_PARTITION_VALID;
138	partition->flags |= B_PARTITION_PARTITIONING_SYSTEM
139						| B_PARTITION_READ_ONLY;
140	partition->content_size = partition->size;
141
142	off_t headCount = B_BENDIAN_TO_HOST_INT16(vtoc->heads);
143	off_t sectorsPerTrack = B_BENDIAN_TO_HOST_INT16(vtoc->sectorsPerTrack);
144	off_t cylinderSize = kSectorSize * headCount * sectorsPerTrack;
145
146	TRACE(("%" B_PRIdOFF " heads, %" B_PRIdOFF " sectors, cylindersize %"
147		B_PRIdOFF "\n", headCount, sectorsPerTrack, cylinderSize));
148
149	for (int i = 0; i < B_BENDIAN_TO_HOST_INT16(vtoc->vtoc.partitionCount);
150		i++) {
151		uint16_t type = B_BENDIAN_TO_HOST_INT16(vtoc->vtoc.partitions[i].type);
152		// Ignore unused and "whole disk" entries
153		if (type == 0 || type == 5)
154			continue;
155
156		off_t start = B_BENDIAN_TO_HOST_INT32(
157			vtoc->partitions[i].startCylinder) * cylinderSize;
158		off_t size = B_BENDIAN_TO_HOST_INT32(vtoc->partitions[i].sectorCount)
159			* kSectorSize;
160		TRACE(("Part %d type %d start %" B_PRIdOFF " size %" B_PRIdOFF "\n", i,
161			type, start, size));
162		partition_data *child = create_child_partition(partition->id, i,
163			start, size, -1);
164		if (child == NULL) {
165			TRACE(("sun: Creating child at index %d failed\n", i));
166			return B_ERROR;
167		}
168		child->block_size = partition->block_size;
169	}
170
171	return B_OK;
172}
173
174
175static void
176sun_free_identify_partition_cookie(partition_data *partition, void *_cookie)
177{
178	delete (sun_vtoc *)_cookie;
179}
180
181
182#ifndef _BOOT_MODE
183static partition_module_info sSunPartitionModule = {
184#else
185partition_module_info gSunPartitionModule = {
186#endif
187	{
188		SUN_PARTITION_MODULE_NAME,
189		0,
190		sun_std_ops
191	},
192	"sun",							// short_name
193	SUN_PARTITION_NAME,				// pretty_name
194	0,									// flags
195
196	// scanning
197	sun_identify_partition,		// identify_partition
198	sun_scan_partition,			// scan_partition
199	sun_free_identify_partition_cookie,	// free_identify_partition_cookie
200	NULL,
201//	atari_free_partition_content_cookie,	// free_partition_content_cookie
202};
203
204#ifndef _BOOT_MODE
205partition_module_info *modules[] = {
206	&sSunPartitionModule,
207	NULL
208};
209#endif
210