2 Copyright © 1995-2014, The AROS Development Team. All rights reserved.
5 Desc: Discover all mountable partitions
12 #include <aros/debug.h>
13 #include <exec/alerts.h>
14 #include <aros/asmcall.h>
15 #include <aros/bootloader.h>
16 #include <exec/lists.h>
17 #include <exec/memory.h>
18 #include <exec/resident.h>
19 #include <exec/types.h>
20 #include <libraries/configvars.h>
21 #include <libraries/expansion.h>
22 #include <libraries/expansionbase.h>
23 #include <libraries/partition.h>
24 #include <utility/tagitem.h>
25 #include <devices/bootblock.h>
26 #include <devices/timer.h>
27 #include <dos/dosextens.h>
28 #include <resources/filesysres.h>
30 #include <proto/exec.h>
31 #include <proto/expansion.h>
32 #include <proto/partition.h>
33 #include <proto/bootloader.h>
34 #include <clib/alib_protos.h>
36 #include LC_LIBDEFS_FILE
38 #include "dosboot_intern.h"
39 #include "../expansion/expansion_intern.h"
41 #define uppercase(x) ((x >= 'a' && x <= 'z') ? (x & 0xdf) : x)
43 static ULONG
GetOffset(struct Library
*PartitionBase
, struct PartitionHandle
*ph
)
49 tags
[0] = PT_DOSENVEC
;
55 GetPartitionAttrs(ph
, (struct TagItem
*)tags
);
56 offset
+= de
.de_LowCyl
* de
.de_Surfaces
* de
.de_BlocksPerTrack
;
62 static VOID
AddPartitionVolume(struct ExpansionBase
*ExpansionBase
, struct Library
*PartitionBase
,
63 struct FileSysStartupMsg
*fssm
, struct PartitionHandle
*table
,
64 struct PartitionHandle
*pn
, struct ExecBase
*SysBase
)
67 ULONG i
, blockspercyl
;
68 const struct PartitionAttribute
*attrs
;
70 IPTR pp
[4 + DE_BOOTBLOCKS
+ 1] = { };
71 struct DeviceNode
*devnode
;
75 ULONG pttype
= PHPTT_UNKNOWN
;
76 BOOL appended
, changed
;
79 D(bug("[Boot] AddPartitionVolume\n"));
80 GetPartitionTableAttrsTags(table
, PTT_TYPE
, &pttype
, TAG_DONE
);
82 attrs
= QueryPartitionAttrs(table
);
83 while ((attrs
->attribute
!= TAG_DONE
) && (attrs
->attribute
!= PT_NAME
))
84 attrs
++; /* look for name attr */
86 if (attrs
->attribute
!= TAG_DONE
)
88 D(bug("[Boot] RDB/GPT partition\n"));
90 /* partition has a name => RDB/GPT partition */
93 tags
[2] = PT_DOSENVEC
;
94 tags
[3] = (IPTR
)&pp
[4];
95 tags
[4] = PT_BOOTABLE
;
96 tags
[5] = (IPTR
)&bootable
;
98 GetPartitionAttrs(pn
, (struct TagItem
*)tags
);
100 D(bug("[Boot] Partition name: %s bootable: %d\n", name
, bootable
));
104 D(bug("[Boot] MBR/EBR partition\n"));
106 /* partition doesn't have a name => MBR/EBR partition */
107 tags
[0] = PT_POSITION
;
108 tags
[1] = (IPTR
)&ppos
;
109 tags
[2] = PT_DOSENVEC
;
110 tags
[3] = (IPTR
)&pp
[4];
112 GetPartitionAttrs(pn
, (struct TagItem
*)tags
);
115 * 'Active' is not the same as 'Bootable'. Theoretically we can set Active flag for multiple
116 * partitions, but this may screw up Microsoft system software which expects to see only one
122 devname
= AROS_BSTR_ADDR(fssm
->fssm_Device
);
123 for (i
= 0; i
< 26; i
++)
125 if (*devname
== '.' || *devname
== '\0')
127 name
[i
] = (UBYTE
)uppercase(*devname
);
130 if ((fssm
->fssm_Unit
/ 10))
131 name
[i
++] = '0' + (UBYTE
)(fssm
->fssm_Unit
/ 10);
132 name
[i
++] = '0' + (UBYTE
)(fssm
->fssm_Unit
% 10);
134 if (table
->table
->type
== PHPTT_EBR
)
137 name
[i
++] = '0' + (UBYTE
)(ppos
/ 10);
138 name
[i
++] = '0' + (UBYTE
)(ppos
% 10);
141 D(bug("[Boot] Partition name: %s\n", name
));
144 if ((pp
[4 + DE_TABLESIZE
] < DE_DOSTYPE
) || (pp
[4 + DE_DOSTYPE
] == 0))
147 * partition.library reports DosType == 0 for unknown filesystems.
148 * However dos.library will mount such DeviceNodes using rn_DefaultHandler
149 * (FFS). This is done for compatibility with 3rd party expansion ROMs.
150 * Here we ignore partitions with DosType == 0 and won't enter them into
153 D(bug("[Boot] Unknown DosType for %s, skipping partition\n"));
157 if (pttype
!= PHPTT_RDB
)
160 * Only RDB partitions can store the complete DosEnvec.
161 * For other partition types partition.library puts some defaults
162 * into these fields, however they do not have anything to do with
163 * real values, which are device-dependent.
164 * However, the device itself knows them. Here we inherit these settings
165 * from the original DeviceNode which represents the whole drive.
166 * Note that we don't change DosEnvec size. If these fields are not included,
167 * it will stay this way.
168 * Copy members only if they are present in device's DosEnvec.
170 struct DosEnvec
*devenv
= BADDR(fssm
->fssm_Environ
);
172 if (devenv
->de_TableSize
>= DE_MAXTRANSFER
)
174 pp
[4 + DE_MAXTRANSFER
] = devenv
->de_MaxTransfer
;
176 if (devenv
->de_TableSize
>= DE_MASK
)
177 pp
[4 + DE_MASK
] = devenv
->de_Mask
;
182 * BHFormat complains if this bit is not set, and it's really wrong to have it unset.
183 * So we explicitly set it here. Pavel Fedin <pavel.fedin@mail.ru>
185 pp
[4 + DE_BUFMEMTYPE
] |= MEMF_PUBLIC
;
188 pp
[1] = (IPTR
)AROS_BSTR_ADDR(fssm
->fssm_Device
);
189 pp
[2] = fssm
->fssm_Unit
;
190 pp
[3] = fssm
->fssm_Flags
;
192 i
= GetOffset(PartitionBase
, pn
);
193 blockspercyl
= pp
[4 + DE_BLKSPERTRACK
] * pp
[4 + DE_NUMHEADS
];
194 if (i
% blockspercyl
!= 0)
196 D(bug("[Boot] Start block of subtable not on cylinder boundary: "
197 "%ld (Blocks per Cylinder = %ld)\n", i
, blockspercyl
));
201 pp
[4 + DE_LOWCYL
] += i
;
202 pp
[4 + DE_HIGHCYL
] += i
;
204 /* Append .n if same device name already exists */
212 /* Note that we already have the mount list semaphore */
213 ForeachNode(&ExpansionBase
->MountList
, bn
)
215 if (stricmp(AROS_BSTR_ADDR(((struct DeviceNode
*)bn
->bn_DeviceNode
)->dn_Name
), name
) == 0)
220 name
[strlen(name
) - 1]++;
227 fsnode
= FindFileSystem(table
, FST_ID
, pp
[4 + DE_DOSTYPE
], TAG_DONE
);
229 D(bug("[Boot] Found on-disk filesystem 0x%08x\n", pp
[4 + DE_DOSTYPE
]));
230 AddBootFileSystem(fsnode
);
233 devnode
= MakeDosNode(pp
);
234 if (devnode
!= NULL
) {
235 AddBootNode(bootable
? pp
[4 + DE_BOOTPRI
] : -128, ADNF_STARTPROC
, devnode
, NULL
);
236 D(bug("[Boot] AddBootNode(%b, 0, 0x%p, NULL)\n", devnode
->dn_Name
, pp
[4 + DE_DOSTYPE
]));
241 static BOOL
CheckTables(struct ExpansionBase
*ExpansionBase
, struct Library
*PartitionBase
,
242 struct FileSysStartupMsg
*fssm
, struct PartitionHandle
*table
,
243 struct ExecBase
*SysBase
)
246 struct PartitionHandle
*ph
;
248 /* Traverse partition tables recursively, and attempt to add a BootNode
249 for any non-subtable partitions found */
250 if (OpenPartitionTable(table
) == 0)
252 ph
= (struct PartitionHandle
*)table
->table
->list
.lh_Head
;
253 while (ph
->ln
.ln_Succ
)
255 /* Attempt to add partition to system if it isn't a subtable */
256 if (!CheckTables(ExpansionBase
, PartitionBase
, fssm
, ph
, SysBase
))
257 AddPartitionVolume(ExpansionBase
, PartitionBase
, fssm
, table
,
259 ph
= (struct PartitionHandle
*)ph
->ln
.ln_Succ
;
262 ClosePartitionTable(table
);
267 static VOID
CheckPartitions(struct ExpansionBase
*ExpansionBase
, struct Library
*PartitionBase
, struct ExecBase
*SysBase
, struct BootNode
*bn
)
269 struct DeviceNode
*dn
= bn
->bn_DeviceNode
;
272 D(bug("CheckPartitions('%b') handler seglist = %x, handler = %s\n", dn
->dn_Name
,
273 dn
->dn_SegList
, AROS_BSTR_ADDR(dn
->dn_Handler
)));
276 * ata.device registers a HDx device describing whole disk with no handler name and no seglist
277 * massstorage.class registers each partition giving it a handler name but not seglist
280 /* If we already have filesystem handler, don't do anything */
281 if (dn
->dn_SegList
== BNULL
&& dn
->dn_Handler
== BNULL
)
283 struct FileSysStartupMsg
*fssm
= BADDR(dn
->dn_Startup
);
285 if (fssm
&& fssm
->fssm_Device
)
287 struct PartitionHandle
*pt
= OpenRootPartition(AROS_BSTR_ADDR(fssm
->fssm_Device
), fssm
->fssm_Unit
);
291 res
= CheckTables(ExpansionBase
, PartitionBase
, fssm
, pt
, SysBase
);
293 CloseRootPartition(pt
);
300 /* If no partitions were found for the DeviceNode, put it back */
301 Remove(&bn
->bn_Node
);
302 Enqueue(&ExpansionBase
->MountList
, &bn
->bn_Node
);
306 /* Scan all partitions manually for additional volumes that can be mounted. */
307 void dosboot_BootScan(LIBBASETYPEPTR LIBBASE
)
309 struct ExpansionBase
*ExpansionBase
= LIBBASE
->bm_ExpansionBase
;
311 struct BootNode
*bootNode
, *temp
;
312 struct List rootList
;
314 /* If we have partition.library, we can look for partitions */
315 PartitionBase
= OpenLibrary("partition.library", 2);
318 ObtainSemaphore(&IntExpBase(ExpansionBase
)->BootSemaphore
);
320 /* Transfer all bootnodes in the mountlist into a temporary list.
321 The assumption is that all bootnodes created before now represent
324 while ((temp
= (struct BootNode
*)RemHead(&ExpansionBase
->MountList
))
326 AddTail(&rootList
, (struct Node
*) temp
);
328 ForeachNodeSafe (&rootList
, bootNode
, temp
)
329 CheckPartitions(ExpansionBase
, PartitionBase
, SysBase
,
332 ReleaseSemaphore(&IntExpBase(ExpansionBase
)->BootSemaphore
);
334 CloseLibrary(PartitionBase
);