Subversion Repositories Kolibri OS

Rev

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

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