-
Notifications
You must be signed in to change notification settings - Fork 20
/
cpm.5
320 lines (320 loc) · 10.3 KB
/
cpm.5
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
.\" Believe it or not, reportedly there are nroffs which do not know \(en
.if n .ds en -
.if t .ds en \(en
.TH CPM 5 "Jan 23, 2019" "CP/M tools" "File formats"
.SH NAME \"{{{roff}}}\"{{{
cpm \- CP/M disk and file system format
.\"}}}
.SH DESCRIPTION \"{{{
.SS "Format descrptions" \"{{{
CP/M format may be specified by either the format name in a
diskdefs file, or by including the entire "diskdef" format.
For example:
.RS
.sp
-f name
.br
-f `cat mydiskdef`
.br
-f "diskdef; seclen 512; tracks 512; ... end"
.sp
.RE
A single diskdef must not begin with a comment, in other words it must
begin with "diskdef". The name is not required.
.\"}}}
.SS "Characteristic sizes" \"{{{
Each CP/M disk format is described by the following specific sizes:
.RS
.sp
Sector size in bytes
.br
Number of tracks
.br
Number of sectors
.br
Block size
.br
Number of directory entries
.br
Logical sector skew
.br
Number of reserved system tracks (optional)
.br
Offset to start of volume (optional and not covered by operating system,
but disk driver specific)
.sp
.RE
A block is the smallest allocatable storage unit. CP/M supports block
sizes of 1024, 2048, 4096, 8192 and 16384 bytes. Unfortunately, this
format specification is not stored on the disk and there are lots of
formats. Accessing a block is performed by accessing its sectors, which
are stored with the given software skew. \fBcpmtools\fP always counts
sectors starting with 0, as it deals with logical sectors. CP/M uses physical
sectors in the skew table, which often start with 1.
.\"}}}
.SS "Device areas" \"{{{
A CP/M disk contains four areas:
.RS
.sp
Volume offset (optional and not covered by operating system, but disk driver specific)
.br
System tracks (optional)
.br
Directory
.br
Data
.sp
.RE
The system tracks store the boot loader and CP/M itself. In order to save
disk space, there are non-bootable formats which omit those system tracks.
The term \fIdisk capacity\fP always excludes the space for system tracks.
Note that there is no bitmap or list for free blocks. When accessing a
drive for the first time, CP/M builds this bitmap in core from the directory.
.LP
A hard disk can have the additional notion of a \fIvolume offset\fP to
locate the start of the drive image (which may or may not have system
tracks associated with it). The base unit for volume offset is byte
count from the beginning of the physical disk, but specifiers of
\fIK\fP, \fIM\fP, \fIT\fP or \fIS\fP may be appended to denote
kilobytes, megabytes, tracks or sectors. If provided, a specifier
must immediately follow the numeric value with no whitespace. For
convenience upper and lower case are both accepted and only the first
letter is significant, thus 2KB, 8MB, 1000trk and 16sec are valid
values. The \fBoffset\fP must appear subsequent to track, sector and sector
length values for the sector and track units to work.
.\"}}}
.SS "Directory entries" \"{{{
The directory is a sequence of directory entries (also called extents),
which contain 32 bytes of the following structure:
.RS
.sp
.ta 3n 6n 9n 12n 15n 18n 21n 24n 27n 30n 33n 36n 39n 42n 45n
St F0 F1 F2 F3 F4 F5 F6 F7 E0 E1 E2 Xl Bc Xh Rc
.br
Al Al Al Al Al Al Al Al Al Al Al Al Al Al Al Al
.sp
.RE
.\"{{{ St = status
\fBSt\fP is the status; possible values are:
.RS
.sp
0\*(en15: used for file, status is the user number
.br
16\*(en31: used for file, status is the user number (P2DOS)
or used for password extent (CP/M 3 or higher)
.br
32: disc label
.br
33: time stamp (P2DOS)
.br
0xE5: unused
.sp
.RE
.\"}}}
.LP
.\"{{{ F0-E2 = file name and extension
\fBF0\*(enE2\fP are the file name and its extension. They may consist of
any printable 7 bit ASCII character but: \fB< > . , ; : = ? * [ ]\fP.
The file name must not be empty, the extension may be empty. Both are
padded with blanks. The highest bit of each character of the file name
and extension is used as attribute. The attributes have the following
meaning:
.RS
.sp
F0: requires set wheel byte (Backgrounder II)
.br
F1: public file (P2DOS, ZSDOS), forground-only command (Backgrounder II)
.br
F2: date stamp (ZSDOS), background-only commands (Backgrounder II)
.br
F7: wheel protect (ZSDOS)
.br
E0: read-only
.br
E1: system file
.br
E2: archived
.sp
.RE
Public files (visible under each user number) are not supported by CP/M
2.2, but there is a patch and some free CP/M clones support them without
any patches.
.LP
The wheel byte is (by default) the memory location at 0x4b. If it is
zero, only non-privileged commands may be executed.
.\"}}}
.LP
.\"{{{ Xl, Xh = extent number
\fBXl\fP and \fBXh\fP store the extent number. A file may use more than
one directory entry, if it contains more blocks than an extent can hold.
In this case, more extents are allocated and each of them is numbered
sequentially with an extent number. If a physical extent stores more than
16k, it is considered to contain multiple logical extents, each pointing
to 16k data, and the extent number of the last used logical extent
is stored. Note: Some formats decided to always store only one logical
extent in a physical extent, thus wasting extent space. CP/M 2.2 allows
512 extents per file, CP/M 3 and higher allow up to 2048. Bit 5\*(en7 of
Xl are 0, bit 0\*(en4 store the lower bits of the extent number. Bit 6
and 7 of Xh are 0, bit 0\*(en5 store the higher bits of the extent number.
.\"}}}
.LP
.\"{{{ Rc, Bc = record count, byte count
\fBRc\fP and \fBBc\fP determine the length of the data used by this extent. The
physical extent is divided into logical extents, each of them being 16k
in size (a physical extent must hold at least one logical extent, e.g. a
blocksize of 1024 byte with two-byte block pointers is not allowed).
Rc stores the number of 128 byte records of the last used logical extent.
Bc stores the number of bytes in the last used record. The value 0 means
128 for backward compatibility with CP/M 2.2, which did not support Bc.
ISX records the number of unused instead of used bytes in Bc.
This only applies to files with allocated blocks. For an empty file, no
block is allocated and Bc 0 has no meaning.
.\"}}}
.LP
.\"{{{ Al = allocated blocks
\fBAl\fP stores block pointers. If the disk capacity minus boot
tracks but including the directory area is less than 256 blocks, Al
is interpreted as 16 byte-values, otherwise as 8 double-byte-values.
Since the directory area is not subtracted, the directory area starts
with block 0 and files can never allocate block 0, which is why this
value can be given a new meaning: A block pointer of 0 marks a hole in
the file. If a hole covers the range of a full extent, the extent will
not be allocated. In particular, the first extent of a file does not
neccessarily have extent number 0. A file may not share blocks with other
files, as its blocks would be freed if the other files is erased without
a following disk system reset. CP/M returns EOF when it reaches a hole,
whereas UNIX returns zero-value bytes, which makes holes invisible.
.\"}}}
.\"}}}
.SS "Native time stamps" \"{{{
P2DOS and CP/M Plus support time stamps, which are stored in each fourth
directory entry. This entry contains the time stamps for
the extents using the previous three directory entries. Note that you
really have time stamps for each extent, no matter if it is the first
extent of a file or not. The structure of time stamp entries is:
.RS
.sp
1 byte status 0x21
.br
8 bytes time stamp for third-last directory entry
.br
2 bytes unused
.br
8 bytes time stamp for second-last directory entry
.br
2 bytes unused
.br
8 bytes time stamp for last directory entry
.sp
.RE
A time stamp consists of two dates: Creation and modification date (the
latter being recorded when the file is closed). CP/M Plus further
allows optionally to record the access instead of creation date as first
time stamp.
.RS
.sp
2 bytes (little-endian) days starting with 1 at 01-01-1978
.br
1 byte hour in BCD format
.br
1 byte minute in BCD format
.sp
.RE
All time stamps are stored in local time.
.\"}}}
.SS "DateStamper time stamps" \"{{{
The DateStamper software added functions to the BDOS to manage
time stamps by allocating a read only file with the name "!!!TIME&.DAT"
in the very first directory entry, covering the very first data
blocks. It contains one entry per directory entry with the
following structure of 16 bytes:
.RS
.sp
5 bytes create datefield
.br
5 bytes access datefield
.br
5 bytes modify datefield
.br
1 byte magic number/checksum
.sp
.RE
The magic number is used for the first 7 entries of each 128-byte record
and contains the characters \fB!\fP, \fB!\fP, \fB!\fP, \fBT\fP, \fBI\fP,
\fBM\fP and \fBE\fP. The checksum is used on every 8th entry (last entry
in 128-byte record) and is the sum of the first 127 bytes of the record.
Each datefield has this structure:
.RS
.sp
1 byte BCD coded year (no century, so it is sane assuming any year < 70
means 21st century)
.br
1 byte BCD coded month
.br
1 byte BCD coded day
.br
1 byte BCD coded hour or, if the high bit is set, the high byte of a
counter for systems without real time clock
.br
1 byte BCD coded minute, or the low byte of the counter
.sp
.DE
.\"}}}
.SS "Disc labels" \"{{{
CP/M Plus support disc labels, which are stored in an arbitrary directory
entry.
The structure of disc labels is:
.RS
.sp
1 byte status 0x20
.br
\fBF0\*(enE2\fP are the disc label
.br
1 byte mode: bit 7 activates password protection, bit 6 causes time stamps on
access, but 5 causes time stamps on modifications, bit 4 causes time stamps on
creation and bit 0 is set when a label exists. Bit 4 and 6 are exclusively set.
.br
1 byte password decode byte: To decode the password, xor this byte with the password
bytes in reverse order. To encode a password, add its characters to get the
decode byte.
.br
2 reserved bytes
.br
8 password bytes
.br
4 bytes label creation time stamp
.br
4 bytes label modification time stamp
.sp
.RE
.\"}}}
.SS "Passwords" \"{{{
CP/M Plus supports passwords, which are stored in an arbitrary directory
entry.
The structure of these entries is:
.RS
.sp
1 byte status (user number plus 16)
.br
\fBF0\*(enE2\fP are the file name and its extension.
.br
1 byte password mode: bit 7 means password required for reading, bit 6 for writing
and bit 5 for deleting.
.br
1 byte password decode byte: To decode the password, xor this byte with the password
bytes in reverse order. To encode a password, add its characters to get the
decode byte.
.br
2 reserved bytes
.br
8 password bytes
.sp
.RE
.\"}}}
.\"}}}
.SH "SEE ALSO" \"{{{
.IR mkfs.cpm (1),
.IR fsck.cpm (1),
.IR fsed.cpm (1),
.IR cpmls (1)
.\"}}}