See also: part 1, part 2 and part 3.
- 2016/04/26 – I had a HUGE mistake in STEP 5 about what to put in LSN0 for the os9boot file size. (It’s sectors, not bytes – oops!) Thanks to Travis Poppe for helping me figure out what was wrong in my instructions. I have marked the updates in red. I will do some testing soon to make sure it is correct now.
- 2016/05/01 – A minor correction to the instructions, and I added links to DSK images of the BASIC and OS-9 programs in this article, as well as a link to the full 128MB NitrOS-9 image, ready for you to start customizing.
- 2017/02/05 – Well, this is confusing. Ignore my first correction. LSN 0 needs file size in bytes, not sectors. Correcting again.
As promised in Part 1, and teased in Part 2, I finally present some simple steps to making a bootable OS-9 disk without using “cobbler” or “os9gen”. If I had understood this more back in the early 90s when I was using CoCo OS-9 Level 2 full-time, I don’t think I would have seen nearly as many BOOT FAILED messages :)
Step 0 – Creating a 128MB disk image.
This doesn’t have anything to do with the rest of the article, but it’s good to know. CoCoSDC creates disk images, by default as 35-track single sided images. As you write data past the end of those 35 tracks, the image expands. This can lead to fragmentation and performance issues as the CoCoSDC firmware has to juggle more bits and bytes. Instead, designer Darren Atkinson sent me a simple BASIC program that will create a .DSK image and expand it automatically to the size (in megabytes) you specify. I called mine SDCMAKE.DSK (download the SDCMAKE.DSK disk image here).
10 INPUT "DSK NAME";DN$
20 DRIVE 1,DN$,NEW
30 INPUT"SIZE MB";MB:IF MB>128 THEN 30
40 A=&HFF48:SC=INT(MB*4096)-1
50 B1=INT(SC/65536):B2=INT((SC-B1*65536)/256):B3=SC-B1*65536-B2*256
60 POKE &HFF40,67:POKE A+1,B1:POKE A+2,B2
70 POKE A+3,B3:POKE A,&HA1:POKE A+2,0
80 IF (PEEK(A) AND 2)=0 THEN 80
90 FOR I=1 TO 128:POKE A+3,0:NEXT
100 IF PEEK(A) AND 1 THEN 100
110 POKE &HFF40,0
You can run that from BASIC and make a fresh “128MB.DSK” file to experiment on under OS-9.
Step 1 – Format the hard drive for the 128MB.
To do this, we must configure the /sd1 device descriptor so it provides 524,280 clusters – the most we can have (65535 bytes in the DAM, multiplied by 8 bits per = 524280). I use 65535 ($FFFF) cylinders, 8 sides, and 1 sector-per-track which works out to 524280 exactly.
dmode /sd1 cyl=ffff sid=8 sct=1 t0s=1
format /sd1
NOTE: There may be more values that need to be set. I tried this tonight (2/5/2017) on an old SyQuest EZ135 SCSI drive (128MB as well) and format showed some real weird stuff. I think there were some other options in my SCSI descriptor (clusters, etc.) that I needed to override.
Format should report “Disk capacity: 524280 sectors (134,215,680 bytes)” and you should see “Sectors/track” and “Track zero sect/trk” both at 1 (sct and t0s in the dmode command), and “Total physical cylinders” at 65,535 (cyl in the dmode command). Do not to a PHYSICAL format, and there is no need to Verify unless you just have some time to kill.
Format Note: During the research for this article, I realized that not only is cobbler and os9gen broken in regards to hard drive images, but it appears format is as well. There is a byte in LSN 0 that indicates the type/format (DD.FMT) of the disk. It has bits that are associated with various floppy disk formats, with one representing single-sided or double-sided. It appears that, by default, format will set that side bit if sides > 1. By formatting a hard drive like I suggested (with sid=8), the double-sided bit will be set, and that throws off cobbler and os9gen. If you format using the “1” option, for singled sided, it will NOT set that bit (thus, single-sided) BUT it will override the sid=8 settings (or whatever is in the descriptor). What we really need are versions of these commands that have a “it’s a HARD DRIVE, darnit!” option that will not set those floppy drive bits. I expect this was done long ago when hard drives started getting affordable, but reinventing the wheel is fun so maybe that will be another article…
Step 2 – Copy the kernel track from a bootable disk on sectors $264-$275 to sectors $264-$275 on /sd1.
I did this using a brute-force BASIC09 program: (Download the KERCOPY.DSK disk image here.)
PROCEDURE kercopy
DIM in,out:BYTE
DIM srcDev,dstDev:STRING
DIM sectorNum:REAL
DIM sectorData(256):BYTE
INPUT "Source drive with kernel:",srcDev
INPUT "Destination drive :",dstDev
OPEN #in,srcDev+"@":READ
OPEN #out,dstDev+"@":UPDATE
FOR sectorNum=$0264 TO $0275
PRINT "Copying sector "; sectorNum; " from "; srcDev; " to "; dstDev
; "..."
SEEK #in,sectorNum*256
GET #in,sectorData
SEEK #out,sectorNum*256
PUT #out,sectorData
NEXT sectorNum
CLOSE #out
CLOSE #in
END
Please note that this program does no error checking. When you run it, you would type in “/sd0” for the source disk (if that is the one with your kernel boot track) and “/sd1” for the destination. It will then simply read all the boot track sectors from /sd0 and write them to the same place on /sd1.
Given a bit more time, I need to make that program take care of this next step so it does not have to be done manually… At that point, it would be a nice replacement for cobbler, almost.
Step 3 – Mark sectors $264-$275 as used to prevent files from overwriting the “hidden” kernel track.
I use dEd to edit the hard drive in raw mode (/sd1@) and then just find the 18 appropriate bits in the DAM (disk allocation bitmap) that represent the 18 sectors of the kernel track and set them.
The boot track is located on sectors $264-$275 in the DAM (disk allocation bitmap). The DAM starts at LSN 1. You basically want to set the 18 bits that represent sectors $264-$275. They reside in bytes $14C, $14D and $1FE:
- offset $14C = $0F (00001111)
- offset $14D = $FF (11111111)
- offset $14E = $FC (11111100)
ded /sd1@
CMD: s 1 [ENTER] (skip to LSN=$01 one)
CMD: e (edit mode)
Cursor over to row 04, column C and change that to $0F
Cursor over to row 04, column D and change that to $FF
Cursor over to row 04, column E and change that to $FC
[ENTER] to exit edit mode
CMD: w (to write sector)
Are you sure? y (yes, you are sure)
Step 4 – Copy your OS9Boot file over to /sd1. If this disk is freshly formatted, it should copy as a contiguous (non-fragmented) file.
copy /sd0/OS9Boot /sd1/OS9Boot
Step 5 – Mark the location and size of the bootfile in logical sector 0. This is how the booter knows where to find OS9Boot.
To do this, I do a “dir -e /sd1” and note the “Sector” and “Bytecount” (size) fields. In my example, dir reports OS9Boot is at Sector 109 and has a Bytecount (size) of $5EDD. The sector reported is NOT the one we want to use. That sector is where the File ID sector is for OS9Boot. File ID is what contains the attributes, owner, creation date, etc. as well as the segment list. For a fragmented file, the File ID sector may contain up to 48 entries of different file segments.
Using “ded /sd1@” again, first we want to verify where OS9Boot is. Open dEd, and skip to the sector that was shown in the “dir -e /sd1” output:
ded /sd1@
s 109 [ENTER] (skip to sector shown in the dir -e display)
That sector should have some data on the first row (00), and a few entries on the second row (10). The second row is what we really want. The first three bytes (offsets $10-$12) are the starting sector for the segment (where OS9Boot really begins), and the next two bytes (offsets $13-$14) are the size in sectors.
On a freshly formatted disk, the starting sector should be one higher than what “dir -e” showed. On my system, it is “00 01 0A” ($10A is the sector after the directory entry at $109).
Just to make sure you have the correct starting sector, in dEd you can skip to that sector (“s 10a [ENTER]”) to look at it and see if it is the kernel. On the top line of the ASCII display on the right you should see the module name embedded in there. In this case, “KrnP2”. That confirms sector $10A is indeed the kernel.
From the NitrOS-9 Technical Reference manual “Identification Sector (LSN 0)” on page 57:
Name Rel. Size Use
Addr (Bytes)
DD.TOT $00 3 Number of sectors on disk
DD.TKS $03 1 Track size (in sectors)
DD.MAP $04 2 Number of bytes in the allocation bit map
DD.BIT $06 2 Number of sectors per cluster
DD.DIR $08 3 Starting sector of the root directory
DD.OWN $0B 2 Owner’s user number
DD.ATT $0D 1 Disk attributes
DD.DSK $0E 2 Disk identification (for internal use)
DD.FMT $10 1 Disk format, density, number of sides
DD.SPT $11 2 Number of sectors per track
DD.RES $13 2 Reserved for future use
DD.BT $15 3 Starting sector of the bootstrap file
DD.BSZ $18 2 Size of the bootstrap file (in bytes)
DD.DAT $1A 5 Time of creation (Y:M:D:H:M)
DD.NAM $1F 32 Volume name in which the last character has the most significant bit set
DD.OPT $3F Path descriptor options
We will want to put the starting sector (that we got from dEd) as three bytes at offset $15 of LSN 0. We will want to put the byte count (that we got from dir) as two bytes at offset $18 of LSN0.
Now just skip back to LSN 0 and type in the starting sector for the OS9Boot module and it’s size. These go at offset $15-$17 (starting sector) and $18-19 (size in bytes). Basically, you want to edit $15-$19 to be the three bytes that were at $10-$12 in the files’ ID sector, and the two byte size (from dir). In my case, I put in “00 01 0A FE DD” to match the start of my boot file ($00010A) and it’s file size ($FEDD).
s 0 [ENTER] (skip to Logical Sector 0)
e (to enter edit mode)
Cursor over to row 10, column 5. Change three bytes to the start LSN:
00 01 0A (for me)
Cursor over to row 10, column 8. Change two bytes to the os9boot size:
5E DD (for me)
[ENTER] to exit edit mode
CMD: w (to write sector)
Are you sure? y (yes, you are sure)
Now the kernel track is where the “DOS” command will find it, and its sectors are marked as used to other files will not overwrite it.
OS9Boot has been copied over (and must be contiguous) and LSN0 has been updated to point to where the file starts and how big it is.
Step 6 – The only thing left to do is copy over the other needed files, which at a minimum should be “shell”, “grfdrv” and “sysgo”:
makdir /sd1/CMDS
copy /sd0/CMDS/shell /sd1/CMDS/shell
copy /sd0/CMDS/grfdrv /sd1/CMDS/grfdrv
copy /sd0/sysgo /sd1/sysgo
At this point, you now have a minimally bootable OS-9 hard drive (though it has no commands or anything useful on it yet). You might want to also include utilspak1 (common commands) and the base startup file (which will load them):
copy /sd0/CMDS/utilpak1 /sd1/CMDS/utilpak1
copy /sd0/startup /sd1/startup
I hope this walkthrough demystifies the OS-9 booting process. In a future article, maybe I can present code in BASIC09, C or assembly (or maybe all three versions) that does all of this for you.
2016/5/1: You can download a 128MB disk image here that is the results of me performing this steps tonight.
Until then … tips are always welcome :)