Subversion Repositories Kolibri OS

Rev

Rev 6468 | Rev 6828 | Go to most recent revision | Only display areas with differences | Regard whitespace | Details | Blame | Last modification | View Log | RSS feed

Rev 6468 Rev 6827
1
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
2
;;                                                              ;;
2
;;                                                              ;;
3
;; Copyright (C) KolibriOS team 2011-2015. All rights reserved. ;;
3
;; Copyright (C) KolibriOS team 2011-2015. All rights reserved. ;;
4
;; Distributed under terms of the GNU General Public License    ;;
4
;; Distributed under terms of the GNU General Public License    ;;
5
;;                                                              ;;
5
;;                                                              ;;
6
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
6
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
7
 
7
 
8
$Revision: 6468 $
8
$Revision: 6827 $
9
 
9
 
10
; =============================================================================
10
; =============================================================================
11
; ================================= Constants =================================
11
; ================================= Constants =================================
12
; =============================================================================
12
; =============================================================================
13
; Error codes for callback functions.
13
; Error codes for callback functions.
14
DISK_STATUS_OK              = 0 ; success
14
DISK_STATUS_OK              = 0 ; success
15
DISK_STATUS_GENERAL_ERROR   = -1; if no other code is suitable
15
DISK_STATUS_GENERAL_ERROR   = -1; if no other code is suitable
16
DISK_STATUS_INVALID_CALL    = 1 ; invalid input parameters
16
DISK_STATUS_INVALID_CALL    = 1 ; invalid input parameters
17
DISK_STATUS_NO_MEDIA        = 2 ; no media present
17
DISK_STATUS_NO_MEDIA        = 2 ; no media present
18
DISK_STATUS_END_OF_MEDIA    = 3 ; end of media while reading/writing data
18
DISK_STATUS_END_OF_MEDIA    = 3 ; end of media while reading/writing data
19
DISK_STATUS_NO_MEMORY       = 4 ; insufficient memory for driver operation
19
DISK_STATUS_NO_MEMORY       = 4 ; insufficient memory for driver operation
20
; Driver flags. Represent bits in DISK.DriverFlags.
20
; Driver flags. Represent bits in DISK.DriverFlags.
21
DISK_NO_INSERT_NOTIFICATION = 1
21
DISK_NO_INSERT_NOTIFICATION = 1
22
; Media flags. Represent bits in DISKMEDIAINFO.Flags.
22
; Media flags. Represent bits in DISKMEDIAINFO.Flags.
23
DISK_MEDIA_READONLY = 1
23
DISK_MEDIA_READONLY = 1
24
 
24
 
25
; If too many partitions are detected,there is probably an error on the disk.
25
; If too many partitions are detected,there is probably an error on the disk.
26
; 256 partitions should be enough for any reasonable use.
26
; 256 partitions should be enough for any reasonable use.
27
; Also, the same number is limiting the number of MBRs to process; if
27
; Also, the same number is limiting the number of MBRs to process; if
28
; too many MBRs are visible,there probably is a loop in the MBR structure.
28
; too many MBRs are visible,there probably is a loop in the MBR structure.
29
MAX_NUM_PARTITIONS = 256
29
MAX_NUM_PARTITIONS = 256
30
 
30
 
31
; =============================================================================
31
; =============================================================================
32
; ================================ Structures =================================
32
; ================================ Structures =================================
33
; =============================================================================
33
; =============================================================================
34
; This structure defines all callback functions for working with the physical
34
; This structure defines all callback functions for working with the physical
35
; device. They are implemented by a driver. Objects with this structure reside
35
; device. They are implemented by a driver. Objects with this structure reside
36
; in a driver.
36
; in a driver.
37
struct  DISKFUNC
37
struct  DISKFUNC
38
        strucsize       dd ?
38
        strucsize       dd ?
39
; Size of the structure. This field is intended for possible extensions of
39
; Size of the structure. This field is intended for possible extensions of
40
; this structure. If a new function is added to this structure and a driver
40
; this structure. If a new function is added to this structure and a driver
41
; implements an old version, the caller can detect this by checking .strucsize,
41
; implements an old version, the caller can detect this by checking .strucsize,
42
; so the driver remains compatible.
42
; so the driver remains compatible.
43
        close           dd ?
43
        close           dd ?
44
; The pointer to the function which frees all driver-specific resources for
44
; The pointer to the function which frees all driver-specific resources for
45
; the disk.
45
; the disk.
46
; Optional, may be NULL.
46
; Optional, may be NULL.
47
; void close(void* userdata);
47
; void close(void* userdata);
48
        closemedia      dd ?
48
        closemedia      dd ?
49
; The pointer to the function which informs the driver that the kernel has
49
; The pointer to the function which informs the driver that the kernel has
50
; finished all processing with the current media. If media is removed, the
50
; finished all processing with the current media. If media is removed, the
51
; driver should decline all requests to that media with DISK_STATUS_NO_MEDIA,
51
; driver should decline all requests to that media with DISK_STATUS_NO_MEDIA,
52
; even if new media is inserted, until this function is called. If media is
52
; even if new media is inserted, until this function is called. If media is
53
; removed, a new call to 'disk_media_changed' is not allowed until this
53
; removed, a new call to 'disk_media_changed' is not allowed until this
54
; function is called.
54
; function is called.
55
; Optional, may be NULL (if media is not removable).
55
; Optional, may be NULL (if media is not removable).
56
; void closemedia(void* userdata);
56
; void closemedia(void* userdata);
57
        querymedia      dd ?
57
        querymedia      dd ?
58
; The pointer to the function which determines capabilities of the media.
58
; The pointer to the function which determines capabilities of the media.
59
; int querymedia(void* userdata, DISKMEDIAINFO* info);
59
; int querymedia(void* userdata, DISKMEDIAINFO* info);
60
; Return value: one of DISK_STATUS_*
60
; Return value: one of DISK_STATUS_*
61
        read            dd ?
61
        read            dd ?
62
; The pointer to the function which reads data from the device.
62
; The pointer to the function which reads data from the device.
63
; int read(void* userdata, void* buffer, __int64 startsector, int* numsectors);
63
; int read(void* userdata, void* buffer, __int64 startsector, int* numsectors);
64
; input: *numsectors = number of sectors to read
64
; input: *numsectors = number of sectors to read
65
; output: *numsectors = number of sectors which were successfully read
65
; output: *numsectors = number of sectors which were successfully read
66
; Return value: one of DISK_STATUS_*
66
; Return value: one of DISK_STATUS_*
67
        write           dd ?
67
        write           dd ?
68
; The pointer to the function which writes data to the device.
68
; The pointer to the function which writes data to the device.
69
; Optional, may be NULL.
69
; Optional, may be NULL.
70
; int write(void* userdata, void* buffer, __int64 startsector, int* numsectors);
70
; int write(void* userdata, void* buffer, __int64 startsector, int* numsectors);
71
; input: *numsectors = number of sectors to write
71
; input: *numsectors = number of sectors to write
72
; output: *numsectors = number of sectors which were successfully written
72
; output: *numsectors = number of sectors which were successfully written
73
; Return value: one of DISK_STATUS_*
73
; Return value: one of DISK_STATUS_*
74
        flush           dd ?
74
        flush           dd ?
75
; The pointer to the function which flushes the internal device cache.
75
; The pointer to the function which flushes the internal device cache.
76
; Optional, may be NULL.
76
; Optional, may be NULL.
77
; int flush(void* userdata);
77
; int flush(void* userdata);
78
; Return value: one of DISK_STATUS_*
78
; Return value: one of DISK_STATUS_*
79
; Note that read/write are called by the cache manager, so a driver should not
79
; Note that read/write are called by the cache manager, so a driver should not
80
; create a software cache. This function is implemented for flushing a hardware
80
; create a software cache. This function is implemented for flushing a hardware
81
; cache, if it exists.
81
; cache, if it exists.
82
        adjust_cache_size       dd ?
82
        adjust_cache_size       dd ?
83
; The pointer to the function which returns the cache size for this device.
83
; The pointer to the function which returns the cache size for this device.
84
; Optional, may be NULL.
84
; Optional, may be NULL.
85
; unsigned int adjust_cache_size(unsigned int suggested_size);
85
; unsigned int adjust_cache_size(unsigned int suggested_size);
86
; Return value: 0 = disable cache, otherwise = used cache size in bytes.
86
; Return value: 0 = disable cache, otherwise = used cache size in bytes.
87
ends
87
ends
88
 
88
 
89
; This structure holds information on a medium.
89
; This structure holds information on a medium.
90
; Objects with this structure are allocated by the kernel as a part of the DISK
90
; Objects with this structure are allocated by the kernel as a part of the DISK
91
; structure and are filled by a driver in the 'querymedia' callback.
91
; structure and are filled by a driver in the 'querymedia' callback.
92
struct  DISKMEDIAINFO
92
struct  DISKMEDIAINFO
93
        Flags           dd ?
93
        Flags           dd ?
94
; Combination of DISK_MEDIA_* bits.
94
; Combination of DISK_MEDIA_* bits.
95
        SectorSize      dd ?
95
        SectorSize      dd ?
96
; Size of the sector.
96
; Size of the sector.
97
        Capacity        dq ?
97
        Capacity        dq ?
98
; Size of the media in sectors.
98
; Size of the media in sectors.
99
ends
99
ends
100
 
100
 
101
; This structure represents the disk cache. To follow the old implementation,
101
; This structure represents the disk cache. To follow the old implementation,
102
; there are two distinct caches for a disk, one for "system" data,and the other
102
; there are two distinct caches for a disk, one for "system" data,and the other
103
; for "application" data.
103
; for "application" data.
104
struct  DISKCACHE
104
struct  DISKCACHE
105
; The following fields are inherited from data32.inc:cache_ideX.
105
; The following fields are inherited from data32.inc:cache_ideX.
106
        pointer         dd ?
106
        pointer         dd ?
107
        data_size       dd ?    ; unused
107
        data_size       dd ?    ; unused
108
        data            dd ?
108
        data            dd ?
109
        sad_size        dd ?
109
        sad_size        dd ?
110
        search_start    dd ?
110
        search_start    dd ?
111
        sector_size_log dd ?
111
        sector_size_log dd ?
112
ends
112
ends
113
 
113
 
114
; This structure represents a disk device and its media for the kernel.
114
; This structure represents a disk device and its media for the kernel.
115
; This structure is allocated by the kernel in the 'disk_add' function,
115
; This structure is allocated by the kernel in the 'disk_add' function,
116
; freed in the 'disk_dereference' function.
116
; freed in the 'disk_dereference' function.
117
struct  DISK
117
struct  DISK
118
; Fields of disk object
118
; Fields of disk object
119
        Next            dd ?
119
        Next            dd ?
120
        Prev            dd ?
120
        Prev            dd ?
121
; All disk devices are linked in one list with these two fields.
121
; All disk devices are linked in one list with these two fields.
122
; Head of the list is the 'disk_list' variable.
122
; Head of the list is the 'disk_list' variable.
123
        Functions       dd ?
123
        Functions       dd ?
124
; Pointer to the 'DISKFUNC' structure with driver functions.
124
; Pointer to the 'DISKFUNC' structure with driver functions.
125
        Name            dd ?
125
        Name            dd ?
126
; Pointer to the string used for accesses through the global filesystem.
126
; Pointer to the string used for accesses through the global filesystem.
127
        UserData        dd ?
127
        UserData        dd ?
128
; This field is passed to all callback functions so a driver can decide which
128
; This field is passed to all callback functions so a driver can decide which
129
; physical device is addressed.
129
; physical device is addressed.
130
        DriverFlags     dd ?
130
        DriverFlags     dd ?
131
; Bitfield. Currently only DISK_NO_INSERT_NOTIFICATION bit is defined.
131
; Bitfield. Currently only DISK_NO_INSERT_NOTIFICATION bit is defined.
132
; If it is set, the driver will never issue 'disk_media_changed' notification
132
; If it is set, the driver will never issue 'disk_media_changed' notification
133
; with argument set to true, so the kernel must try to detect media during
133
; with argument set to true, so the kernel must try to detect media during
134
; requests from the file system.
134
; requests from the file system.
135
        RefCount        dd ?
135
        RefCount        dd ?
136
; Count of active references to this structure. One reference is kept during
136
; Count of active references to this structure. One reference is kept during
137
; the lifetime of the structure between 'disk_add' and 'disk_del'.
137
; the lifetime of the structure between 'disk_add' and 'disk_del'.
138
; Another reference is taken during any filesystem operation for this disk.
138
; Another reference is taken during any filesystem operation for this disk.
139
; One reference is added if media is inserted.
139
; One reference is added if media is inserted.
140
; The structure is destroyed when the reference count decrements to zero:
140
; The structure is destroyed when the reference count decrements to zero:
141
; this usually occurs in 'disk_del', but can be delayed to the end of last
141
; this usually occurs in 'disk_del', but can be delayed to the end of last
142
; filesystem operation, if one is active.
142
; filesystem operation, if one is active.
143
        MediaLock       MUTEX
143
        MediaLock       MUTEX
144
; Lock to protect the MEDIA structure. See the description after
144
; Lock to protect the MEDIA structure. See the description after
145
; 'disk_list_mutex' for the locking strategy.
145
; 'disk_list_mutex' for the locking strategy.
146
; Fields of media object
146
; Fields of media object
147
        MediaInserted   db ?
147
        MediaInserted   db ?
148
; 0 if media is not inserted, nonzero otherwise.
148
; 0 if media is not inserted, nonzero otherwise.
149
        MediaUsed       db ?
149
        MediaUsed       db ?
150
; 0 if media fields are not used, nonzero otherwise. If .MediaRefCount is
150
; 0 if media fields are not used, nonzero otherwise. If .MediaRefCount is
151
; nonzero, this field is nonzero too; however, when .MediaRefCount goes
151
; nonzero, this field is nonzero too; however, when .MediaRefCount goes
152
; to zero, there is some time interval during which media object is still used.
152
; to zero, there is some time interval during which media object is still used.
153
                        dw ? ; padding
153
                        dw ? ; padding
154
; The following fields are not valid unless either .MediaInserted is nonzero
154
; The following fields are not valid unless either .MediaInserted is nonzero
155
; or they are accessed from a code which has obtained the reference when
155
; or they are accessed from a code which has obtained the reference when
156
; .MediaInserted was nonzero.
156
; .MediaInserted was nonzero.
157
        MediaRefCount   dd ?
157
        MediaRefCount   dd ?
158
; Count of active references to the media object. One reference is kept during
158
; Count of active references to the media object. One reference is kept during
159
; the lifetime of the media between two calls to 'disk_media_changed'.
159
; the lifetime of the media between two calls to 'disk_media_changed'.
160
; Another reference is taken during any filesystem operation for this media.
160
; Another reference is taken during any filesystem operation for this media.
161
; The callback 'closemedia' is called when the reference count decrements to
161
; The callback 'closemedia' is called when the reference count decrements to
162
; zero: this usually occurs in 'disk_media_changed', but can be delayed to the
162
; zero: this usually occurs in 'disk_media_changed', but can be delayed to the
163
; end of the last filesystem operation, if one is active.
163
; end of the last filesystem operation, if one is active.
164
        MediaInfo       DISKMEDIAINFO
164
        MediaInfo       DISKMEDIAINFO
165
; This field keeps information on the current media.
165
; This field keeps information on the current media.
166
        NumPartitions   dd ?
166
        NumPartitions   dd ?
167
; Number of partitions on this media.
167
; Number of partitions on this media.
168
        Partitions      dd ?
168
        Partitions      dd ?
169
; Pointer to array of .NumPartitions pointers to PARTITION structures.
169
; Pointer to array of .NumPartitions pointers to PARTITION structures.
170
        cache_size      dd ?
170
        cache_size      dd ?
171
; inherited from cache_ideX_size
171
; inherited from cache_ideX_size
172
        CacheLock       MUTEX
172
        CacheLock       MUTEX
173
; Lock to protect both caches.
173
; Lock to protect both caches.
174
        SysCache        DISKCACHE
174
        SysCache        DISKCACHE
175
        AppCache        DISKCACHE
175
        AppCache        DISKCACHE
176
; Two caches for the disk.
176
; Two caches for the disk.
177
ends
177
ends
178
 
178
 
179
; This structure represents one partition for the kernel. This is a base
179
; This structure represents one partition for the kernel. This is a base
180
; template, the actual contents after common fields is determined by the
180
; template, the actual contents after common fields is determined by the
181
; file system code for this partition.
181
; file system code for this partition.
182
struct  PARTITION
182
struct  PARTITION
183
        FirstSector     dq ?
183
        FirstSector     dq ?
184
; First sector of the partition.
184
; First sector of the partition.
185
        Length          dq ?
185
        Length          dq ?
186
; Length of the partition in sectors.
186
; Length of the partition in sectors.
187
        Disk            dd ?
187
        Disk            dd ?
188
; Pointer to parent DISK structure.
188
; Pointer to parent DISK structure.
189
        FSUserFunctions dd ?
189
        FSUserFunctions dd ?
190
; Handlers for the sysfunction 70h. This field is a pointer to the following
190
; Handlers for the sysfunction 70h. This field is a pointer to the following
191
; array. The first dword is pointer to disconnect handler.
191
; array. The first dword is pointer to disconnect handler.
192
; The first dword is a number of supported subfunctions, other dwords
192
; The first dword is a number of supported subfunctions, other dwords
193
; point to handlers of corresponding subfunctions.
193
; point to handlers of corresponding subfunctions.
194
; ...fs-specific data may follow...
194
; ...fs-specific data may follow...
195
ends
195
ends
196
 
196
 
197
; This is an external structure, it represents an entry in the partition table.
197
; This is an external structure, it represents an entry in the partition table.
198
struct  PARTITION_TABLE_ENTRY
198
struct  PARTITION_TABLE_ENTRY
199
        Bootable        db ?
199
        Bootable        db ?
200
; 80h = bootable partition, 0 = non-bootable partition, other values = invalid
200
; 80h = bootable partition, 0 = non-bootable partition, other values = invalid
201
        FirstHead       db ?
201
        FirstHead       db ?
202
        FirstSector     db ?
202
        FirstSector     db ?
203
        FirstTrack      db ?
203
        FirstTrack      db ?
204
; Coordinates of first sector in CHS.
204
; Coordinates of first sector in CHS.
205
        Type            db ?
205
        Type            db ?
206
; Partition type, one of predefined constants. 0 = empty, several types denote
206
; Partition type, one of predefined constants. 0 = empty, several types denote
207
; extended partition (see process_partition_table_entry), we are not interested
207
; extended partition (see process_partition_table_entry), we are not interested
208
; in other values.
208
; in other values.
209
        LastHead        db ?
209
        LastHead        db ?
210
        LastSector      db ?
210
        LastSector      db ?
211
        LastTrack       db ?
211
        LastTrack       db ?
212
; Coordinates of last sector in CHS.
212
; Coordinates of last sector in CHS.
213
        FirstAbsSector  dd ?
213
        FirstAbsSector  dd ?
214
; Coordinate of first sector in LBA.
214
; Coordinate of first sector in LBA.
215
        Length          dd ?
215
        Length          dd ?
216
; Length of the partition in sectors.
216
; Length of the partition in sectors.
217
ends
217
ends
-
 
218
 
-
 
219
; GUID Partition Table Header, UEFI 2.6, Table 18
-
 
220
struct GPTH
-
 
221
        Signature                rb 8
-
 
222
; 'EFI PART'
-
 
223
        Revision                 dd ?
-
 
224
; 0x00010000
-
 
225
        HeaderSize               dd ?
-
 
226
; Size of this header in bytes, must fit to one sector.
-
 
227
        HeaderCRC32              dd ?
-
 
228
; Set this field to zero, compute CRC32 via 0xEDB88320, compare.
-
 
229
        Reserved                 dd ?
-
 
230
; Myst be zero.
-
 
231
        MyLBA                    dq ?
-
 
232
; LBA of the sector containing this GPT header.
-
 
233
        AlternateLBA             dq ?
-
 
234
; LBA of the sector containing the other GPT header.
-
 
235
; AlternateLBA of Primary GPTH points to Backup one and vice versa.
-
 
236
        FirstUsableLBA           dq ?
-
 
237
; Only sectors between first and last UsableLBA may form partitions
-
 
238
        LastUsableLBA            dq ?
-
 
239
        DiskGUID                 rb 16
-
 
240
; Globally Unique IDentifier
-
 
241
        PartitionEntryLBA        dq ?
-
 
242
; First LBA of Partition Entry Array.
-
 
243
; Length in bytes is computed as a product of two following fields.
-
 
244
        NumberOfPartitionEntries dd ?
-
 
245
; Actual number of partitions depends on the contents of Partition Entry Array.
-
 
246
; A partition entry is unused if zeroed.
-
 
247
        SizeOfPartitionEntry     dd ?   ; in bytes
-
 
248
        PartitionEntryArrayCRC32 dd ?
-
 
249
; Same CRC as for GPT header.
-
 
250
ends
-
 
251
 
-
 
252
; GPT Partition Entry, UEFI 2.6, Table 19
-
 
253
struct GPE
-
 
254
        PartitionTypeGUID       rb 16
-
 
255
        UniquePartitionGUID     rb 16
-
 
256
        StartingLBA             dq ?
-
 
257
        EndingLBA               dq ?
-
 
258
; Length in sectors is EndingLBA - StartingLBA + 1.
-
 
259
        Attributes              dq ?
-
 
260
        PartitionName           rb 72
-
 
261
ends
218
 
262
 
219
; =============================================================================
263
; =============================================================================
220
; ================================ Global data ================================
264
; ================================ Global data ================================
221
; =============================================================================
265
; =============================================================================
222
iglobal
266
iglobal
223
; The pseudo-item for the list of all DISK structures.
267
; The pseudo-item for the list of all DISK structures.
224
; Initialized to the empty list.
268
; Initialized to the empty list.
225
disk_list:
269
disk_list:
226
        dd      disk_list
270
        dd      disk_list
227
        dd      disk_list
271
        dd      disk_list
228
endg
272
endg
229
uglobal
273
uglobal
230
; This mutex guards all operations with the global list of DISK structures.
274
; This mutex guards all operations with the global list of DISK structures.
231
disk_list_mutex MUTEX
275
disk_list_mutex MUTEX
232
; * There are two dependent objects, a disk and a media. In the simplest case,
276
; * There are two dependent objects, a disk and a media. In the simplest case,
233
;   disk and media are both non-removable. However, in the general case both
277
;   disk and media are both non-removable. However, in the general case both
234
;   can be removed at any time, simultaneously or only media,and this makes things
278
;   can be removed at any time, simultaneously or only media,and this makes things
235
;   complicated.
279
;   complicated.
236
; * For efficiency, both disk and media objects are located in the one
280
; * For efficiency, both disk and media objects are located in the one
237
;   structure named DISK. However, logically they are different.
281
;   structure named DISK. However, logically they are different.
238
; * The following operations use data of disk object: adding (disk_add);
282
; * The following operations use data of disk object: adding (disk_add);
239
;   deleting (disk_del); filesystem (fs_lfn which eventually calls
283
;   deleting (disk_del); filesystem (fs_lfn which eventually calls
240
;   dyndisk_handler or dyndisk_enum_root).
284
;   dyndisk_handler or dyndisk_enum_root).
241
; * The following operations use data of media object: adding/removing
285
; * The following operations use data of media object: adding/removing
242
;   (disk_media_changed); filesystem (fs_lfn which eventually calls
286
;   (disk_media_changed); filesystem (fs_lfn which eventually calls
243
;   dyndisk_handler; dyndisk_enum_root doesn't work with media).
287
;   dyndisk_handler; dyndisk_enum_root doesn't work with media).
244
; * Notifications disk_add, disk_media_changed, disk_del are synchronized
288
; * Notifications disk_add, disk_media_changed, disk_del are synchronized
245
;   between themselves, this is a requirement for the driver. However, file
289
;   between themselves, this is a requirement for the driver. However, file
246
;   system operations are asynchronous, can be issued at any time by any
290
;   system operations are asynchronous, can be issued at any time by any
247
;   thread.
291
;   thread.
248
; * We must prevent a situation when a filesystem operation thinks that the
292
; * We must prevent a situation when a filesystem operation thinks that the
249
;   object is still valid but in fact the notification has destroyed the
293
;   object is still valid but in fact the notification has destroyed the
250
;   object. So we keep a reference counter for both disk and media and destroy
294
;   object. So we keep a reference counter for both disk and media and destroy
251
;   the object when this counter goes to zero.
295
;   the object when this counter goes to zero.
252
; * The driver must know when it is safe to free driver-allocated resources.
296
; * The driver must know when it is safe to free driver-allocated resources.
253
;   The object can be alive even after death notification has completed.
297
;   The object can be alive even after death notification has completed.
254
;   We use special callbacks to satisfy both assertions: 'close' for the disk
298
;   We use special callbacks to satisfy both assertions: 'close' for the disk
255
;   and 'closemedia' for the media. The destruction of the object includes
299
;   and 'closemedia' for the media. The destruction of the object includes
256
;   calling the corresponding callback.
300
;   calling the corresponding callback.
257
; * Each filesystem operation keeps one reference for the disk and one
301
; * Each filesystem operation keeps one reference for the disk and one
258
;   reference for the media. Notification disk_del forces notification on the
302
;   reference for the media. Notification disk_del forces notification on the
259
;   media death, so the reference counter for the disk is always not less than
303
;   media death, so the reference counter for the disk is always not less than
260
;   the reference counter for the media.
304
;   the reference counter for the media.
261
; * Two operations "get the object" and "increment the reference counter" can
305
; * Two operations "get the object" and "increment the reference counter" can
262
;   not be done simultaneously. We use a mutex to guard the consistency here.
306
;   not be done simultaneously. We use a mutex to guard the consistency here.
263
;   It must be a part of the container for the object, so that this mutex can
307
;   It must be a part of the container for the object, so that this mutex can
264
;   be acquired as a part of getting the object from the container. The
308
;   be acquired as a part of getting the object from the container. The
265
;   container for disk object is the global list, and this list is guarded by
309
;   container for disk object is the global list, and this list is guarded by
266
;   'disk_list_mutex'. The container for media object is the disk object, and
310
;   'disk_list_mutex'. The container for media object is the disk object, and
267
;   the corresponding mutex is DISK.MediaLock.
311
;   the corresponding mutex is DISK.MediaLock.
268
; * Notifications do not change the data of objects, they can only remove
312
; * Notifications do not change the data of objects, they can only remove
269
;   objects. Thus we don't need another synchronization at this level. If two
313
;   objects. Thus we don't need another synchronization at this level. If two
270
;   filesystem operations are referencing the same filesystem data, this is
314
;   filesystem operations are referencing the same filesystem data, this is
271
;   better resolved at the level of the filesystem.
315
;   better resolved at the level of the filesystem.
272
endg
316
endg
273
 
317
 
274
iglobal
318
iglobal
275
; The function 'disk_scan_partitions' needs three sector-sized buffers for
319
; The function 'disk_scan_partitions' needs three sector-sized buffers for
276
; MBR, bootsector and fs-temporary sector data. It can not use the static
320
; MBR, bootsector and fs-temporary sector data. It can not use the static
277
; buffers always, since it can be called for two or more disks in parallel.
321
; buffers always, since it can be called for two or more disks in parallel.
278
; However, this case is not typical. We reserve three static 512-byte buffers
322
; However, this case is not typical. We reserve three static 512-byte buffers
279
; and a flag that these buffers are currently used. If 'disk_scan_partitions'
323
; and a flag that these buffers are currently used. If 'disk_scan_partitions'
280
; detects that the buffers are currently used, it allocates buffers from the
324
; detects that the buffers are currently used, it allocates buffers from the
281
; heap. Also, the heap is used when sector size is other than 512.
325
; heap. Also, the heap is used when sector size is other than 512.
282
; The flag is implemented as a global dword variable. When the static buffers
326
; The flag is implemented as a global dword variable. When the static buffers
283
; are not used, the value is -1. When the static buffers are used, the value
327
; are not used, the value is -1. When the static buffers are used, the value
284
; is normally 0 and temporarily can become greater. The function increments
328
; is normally 0 and temporarily can become greater. The function increments
285
; this value. If the resulting value is zero, it uses the buffers and
329
; this value. If the resulting value is zero, it uses the buffers and
286
; decrements the value when the job is done. Otherwise, it immediately
330
; decrements the value when the job is done. Otherwise, it immediately
287
; decrements the value and uses buffers from the heap, allocated in the
331
; decrements the value and uses buffers from the heap, allocated in the
288
; beginning and freed in the end.
332
; beginning and freed in the end.
289
partition_buffer_users  dd      -1
333
partition_buffer_users  dd      -1
290
endg
334
endg
291
uglobal
335
uglobal
292
; The static buffers for MBR, bootsector and fs-temporary sector data.
336
; The static buffers for MBR, bootsector and fs-temporary sector data.
293
align 16
337
align 16
294
mbr_buffer      rb      512
338
mbr_buffer      rb      512
295
bootsect_buffer rb      512
339
bootsect_buffer rb      512
296
fs_tmp_buffer   rb      512
340
fs_tmp_buffer   rb      512
297
endg
341
endg
298
 
342
 
299
iglobal
343
iglobal
300
; This is the array of default implementations of driver callbacks.
344
; This is the array of default implementations of driver callbacks.
301
; Same as DRIVERFUNC structure except for the first field; all functions must
345
; Same as DRIVERFUNC structure except for the first field; all functions must
302
; have the default implementations.
346
; have the default implementations.
303
align 4
347
align 4
304
disk_default_callbacks:
348
disk_default_callbacks:
305
        dd      disk_default_close
349
        dd      disk_default_close
306
        dd      disk_default_closemedia
350
        dd      disk_default_closemedia
307
        dd      disk_default_querymedia
351
        dd      disk_default_querymedia
308
        dd      disk_default_read
352
        dd      disk_default_read
309
        dd      disk_default_write
353
        dd      disk_default_write
310
        dd      disk_default_flush
354
        dd      disk_default_flush
311
        dd      disk_default_adjust_cache_size
355
        dd      disk_default_adjust_cache_size
312
endg
356
endg
313
 
357
 
314
; =============================================================================
358
; =============================================================================
315
; ================================= Functions =================================
359
; ================================= Functions =================================
316
; =============================================================================
360
; =============================================================================
317
 
361
 
318
; This function registers a disk device.
362
; This function registers a disk device.
319
; This includes:
363
; This includes:
320
; - allocating an internal structure describing this device;
364
; - allocating an internal structure describing this device;
321
; - registering this structure in the global filesystem.
365
; - registering this structure in the global filesystem.
322
; The function initializes the disk as if there is no media. If a media is
366
; The function initializes the disk as if there is no media. If a media is
323
; present, the function 'disk_media_changed' should be called after this
367
; present, the function 'disk_media_changed' should be called after this
324
; function succeeds.
368
; function succeeds.
325
; Parameters:
369
; Parameters:
326
; [esp+4] = pointer to DISKFUNC structure with the callbacks
370
; [esp+4] = pointer to DISKFUNC structure with the callbacks
327
; [esp+8] = pointer to name (ASCIIZ string)
371
; [esp+8] = pointer to name (ASCIIZ string)
328
; [esp+12] = userdata to be passed to the callbacks as is.
372
; [esp+12] = userdata to be passed to the callbacks as is.
329
; [esp+16] = flags, bitfield. Currently only DISK_NO_INSERT_NOTIFICATION bit
373
; [esp+16] = flags, bitfield. Currently only DISK_NO_INSERT_NOTIFICATION bit
330
;            is defined.
374
;            is defined.
331
; Return value:
375
; Return value:
332
; NULL = operation has failed
376
; NULL = operation has failed
333
; non-NULL = handle of the disk. This handle can be used
377
; non-NULL = handle of the disk. This handle can be used
334
; in the operations with other Disk* functions.
378
; in the operations with other Disk* functions.
335
; The handle is the pointer to the internal structure DISK.
379
; The handle is the pointer to the internal structure DISK.
336
disk_add:
380
disk_add:
337
        push    ebx esi         ; save used registers to be stdcall
381
        push    ebx esi         ; save used registers to be stdcall
338
; 1. Allocate the DISK structure.
382
; 1. Allocate the DISK structure.
339
; 1a. Call the heap manager.
383
; 1a. Call the heap manager.
340
        movi    eax, sizeof.DISK
384
        movi    eax, sizeof.DISK
341
        call    malloc
385
        call    malloc
342
; 1b. Check the result. If allocation failed, return (go to 9) with eax = 0.
386
; 1b. Check the result. If allocation failed, return (go to 9) with eax = 0.
343
        test    eax, eax
387
        test    eax, eax
344
        jz      .nothing
388
        jz      .nothing
345
; 2. Copy the disk name to the DISK structure.
389
; 2. Copy the disk name to the DISK structure.
346
; 2a. Get length of the name, including the terminating zero.
390
; 2a. Get length of the name, including the terminating zero.
347
        mov     ebx, [esp+8+8]  ; ebx = pointer to name
391
        mov     ebx, [esp+8+8]  ; ebx = pointer to name
348
        push    eax             ; save allocated pointer to DISK
392
        push    eax             ; save allocated pointer to DISK
349
        xor     eax, eax        ; the argument of malloc() is in eax
393
        xor     eax, eax        ; the argument of malloc() is in eax
350
@@:
394
@@:
351
        inc     eax
395
        inc     eax
352
        cmp     byte [ebx+eax-1], 0
396
        cmp     byte [ebx+eax-1], 0
353
        jnz     @b
397
        jnz     @b
354
; 2b. Call the heap manager.
398
; 2b. Call the heap manager.
355
        call    malloc
399
        call    malloc
356
; 2c. Check the result. If allocation failed, go to 7.
400
; 2c. Check the result. If allocation failed, go to 7.
357
        pop     esi             ; restore allocated pointer to DISK
401
        pop     esi             ; restore allocated pointer to DISK
358
        test    eax, eax
402
        test    eax, eax
359
        jz      .free
403
        jz      .free
360
; 2d. Store the allocated pointer to the DISK structure.
404
; 2d. Store the allocated pointer to the DISK structure.
361
        mov     [esi+DISK.Name], eax
405
        mov     [esi+DISK.Name], eax
362
; 2e. Copy the name.
406
; 2e. Copy the name.
363
@@:
407
@@:
364
        mov     dl, [ebx]
408
        mov     dl, [ebx]
365
        mov     [eax], dl
409
        mov     [eax], dl
366
        inc     ebx
410
        inc     ebx
367
        inc     eax
411
        inc     eax
368
        test    dl, dl
412
        test    dl, dl
369
        jnz     @b
413
        jnz     @b
370
; 3. Copy other arguments of the function to the DISK structure.
414
; 3. Copy other arguments of the function to the DISK structure.
371
        mov     eax, [esp+4+8]
415
        mov     eax, [esp+4+8]
372
        mov     [esi+DISK.Functions], eax
416
        mov     [esi+DISK.Functions], eax
373
        mov     eax, [esp+12+8]
417
        mov     eax, [esp+12+8]
374
        mov     [esi+DISK.UserData], eax
418
        mov     [esi+DISK.UserData], eax
375
        mov     eax, [esp+16+8]
419
        mov     eax, [esp+16+8]
376
        mov     [esi+DISK.DriverFlags], eax
420
        mov     [esi+DISK.DriverFlags], eax
377
; 4. Initialize other fields of the DISK structure.
421
; 4. Initialize other fields of the DISK structure.
378
; Media is not inserted, reference counter is 1.
422
; Media is not inserted, reference counter is 1.
379
        lea     ecx, [esi+DISK.MediaLock]
423
        lea     ecx, [esi+DISK.MediaLock]
380
        call    mutex_init
424
        call    mutex_init
381
        xor     eax, eax
425
        xor     eax, eax
382
        mov     dword [esi+DISK.MediaInserted], eax
426
        mov     dword [esi+DISK.MediaInserted], eax
383
        mov     [esi+DISK.MediaRefCount], eax
427
        mov     [esi+DISK.MediaRefCount], eax
384
        inc     eax
428
        inc     eax
385
        mov     [esi+DISK.RefCount], eax
429
        mov     [esi+DISK.RefCount], eax
386
; The DISK structure is initialized.
430
; The DISK structure is initialized.
387
; 5. Insert the new structure to the global list.
431
; 5. Insert the new structure to the global list.
388
; 5a. Acquire the mutex.
432
; 5a. Acquire the mutex.
389
        mov     ecx, disk_list_mutex
433
        mov     ecx, disk_list_mutex
390
        call    mutex_lock
434
        call    mutex_lock
391
; 5b. Insert item to the tail of double-linked list.
435
; 5b. Insert item to the tail of double-linked list.
392
        mov     edx, disk_list
436
        mov     edx, disk_list
393
        list_add_tail esi, edx     ;esi= new edx= list head
437
        list_add_tail esi, edx     ;esi= new edx= list head
394
; 5c. Release the mutex.
438
; 5c. Release the mutex.
395
        call    mutex_unlock
439
        call    mutex_unlock
396
; 6. Return with eax = pointer to DISK.
440
; 6. Return with eax = pointer to DISK.
397
        xchg    eax, esi
441
        xchg    eax, esi
398
        jmp     .nothing
442
        jmp     .nothing
399
.free:
443
.free:
400
; Memory allocation for DISK structure succeeded, but for disk name failed.
444
; Memory allocation for DISK structure succeeded, but for disk name failed.
401
; 7. Free the DISK structure.
445
; 7. Free the DISK structure.
402
        xchg    eax, esi
446
        xchg    eax, esi
403
        call    free
447
        call    free
404
; 8. Return with eax = 0.
448
; 8. Return with eax = 0.
405
        xor     eax, eax
449
        xor     eax, eax
406
.nothing:
450
.nothing:
407
; 9. Return.
451
; 9. Return.
408
        pop     esi ebx         ; restore used registers to be stdcall
452
        pop     esi ebx         ; restore used registers to be stdcall
409
        ret     16              ; purge 4 dword arguments to be stdcall
453
        ret     16              ; purge 4 dword arguments to be stdcall
410
 
454
 
411
; This function deletes a disk device from the global filesystem.
455
; This function deletes a disk device from the global filesystem.
412
; This includes:
456
; This includes:
413
; - removing a media including all partitions;
457
; - removing a media including all partitions;
414
; - deleting this structure from the global filesystem;
458
; - deleting this structure from the global filesystem;
415
; - dereferencing the DISK structure and possibly destroying it.
459
; - dereferencing the DISK structure and possibly destroying it.
416
; Parameters:
460
; Parameters:
417
; [esp+4] = handle of the disk, i.e. the pointer to the DISK structure.
461
; [esp+4] = handle of the disk, i.e. the pointer to the DISK structure.
418
; Return value: none.
462
; Return value: none.
419
disk_del:
463
disk_del:
420
        push    esi         ; save used registers to be stdcall
464
        push    esi         ; save used registers to be stdcall
421
; 1. Force media to be removed. If the media is already removed, the
465
; 1. Force media to be removed. If the media is already removed, the
422
; call does nothing.
466
; call does nothing.
423
        mov     esi, [esp+4+4]  ; esi = handle of the disk
467
        mov     esi, [esp+4+4]  ; esi = handle of the disk
424
        stdcall disk_media_changed, esi, 0
468
        stdcall disk_media_changed, esi, 0
425
; 2. Delete the structure from the global list.
469
; 2. Delete the structure from the global list.
426
; 2a. Acquire the mutex.
470
; 2a. Acquire the mutex.
427
        mov     ecx, disk_list_mutex
471
        mov     ecx, disk_list_mutex
428
        call    mutex_lock
472
        call    mutex_lock
429
; 2b. Delete item from double-linked list.
473
; 2b. Delete item from double-linked list.
430
        mov     eax, [esi+DISK.Next]
474
        mov     eax, [esi+DISK.Next]
431
        mov     edx, [esi+DISK.Prev]
475
        mov     edx, [esi+DISK.Prev]
432
        mov     [eax+DISK.Prev], edx
476
        mov     [eax+DISK.Prev], edx
433
        mov     [edx+DISK.Next], eax
477
        mov     [edx+DISK.Next], eax
434
; 2c. Release the mutex.
478
; 2c. Release the mutex.
435
        call    mutex_unlock
479
        call    mutex_unlock
436
; 3. The structure still has one reference created in disk_add. Remove this
480
; 3. The structure still has one reference created in disk_add. Remove this
437
; reference. If there are no other references, disk_dereference will free the
481
; reference. If there are no other references, disk_dereference will free the
438
; structure.
482
; structure.
439
        call    disk_dereference
483
        call    disk_dereference
440
; 4. Return.
484
; 4. Return.
441
        pop     esi             ; restore used registers to be stdcall
485
        pop     esi             ; restore used registers to be stdcall
442
        ret     4               ; purge 1 dword argument to be stdcall
486
        ret     4               ; purge 1 dword argument to be stdcall
443
 
487
 
444
; This is an internal function which removes a previously obtained reference
488
; This is an internal function which removes a previously obtained reference
445
; to the disk. If this is the last reference, this function lets the driver
489
; to the disk. If this is the last reference, this function lets the driver
446
; finalize all associated data, and afterwards frees the DISK structure.
490
; finalize all associated data, and afterwards frees the DISK structure.
447
; esi = pointer to DISK structure
491
; esi = pointer to DISK structure
448
disk_dereference:
492
disk_dereference:
449
; 1. Decrement reference counter. Use atomic operation to correctly handle
493
; 1. Decrement reference counter. Use atomic operation to correctly handle
450
; possible simultaneous calls.
494
; possible simultaneous calls.
451
        lock dec [esi+DISK.RefCount]
495
        lock dec [esi+DISK.RefCount]
452
; 2. If the result is nonzero, there are other references, so nothing to do.
496
; 2. If the result is nonzero, there are other references, so nothing to do.
453
; In this case, return (go to 4).
497
; In this case, return (go to 4).
454
        jnz     .nothing
498
        jnz     .nothing
455
; 3. If we are here, we just removed the last reference and must destroy the
499
; 3. If we are here, we just removed the last reference and must destroy the
456
; disk object.
500
; disk object.
457
; 3a. Call the driver.
501
; 3a. Call the driver.
458
        mov     al, DISKFUNC.close
502
        mov     al, DISKFUNC.close
459
        stdcall disk_call_driver
503
        stdcall disk_call_driver
460
; 3b. Free the structure.
504
; 3b. Free the structure.
461
        xchg    eax, esi
505
        xchg    eax, esi
462
        push    ebx
506
        push    ebx
463
        call    free
507
        call    free
464
        pop     ebx
508
        pop     ebx
465
; 4. Return.
509
; 4. Return.
466
.nothing:
510
.nothing:
467
        ret
511
        ret
468
 
512
 
469
; This is an internal function which removes a previously obtained reference
513
; This is an internal function which removes a previously obtained reference
470
; to the media. If this is the last reference, this function calls 'closemedia'
514
; to the media. If this is the last reference, this function calls 'closemedia'
471
; callback to signal the driver that the processing has finished and it is safe
515
; callback to signal the driver that the processing has finished and it is safe
472
; to inform about a new media.
516
; to inform about a new media.
473
; esi = pointer to DISK structure
517
; esi = pointer to DISK structure
474
disk_media_dereference:
518
disk_media_dereference:
475
; 1. Decrement reference counter. Use atomic operation to correctly handle
519
; 1. Decrement reference counter. Use atomic operation to correctly handle
476
; possible simultaneous calls.
520
; possible simultaneous calls.
477
        lock dec [esi+DISK.MediaRefCount]
521
        lock dec [esi+DISK.MediaRefCount]
478
; 2. If the result is nonzero, there are other references, so nothing to do.
522
; 2. If the result is nonzero, there are other references, so nothing to do.
479
; In this case, return (go to 4).
523
; In this case, return (go to 4).
480
        jnz     .nothing
524
        jnz     .nothing
481
; 3. If we are here, we just removed the last reference and must destroy the
525
; 3. If we are here, we just removed the last reference and must destroy the
482
; media object.
526
; media object.
483
; Note that the same place inside the DISK structure is reused for all media
527
; Note that the same place inside the DISK structure is reused for all media
484
; objects, so we must guarantee that reusing does not happen while freeing.
528
; objects, so we must guarantee that reusing does not happen while freeing.
485
; Reusing is only possible when someone processes a new media. There are two
529
; Reusing is only possible when someone processes a new media. There are two
486
; mutually exclusive variants:
530
; mutually exclusive variants:
487
; * driver issues media insert notifications (DISK_NO_INSERT_NOTIFICATION bit
531
; * driver issues media insert notifications (DISK_NO_INSERT_NOTIFICATION bit
488
;   in DISK.DriverFlags is not set). In this case, we require from the driver
532
;   in DISK.DriverFlags is not set). In this case, we require from the driver
489
;   that such notification (except for the first one) can occur only after a
533
;   that such notification (except for the first one) can occur only after a
490
;   call to 'closemedia' callback.
534
;   call to 'closemedia' callback.
491
; * driver does not issue media insert notifications. In this case, the kernel
535
; * driver does not issue media insert notifications. In this case, the kernel
492
;   itself must sometimes check whether media is inserted. We have the flag
536
;   itself must sometimes check whether media is inserted. We have the flag
493
;   DISK.MediaUsed, visible to the kernel. This flag signals to the other parts
537
;   DISK.MediaUsed, visible to the kernel. This flag signals to the other parts
494
;   of kernel that the way is free.
538
;   of kernel that the way is free.
495
; In the first case other parts of the kernel do not use DISK.MediaUsed, so it
539
; In the first case other parts of the kernel do not use DISK.MediaUsed, so it
496
; does not matter when this flag is cleared. In the second case this flag must
540
; does not matter when this flag is cleared. In the second case this flag must
497
; be cleared after all other actions, including call to 'closemedia'.
541
; be cleared after all other actions, including call to 'closemedia'.
498
; 3a. Free all partitions.
542
; 3a. Free all partitions.
499
        push    esi edi
543
        push    esi edi
500
        mov     edi, [esi+DISK.NumPartitions]
544
        mov     edi, [esi+DISK.NumPartitions]
501
        mov     esi, [esi+DISK.Partitions]
545
        mov     esi, [esi+DISK.Partitions]
502
        test    edi, edi
546
        test    edi, edi
503
        jz      .nofree
547
        jz      .nofree
504
.freeloop:
548
.freeloop:
505
        lodsd
549
        lodsd
506
        mov     ecx, [eax+PARTITION.FSUserFunctions]
550
        mov     ecx, [eax+PARTITION.FSUserFunctions]
507
        call    dword [ecx]
551
        call    dword [ecx]
508
        dec     edi
552
        dec     edi
509
        jnz     .freeloop
553
        jnz     .freeloop
510
.nofree:
554
.nofree:
511
        pop     edi esi
555
        pop     edi esi
512
; 3b. Free the cache.
556
; 3b. Free the cache.
513
        call    disk_free_cache
557
        call    disk_free_cache
514
; 3c. Call the driver.
558
; 3c. Call the driver.
515
        mov     al, DISKFUNC.closemedia
559
        mov     al, DISKFUNC.closemedia
516
        stdcall disk_call_driver
560
        stdcall disk_call_driver
517
; 3d. Clear the flag.
561
; 3d. Clear the flag.
518
        mov     [esi+DISK.MediaUsed], 0
562
        mov     [esi+DISK.MediaUsed], 0
519
.nothing:
563
.nothing:
520
        ret
564
        ret
521
 
565
 
522
; This function is called by the driver and informs the kernel that the media
566
; This function is called by the driver and informs the kernel that the media
523
; has changed. If the media is non-removable, it is called exactly once
567
; has changed. If the media is non-removable, it is called exactly once
524
; immediately after 'disk_add' and once from 'disk_del'.
568
; immediately after 'disk_add' and once from 'disk_del'.
525
; Parameters:
569
; Parameters:
526
; [esp+4] = handle of the disk, i.e. the pointer to the DISK structure.
570
; [esp+4] = handle of the disk, i.e. the pointer to the DISK structure.
527
; [esp+8] = new status of the media: zero = no media, nonzero = media inserted.
571
; [esp+8] = new status of the media: zero = no media, nonzero = media inserted.
528
disk_media_changed:
572
disk_media_changed:
529
        push    ebx esi edi             ; save used registers to be stdcall
573
        push    ebx esi edi             ; save used registers to be stdcall
530
; 1. Remove the existing media, if it is present.
574
; 1. Remove the existing media, if it is present.
531
        mov     esi, [esp+4+12]         ; esi = pointer to DISK
575
        mov     esi, [esp+4+12]         ; esi = pointer to DISK
532
; 1a. Check whether it is present. Since DISK.MediaInserted is changed only
576
; 1a. Check whether it is present. Since DISK.MediaInserted is changed only
533
; in this function and calls to this function are synchronized, no lock is
577
; in this function and calls to this function are synchronized, no lock is
534
; required for checking.
578
; required for checking.
535
        cmp     [esi+DISK.MediaInserted], 0
579
        cmp     [esi+DISK.MediaInserted], 0
536
        jz      .noremove
580
        jz      .noremove
537
; We really need to remove the media.
581
; We really need to remove the media.
538
; 1b. Acquire mutex.
582
; 1b. Acquire mutex.
539
        lea     ecx, [esi+DISK.MediaLock]
583
        lea     ecx, [esi+DISK.MediaLock]
540
        call    mutex_lock
584
        call    mutex_lock
541
; 1c. Clear the flag.
585
; 1c. Clear the flag.
542
        mov     [esi+DISK.MediaInserted], 0
586
        mov     [esi+DISK.MediaInserted], 0
543
; 1d. Release mutex.
587
; 1d. Release mutex.
544
        call    mutex_unlock
588
        call    mutex_unlock
545
; 1e. Remove the "lifetime" reference and possibly destroy the structure.
589
; 1e. Remove the "lifetime" reference and possibly destroy the structure.
546
        call    disk_media_dereference
590
        call    disk_media_dereference
547
.noremove:
591
.noremove:
548
; 2. Test whether there is new media.
592
; 2. Test whether there is new media.
549
        cmp     dword [esp+8+12], 0
593
        cmp     dword [esp+8+12], 0
550
        jz      .noinsert
594
        jz      .noinsert
551
; Yep, there is.
595
; Yep, there is.
552
; 3. Process the new media. We assume that all media fields are available to
596
; 3. Process the new media. We assume that all media fields are available to
553
; use, see comments in 'disk_media_dereference' (this covers using by previous
597
; use, see comments in 'disk_media_dereference' (this covers using by previous
554
; media referencers) and note that calls to this function are synchronized
598
; media referencers) and note that calls to this function are synchronized
555
; (this covers using by new media referencers).
599
; (this covers using by new media referencers).
556
; 3a. Call the 'querymedia' callback.
600
; 3a. Call the 'querymedia' callback.
557
; .Flags are set to zero for possible future extensions.
601
; .Flags are set to zero for possible future extensions.
558
        lea     edx, [esi+DISK.MediaInfo]
602
        lea     edx, [esi+DISK.MediaInfo]
559
        and     [edx+DISKMEDIAINFO.Flags], 0
603
        and     [edx+DISKMEDIAINFO.Flags], 0
560
        mov     al, DISKFUNC.querymedia
604
        mov     al, DISKFUNC.querymedia
561
        stdcall disk_call_driver, edx
605
        stdcall disk_call_driver, edx
562
; 3b. Check the result of the callback. Abort if it failed.
606
; 3b. Check the result of the callback. Abort if it failed.
563
        test    eax, eax
607
        test    eax, eax
564
        jnz     .noinsert
608
        jnz     .noinsert
565
; 3c. Allocate the cache unless disabled by the driver. Abort if failed.
609
; 3c. Allocate the cache unless disabled by the driver. Abort if failed.
566
        call    disk_init_cache
610
        call    disk_init_cache
567
        test    al, al
611
        test    al, al
568
        jz      .noinsert
612
        jz      .noinsert
569
; 3d. Acquire the lifetime reference for the media object.
613
; 3d. Acquire the lifetime reference for the media object.
570
        inc     [esi+DISK.MediaRefCount]
614
        inc     [esi+DISK.MediaRefCount]
571
; 3e. Scan for partitions. Ignore result; the list of partitions is valid even
615
; 3e. Scan for partitions. Ignore result; the list of partitions is valid even
572
; on errors.
616
; on errors.
573
        call    disk_scan_partitions
617
        call    disk_scan_partitions
574
; 3f. Media is inserted and available for use.
618
; 3f. Media is inserted and available for use.
575
        inc     [esi+DISK.MediaInserted]
619
        inc     [esi+DISK.MediaInserted]
576
.noinsert:
620
.noinsert:
577
; 4. Return.
621
; 4. Return.
578
        pop     edi esi ebx             ; restore used registers to be stdcall
622
        pop     edi esi ebx             ; restore used registers to be stdcall
579
        ret     8                       ; purge 2 dword arguments to be stdcall
623
        ret     8                       ; purge 2 dword arguments to be stdcall
580
 
624
 
581
; This function is a thunk for all functions of a disk driver.
625
; This function is a thunk for all functions of a disk driver.
582
; It checks whether the referenced function is implemented in the driver.
626
; It checks whether the referenced function is implemented in the driver.
583
; If so, this function jumps to the function in the driver.
627
; If so, this function jumps to the function in the driver.
584
; Otherwise, it jumps to the default implementation.
628
; Otherwise, it jumps to the default implementation.
585
; al = offset of function in the DISKFUNC structure;
629
; al = offset of function in the DISKFUNC structure;
586
; esi = pointer to the DISK structure;
630
; esi = pointer to the DISK structure;
587
; stack is the same as for the corresponding function except that the
631
; stack is the same as for the corresponding function except that the
588
; first parameter (void* userdata) is prepended automatically.
632
; first parameter (void* userdata) is prepended automatically.
589
disk_call_driver:
633
disk_call_driver:
590
        movzx   eax, al ; eax = offset of function in the DISKFUNC structure
634
        movzx   eax, al ; eax = offset of function in the DISKFUNC structure
591
; 1. Prepend the first argument to the stack.
635
; 1. Prepend the first argument to the stack.
592
        pop     ecx     ; ecx = return address
636
        pop     ecx     ; ecx = return address
593
        push    [esi+DISK.UserData]     ; add argument
637
        push    [esi+DISK.UserData]     ; add argument
594
        push    ecx     ; save return address
638
        push    ecx     ; save return address
595
; 2. Check that the required function is inside the table. If not, go to 5.
639
; 2. Check that the required function is inside the table. If not, go to 5.
596
        mov     ecx, [esi+DISK.Functions]
640
        mov     ecx, [esi+DISK.Functions]
597
        cmp     eax, [ecx+DISKFUNC.strucsize]
641
        cmp     eax, [ecx+DISKFUNC.strucsize]
598
        jae     .default
642
        jae     .default
599
; 3. Check that the required function is implemented. If not, go to 5.
643
; 3. Check that the required function is implemented. If not, go to 5.
600
        mov     ecx, [ecx+eax]
644
        mov     ecx, [ecx+eax]
601
        test    ecx, ecx
645
        test    ecx, ecx
602
        jz      .default
646
        jz      .default
603
; 4. Jump to the required function.
647
; 4. Jump to the required function.
604
        jmp     ecx
648
        jmp     ecx
605
.default:
649
.default:
606
; 5. Driver does not implement the required function; use default implementation.
650
; 5. Driver does not implement the required function; use default implementation.
607
        jmp     dword [disk_default_callbacks+eax-4]
651
        jmp     dword [disk_default_callbacks+eax-4]
608
 
652
 
609
; The default implementation of DISKFUNC.querymedia.
653
; The default implementation of DISKFUNC.querymedia.
610
disk_default_querymedia:
654
disk_default_querymedia:
611
        movi    eax, DISK_STATUS_INVALID_CALL
655
        movi    eax, DISK_STATUS_INVALID_CALL
612
        ret     8
656
        ret     8
613
 
657
 
614
; The default implementation of DISKFUNC.read and DISKFUNC.write.
658
; The default implementation of DISKFUNC.read and DISKFUNC.write.
615
disk_default_read:
659
disk_default_read:
616
disk_default_write:
660
disk_default_write:
617
        movi    eax, DISK_STATUS_INVALID_CALL
661
        movi    eax, DISK_STATUS_INVALID_CALL
618
        ret     20
662
        ret     20
619
 
663
 
620
; The default implementation of DISKFUNC.close, DISKFUNC.closemedia and
664
; The default implementation of DISKFUNC.close, DISKFUNC.closemedia and
621
; DISKFUNC.flush.
665
; DISKFUNC.flush.
622
disk_default_close:
666
disk_default_close:
623
disk_default_closemedia:
667
disk_default_closemedia:
624
disk_default_flush:
668
disk_default_flush:
625
        xor     eax, eax
669
        xor     eax, eax
626
        ret     4
670
        ret     4
627
 
671
 
628
; The default implementation of DISKFUNC.adjust_cache_size.
672
; The default implementation of DISKFUNC.adjust_cache_size.
629
disk_default_adjust_cache_size:
673
disk_default_adjust_cache_size:
630
        mov     eax, [esp+8]
674
        mov     eax, [esp+8]
631
        ret     8
675
        ret     8
632
 
676
 
633
; This is an internal function called from 'disk_media_changed' when a new media
677
; This is an internal function called from 'disk_media_changed' when a new media
634
; is detected. It creates the list of partitions for the media.
678
; is detected. It creates the list of partitions for the media.
635
; If media is not partitioned, then the list consists of one partition which
679
; If media is not partitioned, then the list consists of one partition which
636
; covers all the media.
680
; covers all the media.
637
; esi = pointer to the DISK structure.
681
; esi = pointer to the DISK structure.
638
disk_scan_partitions:
682
disk_scan_partitions:
639
; 1. Initialize .NumPartitions and .Partitions fields as zeros: empty list.
683
; 1. Initialize .NumPartitions and .Partitions fields as zeros: empty list.
640
        and     [esi+DISK.NumPartitions], 0
684
        and     [esi+DISK.NumPartitions], 0
641
        and     [esi+DISK.Partitions], 0
685
        and     [esi+DISK.Partitions], 0
642
; 2. Acquire the buffer for MBR and bootsector tests. See the comment before
686
; 2. Acquire the buffer for MBR and bootsector tests. See the comment before
643
; the 'partition_buffer_users' variable.
687
; the 'partition_buffer_users' variable.
644
        mov     eax, [esi+DISK.MediaInfo.SectorSize]
688
        mov     eax, [esi+DISK.MediaInfo.SectorSize]
645
        cmp     eax, 512
689
        cmp     eax, 512
646
        jnz     @f
690
        jnz     @f
647
        mov     ebx, mbr_buffer         ; assume the global buffer is free
691
        mov     ebx, mbr_buffer         ; assume the global buffer is free
648
        lock inc [partition_buffer_users]
692
        lock inc [partition_buffer_users]
649
        jz      .buffer_acquired        ; yes, it is free
693
        jz      .buffer_acquired        ; yes, it is free
650
        lock dec [partition_buffer_users]       ; no, we must allocate
694
        lock dec [partition_buffer_users]       ; no, we must allocate
651
@@:
695
@@:
652
        lea     eax, [eax*3]
696
        lea     eax, [eax*3]
653
        stdcall kernel_alloc, eax
697
        stdcall kernel_alloc, eax
654
        test    eax, eax
698
        test    eax, eax
655
        jz      .nothing
699
        jz      .nothing
656
        xchg    eax, ebx
700
        xchg    eax, ebx
657
.buffer_acquired:
701
.buffer_acquired:
658
; MBR/EBRs are organized in the chain. We use a loop over MBR/EBRs, but no
702
; MBR/EBRs are organized in the chain. We use a loop over MBR/EBRs, but no
659
; more than MAX_NUM_PARTITION times.
703
; more than MAX_NUM_PARTITION times.
660
; 3. Prepare things for the loop.
704
; 3. Prepare things for the loop.
661
; ebp will hold the sector number for current MBR/EBR.
705
; ebp will hold the sector number for current MBR/EBR.
662
; [esp] will hold the sector number for current extended partition, if there
706
; [esp] will hold the sector number for current extended partition, if there
663
; is one.
707
; is one.
664
; [esp+4] will hold the counter that prevents long loops.
708
; [esp+4] will hold the counter that prevents long loops.
665
        push    ebp             ; save ebp
709
        push    ebp             ; save ebp
666
        push    MAX_NUM_PARTITIONS      ; the counter of max MBRs to process
710
        push    MAX_NUM_PARTITIONS      ; the counter of max MBRs to process
667
        xor     ebp, ebp        ; start from sector zero
711
        xor     ebp, ebp        ; start from sector zero
668
        push    ebp             ; no extended partition yet
712
        push    ebp             ; no extended partition yet
669
; 4. MBR is 512 bytes long. If sector size is less than 512 bytes,
713
; 4. MBR is 512 bytes long. If sector size is less than 512 bytes,
670
; assume no MBR, no partitions and go to 10.
714
; assume no MBR, no partitions and go to 11.
671
        cmp     [esi+DISK.MediaInfo.SectorSize], 512
715
        cmp     [esi+DISK.MediaInfo.SectorSize], 512
672
        jb      .notmbr
716
        jb      .notmbr
673
.new_mbr:
717
.new_mbr:
674
; 5. Read the current sector.
718
; 5. Read the current sector.
675
; Note that 'read' callback operates with 64-bit sector numbers, so we must
719
; Note that 'read' callback operates with 64-bit sector numbers, so we must
676
; push additional zero as a high dword of sector number.
720
; push additional zero as a high dword of sector number.
677
        mov     al, DISKFUNC.read
721
        mov     al, DISKFUNC.read
678
        push    1
722
        push    1
679
        stdcall disk_call_driver, ebx, ebp, 0, esp
723
        stdcall disk_call_driver, ebx, ebp, 0, esp
680
        pop     ecx
724
        pop     ecx
681
; 6. If the read has failed, abort the loop.
725
; 6. If the read has failed, abort the loop.
682
        dec     ecx
726
        dec     ecx
683
        jnz     .mbr_failed
727
        jnz     .mbr_failed
684
; 7. Check the MBR/EBR signature. If it is wrong, abort the loop.
728
; 7. Check the MBR/EBR signature. If it is wrong, abort the loop.
685
; Soon we will access the partition table which starts at ebx+0x1BE,
729
; Soon we will access the partition table which starts at ebx+0x1BE,
686
; so we can fill its address right now. If we do it now, then the addressing
730
; so we can fill its address right now. If we do it now, then the addressing
687
; [ecx+0x40] is shorter than [ebx+0x1fe]: one-byte offset vs 4-bytes offset.
731
; [ecx+0x40] is shorter than [ebx+0x1fe]: one-byte offset vs 4-bytes offset.
688
        lea     ecx, [ebx+0x1be]        ; ecx -> partition table
732
        lea     ecx, [ebx+0x1be]        ; ecx -> partition table
689
        cmp     word [ecx+0x40], 0xaa55
733
        cmp     word [ecx+0x40], 0xaa55
690
        jnz     .mbr_failed
734
        jnz     .mbr_failed
691
; 8. The MBR is treated differently from EBRs. For MBR we additionally need to
735
; 8. The MBR is treated differently from EBRs. For MBR we additionally need to
692
; execute step 9 and possibly step 10.
736
; execute step 10 and possibly step 11.
693
        test    ebp, ebp
737
        test    ebp, ebp
694
        jnz     .mbr
738
        jnz     .mbr
-
 
739
; 9. Handle GUID Partition Table
-
 
740
; 9a. Check if MBR is protective
-
 
741
        call    is_protective_mbr
-
 
742
        jnz     .no_gpt
-
 
743
; 9b. If so, try to scan GPT headers
-
 
744
        call    disk_scan_gpt
-
 
745
; 9c. If any GPT header is valid, ignore MBR
-
 
746
        jz      .done
-
 
747
; Otherwise process legacy/protective MBR
-
 
748
.no_gpt:
695
; The partition table can be present or not present. In the first case, we just
749
; The partition table can be present or not present. In the first case, we just
696
; read the MBR. In the second case, we just read the bootsector for a
750
; read the MBR. In the second case, we just read the bootsector for a
697
; filesystem.
751
; filesystem.
698
; The following algorithm is used to distinguish between these cases.
752
; The following algorithm is used to distinguish between these cases.
699
; A. If at least one entry of the partition table is invalid, this is
753
; A. If at least one entry of the partition table is invalid, this is
700
;    a bootsector. See the description of 'is_partition_table_entry' for
754
;    a bootsector. See the description of 'is_partition_table_entry' for
701
;    definition of validity.
755
;    definition of validity.
702
; B. If all entries are empty (filesystem type field is zero) and the first
756
; B. If all entries are empty (filesystem type field is zero) and the first
703
;    byte is jmp opcode (0EBh or 0E9h), this is a bootsector which happens to
757
;    byte is jmp opcode (0EBh or 0E9h), this is a bootsector which happens to
704
;    have zeros in the place of partition table.
758
;    have zeros in the place of partition table.
705
; C. Otherwise, this is an MBR.
759
; C. Otherwise, this is an MBR.
706
; 9. Test for MBR vs bootsector.
760
; 10. Test for MBR vs bootsector.
707
; 9a. Check entries. If any is invalid, go to 10 (rule A).
761
; 10a. Check entries. If any is invalid, go to 11 (rule A).
708
        call    is_partition_table_entry
762
        call    is_partition_table_entry
709
        jc      .notmbr
763
        jc      .notmbr
710
        add     ecx, 10h
764
        add     ecx, 10h
711
        call    is_partition_table_entry
765
        call    is_partition_table_entry
712
        jc      .notmbr
766
        jc      .notmbr
713
        add     ecx, 10h
767
        add     ecx, 10h
714
        call    is_partition_table_entry
768
        call    is_partition_table_entry
715
        jc      .notmbr
769
        jc      .notmbr
716
        add     ecx, 10h
770
        add     ecx, 10h
717
        call    is_partition_table_entry
771
        call    is_partition_table_entry
718
        jc      .notmbr
772
        jc      .notmbr
719
; 9b. Check types of the entries. If at least one is nonzero, go to 11 (rule C).
773
; 10b. Check types of the entries. If at least one is nonzero, go to 12 (rule C).
720
        mov     al, [ecx-30h+PARTITION_TABLE_ENTRY.Type]
774
        mov     al, [ecx-30h+PARTITION_TABLE_ENTRY.Type]
721
        or      al, [ecx-20h+PARTITION_TABLE_ENTRY.Type]
775
        or      al, [ecx-20h+PARTITION_TABLE_ENTRY.Type]
722
        or      al, [ecx-10h+PARTITION_TABLE_ENTRY.Type]
776
        or      al, [ecx-10h+PARTITION_TABLE_ENTRY.Type]
723
        or      al, [ecx+PARTITION_TABLE_ENTRY.Type]
777
        or      al, [ecx+PARTITION_TABLE_ENTRY.Type]
724
        jnz     .mbr
778
        jnz     .mbr
725
; 9c. Empty partition table or bootsector with many zeroes? (rule B)
779
; 10c. Empty partition table or bootsector with many zeroes? (rule B)
726
        cmp     byte [ebx], 0EBh
780
        cmp     byte [ebx], 0EBh
727
        jz      .notmbr
781
        jz      .notmbr
728
        cmp     byte [ebx], 0E9h
782
        cmp     byte [ebx], 0E9h
729
        jnz     .mbr
783
        jnz     .mbr
730
.notmbr:
784
.notmbr:
731
; 10. This is not an  MBR. The media is not partitioned. Create one partition
785
; 11. This is not an  MBR. The media is not partitioned. Create one partition
732
; which covers all the media and abort the loop.
786
; which covers all the media and abort the loop.
733
        stdcall disk_add_partition, 0, 0, \
787
        stdcall disk_add_partition, 0, 0, \
734
                dword [esi+DISK.MediaInfo.Capacity], dword [esi+DISK.MediaInfo.Capacity+4], esi
788
                dword [esi+DISK.MediaInfo.Capacity], dword [esi+DISK.MediaInfo.Capacity+4], esi
735
        jmp     .done
789
        jmp     .done
736
.mbr:
790
.mbr:
737
; 11. Process all entries of the new MBR/EBR
791
; 12. Process all entries of the new MBR/EBR
738
        lea     ecx, [ebx+0x1be]        ; ecx -> partition table
792
        lea     ecx, [ebx+0x1be]        ; ecx -> partition table
739
        push    0       ; assume no extended partition
793
        push    0       ; assume no extended partition
740
        call    process_partition_table_entry
794
        call    process_partition_table_entry
741
        add     ecx, 10h
795
        add     ecx, 10h
742
        call    process_partition_table_entry
796
        call    process_partition_table_entry
743
        add     ecx, 10h
797
        add     ecx, 10h
744
        call    process_partition_table_entry
798
        call    process_partition_table_entry
745
        add     ecx, 10h
799
        add     ecx, 10h
746
        call    process_partition_table_entry
800
        call    process_partition_table_entry
747
        pop     ebp
801
        pop     ebp
748
; 12. Test whether we found a new EBR and should continue the loop.
802
; 13. Test whether we found a new EBR and should continue the loop.
749
; 12a. If there was no next EBR, return.
803
; 13a. If there was no next EBR, return.
750
        test    ebp, ebp
804
        test    ebp, ebp
751
        jz      .done
805
        jz      .done
752
; Ok, we have EBR.
806
; Ok, we have EBR.
753
; 12b. EBRs addresses are relative to the start of extended partition.
807
; 13b. EBRs addresses are relative to the start of extended partition.
754
; For simplicity, just abort if an 32-bit overflow occurs; large disks
808
; For simplicity, just abort if an 32-bit overflow occurs; large disks
755
; are most likely partitioned with GPT, not MBR scheme, since the precise
809
; are most likely partitioned with GPT, not MBR scheme, since the precise
756
; calculation here would increase limit just twice at the price of big
810
; calculation here would increase limit just twice at the price of big
757
; compatibility problems.
811
; compatibility problems.
758
        pop     eax     ; load extended partition
812
        pop     eax     ; load extended partition
759
        add     ebp, eax
813
        add     ebp, eax
760
        jc      .mbr_failed
814
        jc      .mbr_failed
761
; 12c. If extended partition has not yet started, start it.
815
; 13c. If extended partition has not yet started, start it.
762
        test    eax, eax
816
        test    eax, eax
763
        jnz     @f
817
        jnz     @f
764
        mov     eax, ebp
818
        mov     eax, ebp
765
@@:
819
@@:
766
; 12c. If the limit is not exceeded, continue the loop.
820
; 13d. If the limit is not exceeded, continue the loop.
767
        dec     dword [esp]
821
        dec     dword [esp]
768
        push    eax     ; store extended partition
822
        push    eax     ; store extended partition
769
        jnz     .new_mbr
823
        jnz     .new_mbr
770
.mbr_failed:
824
.mbr_failed:
771
.done:
825
.done:
772
; 13. Cleanup after the loop.
826
; 14. Cleanup after the loop.
773
        pop     eax     ; not important anymore
827
        pop     eax     ; not important anymore
774
        pop     eax     ; not important anymore
828
        pop     eax     ; not important anymore
775
        pop     ebp     ; restore ebp
829
        pop     ebp     ; restore ebp
776
; 14. Release the buffer.
830
; 15. Release the buffer.
777
; 14a. Test whether it is the global buffer or we have allocated it.
831
; 15a. Test whether it is the global buffer or we have allocated it.
778
        cmp     ebx, mbr_buffer
832
        cmp     ebx, mbr_buffer
779
        jz      .release_partition_buffer
833
        jz      .release_partition_buffer
780
; 14b. If we have allocated it, free it.
834
; 15b. If we have allocated it, free it.
781
        xchg    eax, ebx
835
        xchg    eax, ebx
782
        call    free
836
        call    free
783
        jmp     .nothing
837
        jmp     .nothing
784
; 14c. Otherwise, release reference.
838
; 15c. Otherwise, release reference.
785
.release_partition_buffer:
839
.release_partition_buffer:
786
        lock dec [partition_buffer_users]
840
        lock dec [partition_buffer_users]
787
.nothing:
841
.nothing:
788
; 15. Return.
842
; 16. Return.
-
 
843
        ret
-
 
844
 
-
 
845
 
-
 
846
; This function is called from disk_scan_partitions to validate and parse
-
 
847
; primary and backup GPTs.
-
 
848
proc disk_scan_gpt
-
 
849
; Scan primary GPT (second sector)
-
 
850
        stdcall scan_gpt, 1, 0
-
 
851
        test    eax, eax
-
 
852
; There is no code to restore backup GPT if it's corrupt.
-
 
853
; Therefore just exit if Primary GPT has been parsed successfully.
-
 
854
        jz      .exit
-
 
855
        DEBUGF  1, 'K : Primary GPT is corrupt, trying backup one\n'
-
 
856
        mov     eax, dword[esi+DISK.MediaInfo.Capacity+0]
-
 
857
        mov     edx, dword[esi+DISK.MediaInfo.Capacity+4]
-
 
858
        sub     eax, 1
-
 
859
        sbb     edx, 0
-
 
860
; Scan backup GPT (last sector)
-
 
861
        stdcall scan_gpt, eax, edx
-
 
862
        test    eax, eax
-
 
863
        jz      .exit
-
 
864
        DEBUGF  1, 'K : Backup GPT is also corrupt, fallback to legacy MBR\n'
-
 
865
.exit:
-
 
866
; Return value is ZF
-
 
867
        ret
-
 
868
endp
-
 
869
 
-
 
870
 
-
 
871
; This function is called from disk_scan_gpt to process a single GPT.
-
 
872
proc scan_gpt _mylba:qword
-
 
873
locals
-
 
874
        GPEA_len dd ?   ; Length of GPT Partition Entry Array in bytes
-
 
875
endl
-
 
876
        push    ebx edi
-
 
877
; Allocalte memory for GPT header
-
 
878
        mov     eax, [esi+DISK.MediaInfo.SectorSize]
-
 
879
        stdcall kernel_alloc, eax
-
 
880
        test    eax, eax
-
 
881
        jz      .fail
-
 
882
; Save pointer to stack, just in case
-
 
883
        push    eax
-
 
884
        mov     ebx, eax
-
 
885
; Read GPT header
-
 
886
        mov     al, DISKFUNC.read
-
 
887
        push    1
-
 
888
        stdcall disk_call_driver, ebx, dword[_mylba+0], dword[_mylba+4], esp
-
 
889
        pop     ecx
-
 
890
        test    eax, eax
-
 
891
        jnz     .fail_free_gpt
-
 
892
; Check signature
-
 
893
        cmp     dword[ebx+GPTH.Signature+0], 'EFI '
-
 
894
        jnz     .fail_free_gpt
-
 
895
        cmp     dword[ebx+GPTH.Signature+4], 'PART'
-
 
896
        jnz     .fail_free_gpt
-
 
897
; Check Revision
-
 
898
        cmp     [ebx+GPTH.Revision], 0x00010000
-
 
899
        jnz     .fail_free_gpt
-
 
900
; Compute and check CRC32
-
 
901
        xor     edx, edx
-
 
902
        xchg    edx, [ebx+GPTH.HeaderCRC32]
-
 
903
        mov     eax, -1
-
 
904
        stdcall crc_32, 0xEDB88320, ebx, [ebx+GPTH.HeaderSize]
-
 
905
        xor     eax, -1
-
 
906
        cmp     eax, edx
-
 
907
        jnz     .fail_free_gpt
-
 
908
; Reserved must be zero
-
 
909
        cmp     [ebx+GPTH.Reserved], 0
-
 
910
        jnz     .fail_free_gpt
-
 
911
; MyLBA of GPT header at LBA X must equal X
-
 
912
        mov     eax, dword[ebx+GPTH.MyLBA+0]
-
 
913
        mov     edx, dword[ebx+GPTH.MyLBA+4]
-
 
914
        cmp     eax, dword[_mylba+0]
-
 
915
        jnz     .fail_free_gpt
-
 
916
        cmp     edx, dword[_mylba+4]
-
 
917
        jnz     .fail_free_gpt
-
 
918
; Capacity - MyLBA = AlternateLBA
-
 
919
        mov     eax, dword[esi+DISK.MediaInfo.Capacity+0]
-
 
920
        mov     edx, dword[esi+DISK.MediaInfo.Capacity+4]
-
 
921
        sub     eax, dword[_mylba+0]
-
 
922
        sbb     edx, dword[_mylba+4]
-
 
923
        cmp     eax, dword[ebx+GPTH.AlternateLBA+0]
-
 
924
; DISK.MediaInfo.Capacity is -1 for ATA devices, disable this check for now.
-
 
925
;        jnz     .fail_free_gpt
-
 
926
        cmp     edx, dword[ebx+GPTH.AlternateLBA+4]
-
 
927
;        jnz     .fail_free_gpt
-
 
928
 
-
 
929
; Compute GPT Partition Entry Array (GPEA) length in bytes
-
 
930
        mov     eax, [ebx+GPTH.NumberOfPartitionEntries]
-
 
931
        mul     [ebx+GPTH.SizeOfPartitionEntry]
-
 
932
        test    edx, edx        ; far too big
-
 
933
        jnz     .fail_free_gpt
-
 
934
; Round up to sector boundary
-
 
935
        mov     ecx, [esi+DISK.MediaInfo.SectorSize]    ; power of two
-
 
936
        dec     ecx
-
 
937
        add     eax, ecx
-
 
938
        jc      .fail_free_gpt  ; too big
-
 
939
        not     ecx
-
 
940
        and     eax, ecx
-
 
941
; We will need this length to compute CRC32 of GPEA
-
 
942
        mov     [GPEA_len], eax
-
 
943
; Allocate memory for GPEA
-
 
944
        stdcall kernel_alloc, eax
-
 
945
        test    eax, eax
-
 
946
        jz      .fail_free_gpt
-
 
947
; Save to not juggle with registers
-
 
948
        push    eax
-
 
949
        mov     edi, eax
-
 
950
        mov     eax, [GPEA_len]
-
 
951
        xor     edx, edx
-
 
952
; Get the number of sectors GPEA fits into
-
 
953
        div     [esi+DISK.MediaInfo.SectorSize]
-
 
954
        push    eax     ; esp = pointer to the number of sectors
-
 
955
        mov     al, DISKFUNC.read
-
 
956
        stdcall disk_call_driver, edi, dword[ebx+GPTH.PartitionEntryLBA+0], \
-
 
957
                dword[ebx+GPTH.PartitionEntryLBA+4], esp
-
 
958
        pop     ecx
-
 
959
        test    eax, eax
-
 
960
        jnz     .fail_free_gpea_gpt
-
 
961
; Compute and check CRC32 of GPEA
-
 
962
        mov     edx, [ebx+GPTH.PartitionEntryArrayCRC32]
-
 
963
        mov     eax, -1
-
 
964
        stdcall crc_32, 0xEDB88320, edi, [GPEA_len]
-
 
965
        xor     eax, -1
-
 
966
        cmp     eax, edx
-
 
967
        jnz     .fail_free_gpea_gpt
-
 
968
 
-
 
969
; Process partitions, skip zeroed ones.
-
 
970
.next_gpe:
-
 
971
        xor     eax, eax
-
 
972
        mov     ecx, [ebx+GPTH.SizeOfPartitionEntry]
-
 
973
        repz scasb
-
 
974
        jz      .skip
-
 
975
        add     edi, ecx
-
 
976
        sub     edi, [ebx+GPTH.SizeOfPartitionEntry]
-
 
977
; Length of a partition in sectors is EndingLBA - StartingLBA + 1
-
 
978
        mov     eax, dword[edi+GPE.EndingLBA+0]
-
 
979
        mov     edx, dword[edi+GPE.EndingLBA+4]
-
 
980
        sub     eax, dword[edi+GPE.StartingLBA+0]
-
 
981
        sbb     edx, dword[edi+GPE.StartingLBA+4]
-
 
982
        add     eax, 1
-
 
983
        adc     edx, 0
-
 
984
        stdcall disk_add_partition, dword[edi+GPE.StartingLBA+0], \
-
 
985
                dword[edi+GPE.StartingLBA+4], eax, edx, esi
-
 
986
        add     edi, [ebx+GPTH.SizeOfPartitionEntry]
-
 
987
.skip:
-
 
988
        dec     [ebx+GPTH.NumberOfPartitionEntries]
-
 
989
        jnz     .next_gpe
-
 
990
 
-
 
991
; Pointers to GPT header and GPEA are on the stack
-
 
992
        stdcall kernel_free
-
 
993
        stdcall kernel_free
-
 
994
        pop     edi ebx
-
 
995
        xor     eax, eax
-
 
996
        ret
-
 
997
.fail_free_gpea_gpt:
-
 
998
        stdcall kernel_free
-
 
999
.fail_free_gpt:
-
 
1000
        stdcall kernel_free
-
 
1001
.fail:
-
 
1002
        pop     edi ebx
-
 
1003
        xor     eax, eax
-
 
1004
        inc     eax
-
 
1005
        ret
-
 
1006
endp
-
 
1007
 
-
 
1008
; ecx = pointer to partition records array (MBR + 446)
-
 
1009
is_protective_mbr:
-
 
1010
        push    ecx edi
-
 
1011
        xor     eax, eax
-
 
1012
        cmp     [ecx-6], eax
-
 
1013
        jnz     .exit
-
 
1014
        cmp     [ecx-2], eax
-
 
1015
        jnz     .exit
-
 
1016
; Partition record 0 has specific fields
-
 
1017
        cmp     dword[ecx+0], 0x00020000
-
 
1018
        jnz     .exit
-
 
1019
        cmp     byte[ecx+4], 0xEE
-
 
1020
        jnz     .exit
-
 
1021
        cmp     dword[ecx+8], 1
-
 
1022
        jnz     .exit
-
 
1023
; DISK.MediaInfo.Capacity is -1 for ATA devices, disable this check for now.
-
 
1024
;        cmp     dword[esi+DISK.MediaInfo.Capacity+4], eax
-
 
1025
;        mov     edi, 0xFFFFFFFF
-
 
1026
;        jnz     @f
-
 
1027
;        mov     edi, dword[esi+DISK.MediaInfo.Capacity+0]
-
 
1028
;        dec     edi
-
 
1029
;@@:
-
 
1030
;        cmp     dword[ecx+12], edi
-
 
1031
;        jnz     .exit
-
 
1032
 
-
 
1033
; Check that partition records 1-3 are filled with zero
-
 
1034
        lea     edi, [ecx+16]
-
 
1035
        mov     ecx, 16*3/2     ; 3 partitions
-
 
1036
        repz scasw
-
 
1037
.exit:
-
 
1038
        pop     edi ecx
-
 
1039
; Return value is ZF
789
        ret
1040
        ret
790
 
1041
 
791
; This is an internal function called from disk_scan_partitions. It checks
1042
; This is an internal function called from disk_scan_partitions. It checks
792
; whether the entry pointed to by ecx is a valid entry of partition table.
1043
; whether the entry pointed to by ecx is a valid entry of partition table.
793
; The entry is valid if the first byte is 0 or 80h, the first sector plus the
1044
; The entry is valid if the first byte is 0 or 80h, the first sector plus the
794
; length is less than twice the size of media. Multiplication by two is
1045
; length is less than twice the size of media. Multiplication by two is
795
; required since the size mentioned in the partition table can be slightly
1046
; required since the size mentioned in the partition table can be slightly
796
; greater than the real size.
1047
; greater than the real size.
797
is_partition_table_entry:
1048
is_partition_table_entry:
798
; 1. Check .Bootable field.
1049
; 1. Check .Bootable field.
799
        mov     al, [ecx+PARTITION_TABLE_ENTRY.Bootable]
1050
        mov     al, [ecx+PARTITION_TABLE_ENTRY.Bootable]
800
        and     al, 7Fh
1051
        and     al, 7Fh
801
        jnz     .invalid
1052
        jnz     .invalid
802
; 3. Calculate first sector + length. Note that .FirstAbsSector is relative
1053
; 3. Calculate first sector + length. Note that .FirstAbsSector is relative
803
; to the MBR/EBR, so the real sum is ebp + .FirstAbsSector + .Length.
1054
; to the MBR/EBR, so the real sum is ebp + .FirstAbsSector + .Length.
804
        mov     eax, ebp
1055
        mov     eax, ebp
805
        xor     edx, edx
1056
        xor     edx, edx
806
        add     eax, [ecx+PARTITION_TABLE_ENTRY.FirstAbsSector]
1057
        add     eax, [ecx+PARTITION_TABLE_ENTRY.FirstAbsSector]
807
        adc     edx, 0
1058
        adc     edx, 0
808
        add     eax, [ecx+PARTITION_TABLE_ENTRY.Length]
1059
        add     eax, [ecx+PARTITION_TABLE_ENTRY.Length]
809
        adc     edx, 0
1060
        adc     edx, 0
810
; 4. Divide by two.
1061
; 4. Divide by two.
811
        shr     edx, 1
1062
        shr     edx, 1
812
        rcr     eax, 1
1063
        rcr     eax, 1
813
; 5. Compare with capacity. If the subtraction (edx:eax) - .Capacity does not
1064
; 5. Compare with capacity. If the subtraction (edx:eax) - .Capacity does not
814
; overflow, this is bad.
1065
; overflow, this is bad.
815
        sub     eax, dword [esi+DISK.MediaInfo.Capacity]
1066
        sub     eax, dword [esi+DISK.MediaInfo.Capacity]
816
        sbb     edx, dword [esi+DISK.MediaInfo.Capacity+4]
1067
        sbb     edx, dword [esi+DISK.MediaInfo.Capacity+4]
817
        jnc     .invalid
1068
        jnc     .invalid
818
.valid:
1069
.valid:
819
; 5. Return success: CF is cleared.
1070
; 5. Return success: CF is cleared.
820
        clc
1071
        clc
821
        ret
1072
        ret
822
.invalid:
1073
.invalid:
823
; 6. Return fail: CF is set.
1074
; 6. Return fail: CF is set.
824
        stc
1075
        stc
825
        ret
1076
        ret
826
 
1077
 
827
; This is an internal function called from disk_scan_partitions. It processes
1078
; This is an internal function called from disk_scan_partitions. It processes
828
; the entry pointed to by ecx.
1079
; the entry pointed to by ecx.
829
; * If the entry is invalid, just ignore this entry.
1080
; * If the entry is invalid, just ignore this entry.
830
; * If the type is zero, just ignore this entry.
1081
; * If the type is zero, just ignore this entry.
831
; * If the type is one of types for extended partition, store the address
1082
; * If the type is one of types for extended partition, store the address
832
;   of this partition as the new MBR in [esp+4].
1083
;   of this partition as the new MBR in [esp+4].
833
; * Otherwise, add the partition to the list of partitions for this disk.
1084
; * Otherwise, add the partition to the list of partitions for this disk.
834
;   We don't use the type from the entry to identify the file system;
1085
;   We don't use the type from the entry to identify the file system;
835
;   fs-specific checks do this more reliably.
1086
;   fs-specific checks do this more reliably.
836
process_partition_table_entry:
1087
process_partition_table_entry:
837
; 1. Check for valid entry. If invalid, return (go to 5).
1088
; 1. Check for valid entry. If invalid, return (go to 5).
838
        call    is_partition_table_entry
1089
        call    is_partition_table_entry
839
        jc      .nothing
1090
        jc      .nothing
840
; 2. Check for empty entry. If invalid, return (go to 5).
1091
; 2. Check for empty entry. If invalid, return (go to 5).
841
        mov     al, [ecx+PARTITION_TABLE_ENTRY.Type]
1092
        mov     al, [ecx+PARTITION_TABLE_ENTRY.Type]
842
        test    al, al
1093
        test    al, al
843
        jz      .nothing
1094
        jz      .nothing
844
; 3. Check for extended partition. If extended, go to 6.
1095
; 3. Check for extended partition. If extended, go to 6.
845
irp type,\
1096
irp type,\
846
    0x05,\                 ; DOS: extended partition
1097
    0x05,\                 ; DOS: extended partition
847
    0x0f,\                 ; WIN95: extended partition, LBA-mapped
1098
    0x0f,\                 ; WIN95: extended partition, LBA-mapped
848
    0xc5,\                 ; DRDOS/secured: extended partition
1099
    0xc5,\                 ; DRDOS/secured: extended partition
849
    0xd5                   ; Old Multiuser DOS secured: extended partition
1100
    0xd5                   ; Old Multiuser DOS secured: extended partition
850
{
1101
{
851
        cmp     al, type
1102
        cmp     al, type
852
        jz      .extended
1103
        jz      .extended
853
}
1104
}
854
; 4. If we are here, that is a normal partition. Add it to the list.
1105
; 4. If we are here, that is a normal partition. Add it to the list.
855
; Note that the first sector is relative to MBR/EBR.
1106
; Note that the first sector is relative to MBR/EBR.
856
        mov     eax, ebp
1107
        mov     eax, ebp
857
        xor     edx, edx
1108
        xor     edx, edx
858
        add     eax, [ecx+PARTITION_TABLE_ENTRY.FirstAbsSector]
1109
        add     eax, [ecx+PARTITION_TABLE_ENTRY.FirstAbsSector]
859
        adc     edx, 0
1110
        adc     edx, 0
860
        push    ecx
1111
        push    ecx
861
        stdcall disk_add_partition, eax, edx, \
1112
        stdcall disk_add_partition, eax, edx, \
862
                [ecx+PARTITION_TABLE_ENTRY.Length], 0, esi
1113
                [ecx+PARTITION_TABLE_ENTRY.Length], 0, esi
863
        pop     ecx
1114
        pop     ecx
864
.nothing:
1115
.nothing:
865
; 5. Return.
1116
; 5. Return.
866
        ret
1117
        ret
867
.extended:
1118
.extended:
868
; 6. If we are here, that is an extended partition. Store the address.
1119
; 6. If we are here, that is an extended partition. Store the address.
869
        mov     eax, [ecx+PARTITION_TABLE_ENTRY.FirstAbsSector]
1120
        mov     eax, [ecx+PARTITION_TABLE_ENTRY.FirstAbsSector]
870
        mov     [esp+4], eax
1121
        mov     [esp+4], eax
871
        ret
1122
        ret
872
 
1123
 
873
; This is an internal function called from disk_scan_partitions and
1124
; This is an internal function called from disk_scan_partitions and
874
; process_partition_table_entry. It adds one partition to the list of
1125
; process_partition_table_entry. It adds one partition to the list of
875
; partitions for the media.
1126
; partitions for the media.
876
; Important note: start, length, disk MUST be present and
1127
; Important note: start, length, disk MUST be present and
877
; MUST be in the same order as in PARTITION structure.
1128
; MUST be in the same order as in PARTITION structure.
878
; esi duplicates [disk].
1129
; esi duplicates [disk].
879
proc disk_add_partition stdcall uses ebx edi, start:qword, length:qword, disk:dword
1130
proc disk_add_partition stdcall uses ebx edi, start:qword, length:qword, disk:dword
880
; 1. Check that this partition will not exceed the limit on total number.
1131
; 1. Check that this partition will not exceed the limit on total number.
881
        cmp     [esi+DISK.NumPartitions], MAX_NUM_PARTITIONS
1132
        cmp     [esi+DISK.NumPartitions], MAX_NUM_PARTITIONS
882
        jae     .nothing
1133
        jae     .nothing
883
; 2. Check that this partition does not overlap with any already registered
1134
; 2. Check that this partition does not overlap with any already registered
884
; partition. Since any file system assumes that the disk data will not change
1135
; partition. Since any file system assumes that the disk data will not change
885
; outside of its control, such overlap could be destructive.
1136
; outside of its control, such overlap could be destructive.
886
; Since the number of partitions is usually very small and is guaranteed not
1137
; Since the number of partitions is usually very small and is guaranteed not
887
; to be large, the simple linear search is sufficient.
1138
; to be large, the simple linear search is sufficient.
888
; 2a. Prepare the loop: edi will point to the current item of .Partitions
1139
; 2a. Prepare the loop: edi will point to the current item of .Partitions
889
; array, ecx will be the current item, ebx will hold number of items left.
1140
; array, ecx will be the current item, ebx will hold number of items left.
890
        mov     edi, [esi+DISK.Partitions]
1141
        mov     edi, [esi+DISK.Partitions]
891
        mov     ebx, [esi+DISK.NumPartitions]
1142
        mov     ebx, [esi+DISK.NumPartitions]
892
        test    ebx, ebx
1143
        test    ebx, ebx
893
        jz      .partitionok
1144
        jz      .partitionok
894
.scan_existing:
1145
.scan_existing:
895
; 2b. Get the next partition.
1146
; 2b. Get the next partition.
896
        mov     ecx, [edi]
1147
        mov     ecx, [edi]
897
        add     edi, 4
1148
        add     edi, 4
898
; The range [.FirstSector, .FirstSector+.Length) must be either entirely to
1149
; The range [.FirstSector, .FirstSector+.Length) must be either entirely to
899
; the left of [start, start+length) or entirely to the right.
1150
; the left of [start, start+length) or entirely to the right.
900
; 2c. Subtract .FirstSector - start. The possible overflow distinguish between
1151
; 2c. Subtract .FirstSector - start. The possible overflow distinguish between
901
; cases "to the left" (2e) and "to the right" (2d).
1152
; cases "to the left" (2e) and "to the right" (2d).
902
        mov     eax, dword [ecx+PARTITION.FirstSector]
1153
        mov     eax, dword [ecx+PARTITION.FirstSector]
903
        mov     edx, dword [ecx+PARTITION.FirstSector+4]
1154
        mov     edx, dword [ecx+PARTITION.FirstSector+4]
904
        sub     eax, dword [start]
1155
        sub     eax, dword [start]
905
        sbb     edx, dword [start+4]
1156
        sbb     edx, dword [start+4]
906
        jb      .less
1157
        jb      .less
907
; 2d. .FirstSector is greater than or equal to start. Check that .FirstSector
1158
; 2d. .FirstSector is greater than or equal to start. Check that .FirstSector
908
; is greater than or equal to start+length; the subtraction
1159
; is greater than or equal to start+length; the subtraction
909
; (.FirstSector-start) - length must not cause overflow. Go to 2g if life is
1160
; (.FirstSector-start) - length must not cause overflow. Go to 2g if life is
910
; good or to 2f in the other case.
1161
; good or to 2f in the other case.
911
        sub     eax, dword [length]
1162
        sub     eax, dword [length]
912
        sbb     edx, dword [length+4]
1163
        sbb     edx, dword [length+4]
913
        jb      .overlap
1164
        jb      .overlap
914
        jmp     .next_existing
1165
        jmp     .next_existing
915
.less:
1166
.less:
916
; 2e. .FirstSector is less than start. Check that .FirstSector+.Length is less
1167
; 2e. .FirstSector is less than start. Check that .FirstSector+.Length is less
917
; than or equal to start. If the addition (.FirstSector-start) + .Length does
1168
; than or equal to start. If the addition (.FirstSector-start) + .Length does
918
; not cause overflow, then .FirstSector + .Length is strictly less than start;
1169
; not cause overflow, then .FirstSector + .Length is strictly less than start;
919
; since the equality is also valid, use decrement preliminarily. Go to 2g or
1170
; since the equality is also valid, use decrement preliminarily. Go to 2g or
920
; 2f depending on the overflow.
1171
; 2f depending on the overflow.
921
        sub     eax, 1
1172
        sub     eax, 1
922
        sbb     edx, 0
1173
        sbb     edx, 0
923
        add     eax, dword [ecx+PARTITION.Length]
1174
        add     eax, dword [ecx+PARTITION.Length]
924
        adc     edx, dword [ecx+PARTITION.Length+4]
1175
        adc     edx, dword [ecx+PARTITION.Length+4]
925
        jnc     .next_existing
1176
        jnc     .next_existing
926
.overlap:
1177
.overlap:
927
; 2f. The partition overlaps with previously registered partition. Say warning
1178
; 2f. The partition overlaps with previously registered partition. Say warning
928
; and return with nothing done.
1179
; and return with nothing done.
929
        dbgstr 'two partitions overlap, ignoring the last one'
1180
        dbgstr 'two partitions overlap, ignoring the last one'
930
        jmp     .nothing
1181
        jmp     .nothing
931
.next_existing:
1182
.next_existing:
932
; 2g. The partition does not overlap with the current partition. Continue the
1183
; 2g. The partition does not overlap with the current partition. Continue the
933
; loop.
1184
; loop.
934
        dec     ebx
1185
        dec     ebx
935
        jnz     .scan_existing
1186
        jnz     .scan_existing
936
.partitionok:
1187
.partitionok:
937
; 3. The partition has passed tests. Reallocate the partitions array for a new
1188
; 3. The partition has passed tests. Reallocate the partitions array for a new
938
; entry.
1189
; entry.
939
; 3a. Call the allocator.
1190
; 3a. Call the allocator.
940
        mov     eax, [esi+DISK.NumPartitions]
1191
        mov     eax, [esi+DISK.NumPartitions]
941
        inc     eax     ; one more entry
1192
        inc     eax     ; one more entry
942
        shl     eax, 2  ; each entry is dword
1193
        shl     eax, 2  ; each entry is dword
943
        call    malloc
1194
        call    malloc
944
; 3b. Test the result. If failed, return with nothing done.
1195
; 3b. Test the result. If failed, return with nothing done.
945
        test    eax, eax
1196
        test    eax, eax
946
        jz      .nothing
1197
        jz      .nothing
947
; 3c. Copy the old array to the new array.
1198
; 3c. Copy the old array to the new array.
948
        mov     edi, eax
1199
        mov     edi, eax
949
        push    esi
1200
        push    esi
950
        mov     ecx, [esi+DISK.NumPartitions]
1201
        mov     ecx, [esi+DISK.NumPartitions]
951
        mov     esi, [esi+DISK.Partitions]
1202
        mov     esi, [esi+DISK.Partitions]
952
        rep movsd
1203
        rep movsd
953
        pop     esi
1204
        pop     esi
954
; 3d. Set the field in the DISK structure to the new array.
1205
; 3d. Set the field in the DISK structure to the new array.
955
        xchg    [esi+DISK.Partitions], eax
1206
        xchg    [esi+DISK.Partitions], eax
956
; 3e. Free the old array.
1207
; 3e. Free the old array.
957
        call    free
1208
        call    free
958
; 4. Recognize the file system.
1209
; 4. Recognize the file system.
959
; 4a. Call the filesystem recognizer. It will allocate the PARTITION structure
1210
; 4a. Call the filesystem recognizer. It will allocate the PARTITION structure
960
; with possible filesystem-specific fields.
1211
; with possible filesystem-specific fields.
961
        call    disk_detect_partition
1212
        call    disk_detect_partition
962
; 4b. Check return value. If zero, return with list not changed; so far only
1213
; 4b. Check return value. If zero, return with list not changed; so far only
963
; the array was reallocated, this is ok for other code.
1214
; the array was reallocated, this is ok for other code.
964
        test    eax, eax
1215
        test    eax, eax
965
        jz      .nothing
1216
        jz      .nothing
966
; 5. Insert the new partition to the list.
1217
; 5. Insert the new partition to the list.
967
        stosd
1218
        stosd
968
        inc     [esi+DISK.NumPartitions]
1219
        inc     [esi+DISK.NumPartitions]
969
; 6. Return.
1220
; 6. Return.
970
.nothing:
1221
.nothing:
971
        ret
1222
        ret
972
endp
1223
endp
973
 
1224
 
974
; This is an internal function called from disk_add_partition.
1225
; This is an internal function called from disk_add_partition.
975
; It tries to recognize the file system on the partition and allocates the
1226
; It tries to recognize the file system on the partition and allocates the
976
; corresponding PARTITION structure with filesystem-specific fields.
1227
; corresponding PARTITION structure with filesystem-specific fields.
977
disk_detect_partition:
1228
disk_detect_partition:
978
; This function inherits the stack frame from disk_add_partition. In stdcall
1229
; This function inherits the stack frame from disk_add_partition. In stdcall
979
; with ebp-based frame arguments start from ebp+8, since [ebp]=saved ebp
1230
; with ebp-based frame arguments start from ebp+8, since [ebp]=saved ebp
980
; and [ebp+4]=return address.
1231
; and [ebp+4]=return address.
981
virtual at ebp+8
1232
virtual at ebp+8
982
.start  dq      ?
1233
.start  dq      ?
983
.length dq      ?
1234
.length dq      ?
984
.disk   dd      ?
1235
.disk   dd      ?
985
end virtual
1236
end virtual
986
; 1. Read the bootsector to the buffer.
1237
; 1. Read the bootsector to the buffer.
987
; When disk_add_partition is called, ebx contains a pointer to
1238
; When disk_add_partition is called, ebx contains a pointer to
988
; a three-sectors-sized buffer. This function saves ebx in the stack
1239
; a three-sectors-sized buffer. This function saves ebx in the stack
989
; immediately before ebp.
1240
; immediately before ebp.
990
        mov     ebx, [ebp-4] ; get buffer
1241
        mov     ebx, [ebp-4] ; get buffer
991
        add     ebx, [esi+DISK.MediaInfo.SectorSize] ; advance over MBR data to bootsector data
1242
        add     ebx, [esi+DISK.MediaInfo.SectorSize] ; advance over MBR data to bootsector data
992
        add     ebp, 8       ; ebp points to part of PARTITION structure
1243
        add     ebp, 8       ; ebp points to part of PARTITION structure
993
        xor     eax, eax     ; first sector of the partition
1244
        xor     eax, eax     ; first sector of the partition
994
        call    fs_read32_sys
1245
        call    fs_read32_sys
995
        push    eax
1246
        push    eax
996
; 2. Run tests for all supported filesystems. If at least one test succeeded,
1247
; 2. Run tests for all supported filesystems. If at least one test succeeded,
997
; go to 4.
1248
; go to 4.
998
; For tests:
1249
; For tests:
999
; ebp -> first three fields of PARTITION structure, .start, .length, .disk;
1250
; ebp -> first three fields of PARTITION structure, .start, .length, .disk;
1000
; [esp] = error code after bootsector read: 0 = ok, otherwise = failed,
1251
; [esp] = error code after bootsector read: 0 = ok, otherwise = failed,
1001
; ebx points to the buffer for bootsector,
1252
; ebx points to the buffer for bootsector,
1002
; ebx+[esi+DISK.MediaInfo.SectorSize] points to sector-sized buffer that can be used for anything.
1253
; ebx+[esi+DISK.MediaInfo.SectorSize] points to sector-sized buffer that can be used for anything.
1003
        call    fat_create_partition
1254
        call    fat_create_partition
1004
        test    eax, eax
1255
        test    eax, eax
1005
        jnz     .success
1256
        jnz     .success
1006
        call    ntfs_create_partition
1257
        call    ntfs_create_partition
1007
        test    eax, eax
1258
        test    eax, eax
1008
        jnz     .success
1259
        jnz     .success
1009
        call    ext2_create_partition
1260
        call    ext2_create_partition
1010
        test    eax, eax
1261
        test    eax, eax
1011
        jnz     .success
1262
        jnz     .success
1012
        call    xfs_create_partition
1263
        call    xfs_create_partition
1013
        test    eax, eax
1264
        test    eax, eax
1014
        jnz     .success
1265
        jnz     .success
1015
; 3. No file system has recognized the volume, so just allocate the PARTITION
1266
; 3. No file system has recognized the volume, so just allocate the PARTITION
1016
; structure without extra fields.
1267
; structure without extra fields.
1017
        movi    eax, sizeof.PARTITION
1268
        movi    eax, sizeof.PARTITION
1018
        call    malloc
1269
        call    malloc
1019
        test    eax, eax
1270
        test    eax, eax
1020
        jz      .nothing
1271
        jz      .nothing
1021
        mov     edx, dword [ebp+PARTITION.FirstSector]
1272
        mov     edx, dword [ebp+PARTITION.FirstSector]
1022
        mov     dword [eax+PARTITION.FirstSector], edx
1273
        mov     dword [eax+PARTITION.FirstSector], edx
1023
        mov     edx, dword [ebp+PARTITION.FirstSector+4]
1274
        mov     edx, dword [ebp+PARTITION.FirstSector+4]
1024
        mov     dword [eax+PARTITION.FirstSector+4], edx
1275
        mov     dword [eax+PARTITION.FirstSector+4], edx
1025
        mov     edx, dword [ebp+PARTITION.Length]
1276
        mov     edx, dword [ebp+PARTITION.Length]
1026
        mov     dword [eax+PARTITION.Length], edx
1277
        mov     dword [eax+PARTITION.Length], edx
1027
        mov     edx, dword [ebp+PARTITION.Length+4]
1278
        mov     edx, dword [ebp+PARTITION.Length+4]
1028
        mov     dword [eax+PARTITION.Length+4], edx
1279
        mov     dword [eax+PARTITION.Length+4], edx
1029
        mov     [eax+PARTITION.Disk], esi
1280
        mov     [eax+PARTITION.Disk], esi
1030
        mov     [eax+PARTITION.FSUserFunctions], default_fs_functions
1281
        mov     [eax+PARTITION.FSUserFunctions], default_fs_functions
1031
.success:
1282
.success:
1032
.nothing:
1283
.nothing:
1033
        sub     ebp, 8 ; restore ebp
1284
        sub     ebp, 8 ; restore ebp
1034
; 4. Return with eax = pointer to PARTITION or NULL.
1285
; 4. Return with eax = pointer to PARTITION or NULL.
1035
        pop     ecx
1286
        pop     ecx
1036
        ret
1287
        ret
1037
 
1288
 
1038
iglobal
1289
iglobal
1039
align 4
1290
align 4
1040
default_fs_functions:
1291
default_fs_functions:
1041
        dd      free
1292
        dd      free
1042
        dd      0       ; no user functions
1293
        dd      0       ; no user functions
1043
endg
1294
endg
1044
 
1295
 
1045
; This function is called from file_system_lfn.
1296
; This function is called from file_system_lfn.
1046
; This handler gets the control each time when fn 70 is called
1297
; This handler gets the control each time when fn 70 is called
1047
; with unknown item of root subdirectory.
1298
; with unknown item of root subdirectory.
1048
; in: esi = ebp -> path string
1299
; in: esi = ebp -> path string
1049
; out: if the handler processes path, it must not return in file_system_lfn,
1300
; out: if the handler processes path, it must not return in file_system_lfn,
1050
;      but instead pop return address and return directly to the caller
1301
;      but instead pop return address and return directly to the caller
1051
;      otherwise simply return
1302
;      otherwise simply return
1052
dyndisk_handler:
1303
dyndisk_handler:
1053
        push    ebx edi         ; save registers used in file_system_lfn
1304
        push    ebx edi         ; save registers used in file_system_lfn
1054
; 1. Acquire the mutex.
1305
; 1. Acquire the mutex.
1055
        mov     ecx, disk_list_mutex
1306
        mov     ecx, disk_list_mutex
1056
        call    mutex_lock
1307
        call    mutex_lock
1057
; 2. Loop over the list of DISK structures.
1308
; 2. Loop over the list of DISK structures.
1058
; 2a. Initialize.
1309
; 2a. Initialize.
1059
        mov     ebx, disk_list
1310
        mov     ebx, disk_list
1060
.scan:
1311
.scan:
1061
; 2b. Get the next item.
1312
; 2b. Get the next item.
1062
        mov     ebx, [ebx+DISK.Next]
1313
        mov     ebx, [ebx+DISK.Next]
1063
; 2c. Check whether the list is done. If so, go to 3.
1314
; 2c. Check whether the list is done. If so, go to 3.
1064
        cmp     ebx, disk_list
1315
        cmp     ebx, disk_list
1065
        jz      .notfound
1316
        jz      .notfound
1066
; 2d. Compare names. If names match, go to 5.
1317
; 2d. Compare names. If names match, go to 5.
1067
        mov     edi, [ebx+DISK.Name]
1318
        mov     edi, [ebx+DISK.Name]
1068
        push    esi
1319
        push    esi
1069
@@:
1320
@@:
1070
; esi points to the name from fs operation; it is terminated by zero or slash.
1321
; esi points to the name from fs operation; it is terminated by zero or slash.
1071
        lodsb
1322
        lodsb
1072
        test    al, al
1323
        test    al, al
1073
        jz      .eoin_dec
1324
        jz      .eoin_dec
1074
        cmp     al, '/'
1325
        cmp     al, '/'
1075
        jz      .eoin
1326
        jz      .eoin
1076
; edi points to the disk name.
1327
; edi points to the disk name.
1077
        inc     edi
1328
        inc     edi
1078
; edi points to lowercase name, this is a requirement for the driver.
1329
; edi points to lowercase name, this is a requirement for the driver.
1079
; Characters at esi can have any register. Lowercase the current character.
1330
; Characters at esi can have any register. Lowercase the current character.
1080
; This lowercasing works for latin letters and digits; since the disk name
1331
; This lowercasing works for latin letters and digits; since the disk name
1081
; should not contain other symbols, this is ok.
1332
; should not contain other symbols, this is ok.
1082
        or      al, 20h
1333
        or      al, 20h
1083
        cmp     al, [edi-1]
1334
        cmp     al, [edi-1]
1084
        jz      @b
1335
        jz      @b
1085
.wrongname:
1336
.wrongname:
1086
; 2f. Names don't match. Continue the loop.
1337
; 2f. Names don't match. Continue the loop.
1087
        pop     esi
1338
        pop     esi
1088
        jmp     .scan
1339
        jmp     .scan
1089
.notfound:
1340
.notfound:
1090
; The loop is done and no name matches.
1341
; The loop is done and no name matches.
1091
; 3. Release the mutex.
1342
; 3. Release the mutex.
1092
        call    mutex_unlock
1343
        call    mutex_unlock
1093
; 4. Return normally.
1344
; 4. Return normally.
1094
        pop     edi ebx         ; restore registers used in file_system_lfn
1345
        pop     edi ebx         ; restore registers used in file_system_lfn
1095
        ret
1346
        ret
1096
; part of 2d: the name matches partially, but we must check that this is full
1347
; part of 2d: the name matches partially, but we must check that this is full
1097
; equality.
1348
; equality.
1098
.eoin_dec:
1349
.eoin_dec:
1099
        dec     esi
1350
        dec     esi
1100
.eoin:
1351
.eoin:
1101
        cmp     byte [edi], 0
1352
        cmp     byte [edi], 0
1102
        jnz     .wrongname
1353
        jnz     .wrongname
1103
; We found the addressed DISK structure.
1354
; We found the addressed DISK structure.
1104
; 5. Reference the disk.
1355
; 5. Reference the disk.
1105
        lock inc [ebx+DISK.RefCount]
1356
        lock inc [ebx+DISK.RefCount]
1106
; 6. Now we are sure that the DISK structure is not going to die at least
1357
; 6. Now we are sure that the DISK structure is not going to die at least
1107
; while we are working with it, so release the global mutex.
1358
; while we are working with it, so release the global mutex.
1108
        call    mutex_unlock
1359
        call    mutex_unlock
1109
        pop     ecx             ; pop from the stack saved value of esi
1360
        pop     ecx             ; pop from the stack saved value of esi
1110
; 7. Acquire the mutex for media object.
1361
; 7. Acquire the mutex for media object.
1111
        pop     edi             ; restore edi
1362
        pop     edi             ; restore edi
1112
        lea     ecx, [ebx+DISK.MediaLock]
1363
        lea     ecx, [ebx+DISK.MediaLock]
1113
        call    mutex_lock
1364
        call    mutex_lock
1114
; 8. Get the media object. If it is not NULL, reference it.
1365
; 8. Get the media object. If it is not NULL, reference it.
1115
        xor     edx, edx
1366
        xor     edx, edx
1116
        cmp     [ebx+DISK.MediaInserted], dl
1367
        cmp     [ebx+DISK.MediaInserted], dl
1117
        jz      @f
1368
        jz      @f
1118
        mov     edx, ebx
1369
        mov     edx, ebx
1119
        inc     [ebx+DISK.MediaRefCount]
1370
        inc     [ebx+DISK.MediaRefCount]
1120
@@:
1371
@@:
1121
; 9. Now we are sure that the media object, if it exists, is not going to die
1372
; 9. Now we are sure that the media object, if it exists, is not going to die
1122
; at least while we are working with it, so release the mutex for media object.
1373
; at least while we are working with it, so release the mutex for media object.
1123
        call    mutex_unlock
1374
        call    mutex_unlock
1124
        mov     ecx, ebx
1375
        mov     ecx, ebx
1125
        pop     ebx eax         ; restore ebx, pop return address
1376
        pop     ebx eax         ; restore ebx, pop return address
1126
; 10. Check whether the fs operation wants to enumerate partitions (go to 11)
1377
; 10. Check whether the fs operation wants to enumerate partitions (go to 11)
1127
; or work with some concrete partition (go to 12).
1378
; or work with some concrete partition (go to 12).
1128
        cmp     byte [esi], 0
1379
        cmp     byte [esi], 0
1129
        jnz     .haspartition
1380
        jnz     .haspartition
1130
; 11. The fs operation wants to enumerate partitions.
1381
; 11. The fs operation wants to enumerate partitions.
1131
; 11a. Only "list directory" operation is applicable to / path. Check
1382
; 11a. Only "list directory" operation is applicable to / path. Check
1132
; the operation code. If wrong, go to 13.
1383
; the operation code. If wrong, go to 13.
1133
        cmp     dword [ebx], 1
1384
        cmp     dword [ebx], 1
1134
        jnz     .access_denied
1385
        jnz     .access_denied
1135
; 11b. If the media is inserted, use 'fs_dyndisk_next' as an enumeration
1386
; 11b. If the media is inserted, use 'fs_dyndisk_next' as an enumeration
1136
; procedure. Otherwise, use 'fs_dyndisk_next_nomedia'.
1387
; procedure. Otherwise, use 'fs_dyndisk_next_nomedia'.
1137
        mov     esi, fs_dyndisk_next_nomedia
1388
        mov     esi, fs_dyndisk_next_nomedia
1138
        test    edx, edx
1389
        test    edx, edx
1139
        jz      @f
1390
        jz      @f
1140
        mov     esi, fs_dyndisk_next
1391
        mov     esi, fs_dyndisk_next
1141
@@:
1392
@@:
1142
; 11c. Let the procedure from fs_lfn.inc do the job.
1393
; 11c. Let the procedure from fs_lfn.inc do the job.
1143
        jmp     file_system_lfn.maindir_noesi
1394
        jmp     file_system_lfn.maindir_noesi
1144
 
1395
 
1145
.access_denied:
1396
.access_denied:
1146
        mov     dword [esp+32], ERROR_ACCESS_DENIED
1397
        mov     dword [esp+32], ERROR_ACCESS_DENIED
1147
        mov     esi, ecx        ; disk*dereference assume that esi points to DISK
1398
        mov     esi, ecx        ; disk*dereference assume that esi points to DISK
1148
.cleanup_esi:
1399
.cleanup_esi:
1149
        test    edx, edx        ; if there are no media, we didn't reference it
1400
        test    edx, edx        ; if there are no media, we didn't reference it
1150
        jz      @f
1401
        jz      @f
1151
        call    disk_media_dereference
1402
        call    disk_media_dereference
1152
@@:
1403
@@:
1153
        call    disk_dereference
1404
        call    disk_dereference
1154
        stdcall kernel_free, ebp
1405
        stdcall kernel_free, ebp
1155
        ret
1406
        ret
1156
 
1407
 
1157
.dyndisk_cleanup:
1408
.dyndisk_cleanup:
1158
        pop     esi
1409
        pop     esi
1159
        pop     edx
1410
        pop     edx
1160
        mov     dword [esp+32], ERROR_FILE_NOT_FOUND
1411
        mov     dword [esp+32], ERROR_FILE_NOT_FOUND
1161
        jmp     .cleanup_esi
1412
        jmp     .cleanup_esi
1162
 
1413
 
1163
.haspartition:
1414
.haspartition:
1164
; 12. The fs operation has specified some partition.
1415
; 12. The fs operation has specified some partition.
1165
        push    edx
1416
        push    edx
1166
        push    ecx
1417
        push    ecx
1167
        xor     eax, eax
1418
        xor     eax, eax
1168
        lodsb
1419
        lodsb
1169
        sub     eax, '0'
1420
        sub     eax, '0'
1170
        jz      .dyndisk_cleanup
1421
        jz      .dyndisk_cleanup
1171
        cmp     eax, 10
1422
        cmp     eax, 10
1172
        jnc     .dyndisk_cleanup
1423
        jnc     .dyndisk_cleanup
1173
        mov     ecx, eax
1424
        mov     ecx, eax
1174
        lodsb
1425
        lodsb
1175
        cmp     eax, '/'
1426
        cmp     eax, '/'
1176
        jz      @f
1427
        jz      @f
1177
        test    eax, eax
1428
        test    eax, eax
1178
        jnz     .dyndisk_cleanup
1429
        jnz     .dyndisk_cleanup
1179
        dec     esi
1430
        dec     esi
1180
@@:
1431
@@:
1181
        dec     ecx     ; convert to zero-based partition index
1432
        dec     ecx     ; convert to zero-based partition index
1182
        pop     edx     ; edx = pointer to DISK, dword [esp] = NULL or edx
1433
        pop     edx     ; edx = pointer to DISK, dword [esp] = NULL or edx
1183
; If the driver does not support insert notifications and we are the only fs
1434
; If the driver does not support insert notifications and we are the only fs
1184
; operation with this disk, ask the driver whether the media
1435
; operation with this disk, ask the driver whether the media
1185
; was inserted/removed/changed. Otherwise, assume that media status is valid.
1436
; was inserted/removed/changed. Otherwise, assume that media status is valid.
1186
        test    byte [edx+DISK.DriverFlags], DISK_NO_INSERT_NOTIFICATION
1437
        test    byte [edx+DISK.DriverFlags], DISK_NO_INSERT_NOTIFICATION
1187
        jz      .media_accurate
1438
        jz      .media_accurate
1188
        push    ecx esi
1439
        push    ecx esi
1189
        mov     esi, edx
1440
        mov     esi, edx
1190
        cmp     dword [esp+8], 0
1441
        cmp     dword [esp+8], 0
1191
        jz      .test_no_media
1442
        jz      .test_no_media
1192
        cmp     [esi+DISK.MediaRefCount], 2
1443
        cmp     [esi+DISK.MediaRefCount], 2
1193
        jnz     .media_accurate_pop
1444
        jnz     .media_accurate_pop
1194
        lea     edx, [esi+DISK.MediaInfo]
1445
        lea     edx, [esi+DISK.MediaInfo]
1195
        and     [edx+DISKMEDIAINFO.Flags], 0
1446
        and     [edx+DISKMEDIAINFO.Flags], 0
1196
        mov     al, DISKFUNC.querymedia
1447
        mov     al, DISKFUNC.querymedia
1197
        stdcall disk_call_driver, edx
1448
        stdcall disk_call_driver, edx
1198
        test    eax, eax
1449
        test    eax, eax
1199
        jz      .media_accurate_pop
1450
        jz      .media_accurate_pop
1200
        stdcall disk_media_dereference  ; drop our reference so that disk_media_changed could close the media
1451
        stdcall disk_media_dereference  ; drop our reference so that disk_media_changed could close the media
1201
        stdcall disk_media_changed, esi, 0
1452
        stdcall disk_media_changed, esi, 0
1202
        and     dword [esp+8], 0        ; no media
1453
        and     dword [esp+8], 0        ; no media
1203
.test_no_media:
1454
.test_no_media:
1204
        stdcall disk_media_changed, esi, 1      ; issue fake notification
1455
        stdcall disk_media_changed, esi, 1      ; issue fake notification
1205
; if querymedia() inside disk_media_changed returns error, the notification is ignored
1456
; if querymedia() inside disk_media_changed returns error, the notification is ignored
1206
        cmp     [esi+DISK.MediaInserted], 0
1457
        cmp     [esi+DISK.MediaInserted], 0
1207
        jz      .media_accurate_pop
1458
        jz      .media_accurate_pop
1208
        lock inc [esi+DISK.MediaRefCount]
1459
        lock inc [esi+DISK.MediaRefCount]
1209
        mov     dword [esp+8], esi
1460
        mov     dword [esp+8], esi
1210
.media_accurate_pop:
1461
.media_accurate_pop:
1211
        mov     edx, esi
1462
        mov     edx, esi
1212
        pop     esi ecx
1463
        pop     esi ecx
1213
.media_accurate:
1464
.media_accurate:
1214
        pop     eax
1465
        pop     eax
1215
        test    eax, eax
1466
        test    eax, eax
1216
        jz      .nomedia
1467
        jz      .nomedia
1217
        cmp     ecx, [edx+DISK.NumPartitions]
1468
        cmp     ecx, [edx+DISK.NumPartitions]
1218
        jae     .notfound2
1469
        jae     .notfound2
1219
        mov     eax, [edx+DISK.Partitions]
1470
        mov     eax, [edx+DISK.Partitions]
1220
        mov     eax, [eax+ecx*4]
1471
        mov     eax, [eax+ecx*4]
1221
        mov     edi, [eax+PARTITION.FSUserFunctions]
1472
        mov     edi, [eax+PARTITION.FSUserFunctions]
1222
        mov     ecx, [ebx]
1473
        mov     ecx, [ebx]
1223
        cmp     [edi+4], ecx
1474
        cmp     [edi+4], ecx
1224
        jbe     .unsupported
1475
        jbe     .unsupported
1225
        push    edx
1476
        push    edx
1226
        push    ebp
1477
        push    ebp
1227
        mov     ebp, eax
1478
        mov     ebp, eax
1228
        call    dword [edi+8+ecx*4]
1479
        call    dword [edi+8+ecx*4]
1229
        pop     ebp
1480
        pop     ebp
1230
        pop     edx
1481
        pop     edx
1231
        mov     dword [esp+32], eax
1482
        mov     dword [esp+32], eax
1232
        mov     dword [esp+20], ebx
1483
        mov     dword [esp+20], ebx
1233
.cleanup:
1484
.cleanup:
1234
        mov     esi, edx
1485
        mov     esi, edx
1235
        call    disk_media_dereference
1486
        call    disk_media_dereference
1236
@@:
1487
@@:
1237
        call    disk_dereference
1488
        call    disk_dereference
1238
        stdcall kernel_free, ebp
1489
        stdcall kernel_free, ebp
1239
        ret
1490
        ret
1240
 
1491
 
1241
.unsupported:
1492
.unsupported:
1242
        mov     dword [esp+32], ERROR_UNKNOWN_FS
1493
        mov     dword [esp+32], ERROR_UNKNOWN_FS
1243
        cmp     edi, default_fs_functions
1494
        cmp     edi, default_fs_functions
1244
        jz      .cleanup
1495
        jz      .cleanup
1245
        mov     dword [esp+32], ERROR_UNSUPPORTED_FS
1496
        mov     dword [esp+32], ERROR_UNSUPPORTED_FS
1246
        jmp     .cleanup
1497
        jmp     .cleanup
1247
 
1498
 
1248
.notfound2:
1499
.notfound2:
1249
        mov     dword [esp+32], ERROR_FILE_NOT_FOUND
1500
        mov     dword [esp+32], ERROR_FILE_NOT_FOUND
1250
        jmp     .cleanup
1501
        jmp     .cleanup
1251
 
1502
 
1252
.nomedia:
1503
.nomedia:
1253
        test    ecx, ecx
1504
        test    ecx, ecx
1254
        jnz     .notfound2
1505
        jnz     .notfound2
1255
        mov     dword [esp+32], ERROR_DEVICE
1506
        mov     dword [esp+32], ERROR_DEVICE
1256
        mov     esi, edx
1507
        mov     esi, edx
1257
        jmp     @b
1508
        jmp     @b
1258
 
1509
 
1259
; This is a callback for enumerating partitions called from
1510
; This is a callback for enumerating partitions called from
1260
; file_system_lfn.maindir in the case of inserted media.
1511
; file_system_lfn.maindir in the case of inserted media.
1261
; It just increments eax until DISK.NumPartitions reached and then
1512
; It just increments eax until DISK.NumPartitions reached and then
1262
; cleans up.
1513
; cleans up.
1263
fs_dyndisk_next:
1514
fs_dyndisk_next:
1264
        mov     ecx, [esp+8]
1515
        mov     ecx, [esp+8]
1265
        cmp     eax, [ecx+DISK.NumPartitions]
1516
        cmp     eax, [ecx+DISK.NumPartitions]
1266
        jae     .nomore
1517
        jae     .nomore
1267
        inc     eax
1518
        inc     eax
1268
        clc
1519
        clc
1269
        ret
1520
        ret
1270
.nomore:
1521
.nomore:
1271
        pusha
1522
        pusha
1272
        mov     esi, ecx
1523
        mov     esi, ecx
1273
        call    disk_media_dereference
1524
        call    disk_media_dereference
1274
        call    disk_dereference
1525
        call    disk_dereference
1275
        popa
1526
        popa
1276
        stc
1527
        stc
1277
        ret
1528
        ret
1278
 
1529
 
1279
; This is a callback for enumerating partitions called from
1530
; This is a callback for enumerating partitions called from
1280
; file_system_lfn.maindir in the case of missing media.
1531
; file_system_lfn.maindir in the case of missing media.
1281
; In this case we create one pseudo-partition.
1532
; In this case we create one pseudo-partition.
1282
fs_dyndisk_next_nomedia:
1533
fs_dyndisk_next_nomedia:
1283
        cmp     eax, 1
1534
        cmp     eax, 1
1284
        jae     .nomore
1535
        jae     .nomore
1285
        inc     eax
1536
        inc     eax
1286
        clc
1537
        clc
1287
        ret
1538
        ret
1288
.nomore:
1539
.nomore:
1289
        mov     ecx, [esp+8]
1540
        mov     ecx, [esp+8]
1290
        pusha
1541
        pusha
1291
        mov     esi, ecx
1542
        mov     esi, ecx
1292
        call    disk_dereference
1543
        call    disk_dereference
1293
        popa
1544
        popa
1294
        stc
1545
        stc
1295
        ret
1546
        ret
1296
 
1547
 
1297
; This function is called from file_system_lfn.
1548
; This function is called from file_system_lfn.
1298
; This handler is called when virtual root is enumerated
1549
; This handler is called when virtual root is enumerated
1299
; and must return all items which can be handled by this.
1550
; and must return all items which can be handled by this.
1300
; It is called several times, first time with eax=0
1551
; It is called several times, first time with eax=0
1301
; in: eax = 0 for first call, previously returned value for subsequent calls
1552
; in: eax = 0 for first call, previously returned value for subsequent calls
1302
; out: eax = 0 => no more items
1553
; out: eax = 0 => no more items
1303
;      eax != 0 => buffer pointed to by edi contains name of item
1554
;      eax != 0 => buffer pointed to by edi contains name of item
1304
dyndisk_enum_root:
1555
dyndisk_enum_root:
1305
        push    edx             ; save register used in file_system_lfn
1556
        push    edx             ; save register used in file_system_lfn
1306
        mov     ecx, disk_list_mutex    ; it will be useful
1557
        mov     ecx, disk_list_mutex    ; it will be useful
1307
; 1. If this is the first call, acquire the mutex and initialize.
1558
; 1. If this is the first call, acquire the mutex and initialize.
1308
        test    eax, eax
1559
        test    eax, eax
1309
        jnz     .notfirst
1560
        jnz     .notfirst
1310
        call    mutex_lock
1561
        call    mutex_lock
1311
        mov     eax, disk_list
1562
        mov     eax, disk_list
1312
.notfirst:
1563
.notfirst:
1313
; 2. Get next item.
1564
; 2. Get next item.
1314
        mov     eax, [eax+DISK.Next]
1565
        mov     eax, [eax+DISK.Next]
1315
; 3. If there are no more items, go to 6.
1566
; 3. If there are no more items, go to 6.
1316
        cmp     eax, disk_list
1567
        cmp     eax, disk_list
1317
        jz      .last
1568
        jz      .last
1318
; 4. Copy name from the DISK structure to edi.
1569
; 4. Copy name from the DISK structure to edi.
1319
        push    eax esi
1570
        push    eax esi
1320
        mov     esi, [eax+DISK.Name]
1571
        mov     esi, [eax+DISK.Name]
1321
@@:
1572
@@:
1322
        lodsb
1573
        lodsb
1323
        stosb
1574
        stosb
1324
        test    al, al
1575
        test    al, al
1325
        jnz     @b
1576
        jnz     @b
1326
        pop     esi eax
1577
        pop     esi eax
1327
; 5. Return with eax = item.
1578
; 5. Return with eax = item.
1328
        pop     edx             ; restore register used in file_system_lfn
1579
        pop     edx             ; restore register used in file_system_lfn
1329
        ret
1580
        ret
1330
.last:
1581
.last:
1331
; 6. Release the mutex and return with eax = 0.
1582
; 6. Release the mutex and return with eax = 0.
1332
        call    mutex_unlock
1583
        call    mutex_unlock
1333
        xor     eax, eax
1584
        xor     eax, eax
1334
        pop     edx             ; restore register used in file_system_lfn
1585
        pop     edx             ; restore register used in file_system_lfn
1335
        ret
1586
        ret