Subversion Repositories Kolibri OS

Rev

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

Rev 3202 Rev 3460
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: 3202 $
8
$Revision: 3460 $
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
                        dw ? ; padding
154
; The following fields are not valid unless either .MediaInserted is nonzero
154
; The following fields are not valid unless either .MediaInserted is nonzero
155
; or they are accessed from a code which has obtained the reference when
155
; or they are accessed from a code which has obtained the reference when
156
; .MediaInserted was nonzero.
156
; .MediaInserted was nonzero.
157
        MediaRefCount   dd ?
157
        MediaRefCount   dd ?
158
; Count of active references to the media object. One reference is kept during
158
; Count of active references to the media object. One reference is kept during
159
; the lifetime of the media between two calls to 'disk_media_changed'.
159
; the lifetime of the media between two calls to 'disk_media_changed'.
160
; Another reference is taken during any filesystem operation for this media.
160
; Another reference is taken during any filesystem operation for this media.
161
; The callback 'closemedia' is called when the reference count decrements to
161
; The callback 'closemedia' is called when the reference count decrements to
162
; zero: this usually occurs in 'disk_media_changed', but can be delayed to the
162
; zero: this usually occurs in 'disk_media_changed', but can be delayed to the
163
; end of the last filesystem operation, if one is active.
163
; end of the last filesystem operation, if one is active.
164
        MediaInfo       DISKMEDIAINFO
164
        MediaInfo       DISKMEDIAINFO
165
; This field keeps information on the current media.
165
; This field keeps information on the current media.
166
        NumPartitions   dd ?
166
        NumPartitions   dd ?
167
; Number of partitions on this media.
167
; Number of partitions on this media.
168
        Partitions      dd ?
168
        Partitions      dd ?
169
; Pointer to array of .NumPartitions pointers to PARTITION structures.
169
; Pointer to array of .NumPartitions pointers to PARTITION structures.
170
        cache_size      dd ?
170
        cache_size      dd ?
171
; inherited from cache_ideX_size
171
; inherited from cache_ideX_size
172
        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
        mov     [esi+DISK.MediaRefCount], eax
384
        inc     eax
385
        inc     eax
385
        mov     [esi+DISK.RefCount], eax
386
        mov     [esi+DISK.RefCount], eax
386
; The DISK structure is initialized.
387
; The DISK structure is initialized.
387
; 5. Insert the new structure to the global list.
388
; 5. Insert the new structure to the global list.
388
; 5a. Acquire the mutex.
389
; 5a. Acquire the mutex.
389
        mov     ecx, disk_list_mutex
390
        mov     ecx, disk_list_mutex
390
        call    mutex_lock
391
        call    mutex_lock
391
; 5b. Insert item to the tail of double-linked list.
392
; 5b. Insert item to the tail of double-linked list.
392
        mov     edx, disk_list
393
        mov     edx, disk_list
393
        list_add_tail esi, edx     ;esi= new edx= list head
394
        list_add_tail esi, edx     ;esi= new edx= list head
394
; 5c. Release the mutex.
395
; 5c. Release the mutex.
395
        call    mutex_unlock
396
        call    mutex_unlock
396
; 6. Return with eax = pointer to DISK.
397
; 6. Return with eax = pointer to DISK.
397
        xchg    eax, esi
398
        xchg    eax, esi
398
        jmp     .nothing
399
        jmp     .nothing
399
.free:
400
.free:
400
; Memory allocation for DISK structure succeeded, but for disk name failed.
401
; Memory allocation for DISK structure succeeded, but for disk name failed.
401
; 7. Free the DISK structure.
402
; 7. Free the DISK structure.
402
        xchg    eax, esi
403
        xchg    eax, esi
403
        call    free
404
        call    free
404
; 8. Return with eax = 0.
405
; 8. Return with eax = 0.
405
        xor     eax, eax
406
        xor     eax, eax
406
.nothing:
407
.nothing:
407
; 9. Return.
408
; 9. Return.
408
        pop     esi ebx         ; restore used registers to be stdcall
409
        pop     esi ebx         ; restore used registers to be stdcall
409
        ret     16              ; purge 4 dword arguments to be stdcall
410
        ret     16              ; purge 4 dword arguments to be stdcall
410
 
411
 
411
; This function deletes a disk device from the global filesystem.
412
; This function deletes a disk device from the global filesystem.
412
; This includes:
413
; This includes:
413
; - removing a media including all partitions;
414
; - removing a media including all partitions;
414
; - deleting this structure from the global filesystem;
415
; - deleting this structure from the global filesystem;
415
; - dereferencing the DISK structure and possibly destroying it.
416
; - dereferencing the DISK structure and possibly destroying it.
416
; Parameters:
417
; Parameters:
417
; [esp+4] = handle of the disk, i.e. the pointer to the DISK structure.
418
; [esp+4] = handle of the disk, i.e. the pointer to the DISK structure.
418
; Return value: none.
419
; Return value: none.
419
disk_del:
420
disk_del:
420
        push    esi         ; save used registers to be stdcall
421
        push    esi         ; save used registers to be stdcall
421
; 1. Force media to be removed. If the media is already removed, the
422
; 1. Force media to be removed. If the media is already removed, the
422
; call does nothing.
423
; call does nothing.
423
        mov     esi, [esp+4+4]  ; esi = handle of the disk
424
        mov     esi, [esp+4+4]  ; esi = handle of the disk
424
        stdcall disk_media_changed, esi, 0
425
        stdcall disk_media_changed, esi, 0
425
; 2. Delete the structure from the global list.
426
; 2. Delete the structure from the global list.
426
; 2a. Acquire the mutex.
427
; 2a. Acquire the mutex.
427
        mov     ecx, disk_list_mutex
428
        mov     ecx, disk_list_mutex
428
        call    mutex_lock
429
        call    mutex_lock
429
; 2b. Delete item from double-linked list.
430
; 2b. Delete item from double-linked list.
430
        mov     eax, [esi+DISK.Next]
431
        mov     eax, [esi+DISK.Next]
431
        mov     edx, [esi+DISK.Prev]
432
        mov     edx, [esi+DISK.Prev]
432
        mov     [eax+DISK.Prev], edx
433
        mov     [eax+DISK.Prev], edx
433
        mov     [edx+DISK.Next], eax
434
        mov     [edx+DISK.Next], eax
434
; 2c. Release the mutex.
435
; 2c. Release the mutex.
435
        call    mutex_unlock
436
        call    mutex_unlock
436
; 3. The structure still has one reference created in disk_add. Remove this
437
; 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
438
; reference. If there are no other references, disk_dereference will free the
438
; structure.
439
; structure.
439
        call    disk_dereference
440
        call    disk_dereference
440
; 4. Return.
441
; 4. Return.
441
        pop     esi             ; restore used registers to be stdcall
442
        pop     esi             ; restore used registers to be stdcall
442
        ret     4               ; purge 1 dword argument to be stdcall
443
        ret     4               ; purge 1 dword argument to be stdcall
443
 
444
 
444
; This is an internal function which removes a previously obtained reference
445
; 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
446
; 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.
447
; finalize all associated data, and afterwards frees the DISK structure.
447
; esi = pointer to DISK structure
448
; esi = pointer to DISK structure
448
disk_dereference:
449
disk_dereference:
449
; 1. Decrement reference counter. Use atomic operation to correctly handle
450
; 1. Decrement reference counter. Use atomic operation to correctly handle
450
; possible simultaneous calls.
451
; possible simultaneous calls.
451
        lock dec [esi+DISK.RefCount]
452
        lock dec [esi+DISK.RefCount]
452
; 2. If the result is nonzero, there are other references, so nothing to do.
453
; 2. If the result is nonzero, there are other references, so nothing to do.
453
; In this case, return (go to 4).
454
; In this case, return (go to 4).
454
        jnz     .nothing
455
        jnz     .nothing
455
; 3. If we are here, we just removed the last reference and must destroy the
456
; 3. If we are here, we just removed the last reference and must destroy the
456
; disk object.
457
; disk object.
457
; 3a. Call the driver.
458
; 3a. Call the driver.
458
        mov     al, DISKFUNC.close
459
        mov     al, DISKFUNC.close
459
        stdcall disk_call_driver
460
        stdcall disk_call_driver
460
; 3b. Free the structure.
461
; 3b. Free the structure.
461
        xchg    eax, esi
462
        xchg    eax, esi
462
        push    ebx
463
        push    ebx
463
        call    free
464
        call    free
464
        pop     ebx
465
        pop     ebx
465
; 4. Return.
466
; 4. Return.
466
.nothing:
467
.nothing:
467
        ret
468
        ret
468
 
469
 
469
; This is an internal function which removes a previously obtained reference
470
; This is an internal function which removes a previously obtained reference
470
; to the media. If this is the last reference, this function calls 'closemedia'
471
; to the media. If this is the last reference, this function calls 'closemedia'
471
; callback to signal the driver that the processing has finished and it is safe
472
; callback to signal the driver that the processing has finished and it is safe
472
; to inform about a new media.
473
; to inform about a new media.
473
; esi = pointer to DISK structure
474
; esi = pointer to DISK structure
474
disk_media_dereference:
475
disk_media_dereference:
475
; 1. Decrement reference counter. Use atomic operation to correctly handle
476
; 1. Decrement reference counter. Use atomic operation to correctly handle
476
; possible simultaneous calls.
477
; possible simultaneous calls.
477
        lock dec [esi+DISK.MediaRefCount]
478
        lock dec [esi+DISK.MediaRefCount]
478
; 2. If the result is nonzero, there are other references, so nothing to do.
479
; 2. If the result is nonzero, there are other references, so nothing to do.
479
; In this case, return (go to 4).
480
; In this case, return (go to 4).
480
        jnz     .nothing
481
        jnz     .nothing
481
; 3. If we are here, we just removed the last reference and must destroy the
482
; 3. If we are here, we just removed the last reference and must destroy the
482
; media object.
483
; media object.
483
; Note that the same place inside the DISK structure is reused for all media
484
; Note that the same place inside the DISK structure is reused for all media
484
; objects, so we must guarantee that reusing does not happen while freeing.
485
; objects, so we must guarantee that reusing does not happen while freeing.
485
; Reusing is only possible when someone processes a new media. There are two
486
; Reusing is only possible when someone processes a new media. There are two
486
; mutually exclusive variants:
487
; mutually exclusive variants:
487
; * driver issues media insert notifications (DISK_NO_INSERT_NOTIFICATION bit
488
; * driver issues media insert notifications (DISK_NO_INSERT_NOTIFICATION bit
488
;   in DISK.DriverFlags is not set). In this case, we require from the driver
489
;   in DISK.DriverFlags is not set). In this case, we require from the driver
489
;   that such notification (except for the first one) can occur only after a
490
;   that such notification (except for the first one) can occur only after a
490
;   call to 'closemedia' callback.
491
;   call to 'closemedia' callback.
491
; * driver does not issue media insert notifications. In this case, the kernel
492
; * driver does not issue media insert notifications. In this case, the kernel
492
;   itself must sometimes check whether media is inserted. We have the flag
493
;   itself must sometimes check whether media is inserted. We have the flag
493
;   DISK.MediaUsed, visible to the kernel. This flag signals to the other parts
494
;   DISK.MediaUsed, visible to the kernel. This flag signals to the other parts
494
;   of kernel that the way is free.
495
;   of kernel that the way is free.
495
; In the first case other parts of the kernel do not use DISK.MediaUsed, so it
496
; In the first case other parts of the kernel do not use DISK.MediaUsed, so it
496
; does not matter when this flag is cleared. In the second case this flag must
497
; does not matter when this flag is cleared. In the second case this flag must
497
; be cleared after all other actions, including call to 'closemedia'.
498
; be cleared after all other actions, including call to 'closemedia'.
498
; 3a. Free all partitions.
499
; 3a. Free all partitions.
499
        push    esi edi
500
        push    esi edi
500
        mov     edi, [esi+DISK.NumPartitions]
501
        mov     edi, [esi+DISK.NumPartitions]
501
        mov     esi, [esi+DISK.Partitions]
502
        mov     esi, [esi+DISK.Partitions]
502
        test    edi, edi
503
        test    edi, edi
503
        jz      .nofree
504
        jz      .nofree
504
.freeloop:
505
.freeloop:
505
        lodsd
506
        lodsd
506
        call    free
507
        call    free
507
        dec     edi
508
        dec     edi
508
        jnz     .freeloop
509
        jnz     .freeloop
509
.nofree:
510
.nofree:
510
        pop     edi esi
511
        pop     edi esi
511
; 3b. Free the cache.
512
; 3b. Free the cache.
512
        call    disk_free_cache
513
        call    disk_free_cache
513
; 3c. Call the driver.
514
; 3c. Call the driver.
514
        mov     al, DISKFUNC.closemedia
515
        mov     al, DISKFUNC.closemedia
515
        stdcall disk_call_driver
516
        stdcall disk_call_driver
516
; 3d. Clear the flag.
517
; 3d. Clear the flag.
517
        mov     [esi+DISK.MediaUsed], 0
518
        mov     [esi+DISK.MediaUsed], 0
518
.nothing:
519
.nothing:
519
        ret
520
        ret
520
 
521
 
521
; This function is called by the driver and informs the kernel that the media
522
; This function is called by the driver and informs the kernel that the media
522
; has changed. If the media is non-removable, it is called exactly once
523
; has changed. If the media is non-removable, it is called exactly once
523
; immediately after 'disk_add' and once from 'disk_del'.
524
; immediately after 'disk_add' and once from 'disk_del'.
524
; Parameters:
525
; Parameters:
525
; [esp+4] = handle of the disk, i.e. the pointer to the DISK structure.
526
; [esp+4] = handle of the disk, i.e. the pointer to the DISK structure.
526
; [esp+8] = new status of the media: zero = no media, nonzero = media inserted.
527
; [esp+8] = new status of the media: zero = no media, nonzero = media inserted.
527
disk_media_changed:
528
disk_media_changed:
528
        push    ebx esi edi             ; save used registers to be stdcall
529
        push    ebx esi edi             ; save used registers to be stdcall
529
; 1. Remove the existing media, if it is present.
530
; 1. Remove the existing media, if it is present.
530
        mov     esi, [esp+4+12]         ; esi = pointer to DISK
531
        mov     esi, [esp+4+12]         ; esi = pointer to DISK
531
; 1a. Check whether it is present. Since DISK.MediaInserted is changed only
532
; 1a. Check whether it is present. Since DISK.MediaInserted is changed only
532
; in this function and calls to this function are synchronized, no lock is
533
; in this function and calls to this function are synchronized, no lock is
533
; required for checking.
534
; required for checking.
534
        cmp     [esi+DISK.MediaInserted], 0
535
        cmp     [esi+DISK.MediaInserted], 0
535
        jz      .noremove
536
        jz      .noremove
536
; We really need to remove the media.
537
; We really need to remove the media.
537
; 1b. Acquire mutex.
538
; 1b. Acquire mutex.
538
        lea     ecx, [esi+DISK.MediaLock]
539
        lea     ecx, [esi+DISK.MediaLock]
539
        call    mutex_lock
540
        call    mutex_lock
540
; 1c. Clear the flag.
541
; 1c. Clear the flag.
541
        mov     [esi+DISK.MediaInserted], 0
542
        mov     [esi+DISK.MediaInserted], 0
542
; 1d. Release mutex.
543
; 1d. Release mutex.
543
        call    mutex_unlock
544
        call    mutex_unlock
544
; 1e. Remove the "lifetime" reference and possibly destroy the structure.
545
; 1e. Remove the "lifetime" reference and possibly destroy the structure.
545
        call    disk_media_dereference
546
        call    disk_media_dereference
546
.noremove:
547
.noremove:
547
; 2. Test whether there is new media.
548
; 2. Test whether there is new media.
548
        cmp     dword [esp+8+12], 0
549
        cmp     dword [esp+8+12], 0
549
        jz      .noinsert
550
        jz      .noinsert
550
; Yep, there is.
551
; Yep, there is.
551
; 3. Process the new media. We assume that all media fields are available to
552
; 3. Process the new media. We assume that all media fields are available to
552
; use, see comments in 'disk_media_dereference' (this covers using by previous
553
; use, see comments in 'disk_media_dereference' (this covers using by previous
553
; media referencers) and note that calls to this function are synchronized
554
; media referencers) and note that calls to this function are synchronized
554
; (this covers using by new media referencers).
555
; (this covers using by new media referencers).
555
; 3a. Call the 'querymedia' callback.
556
; 3a. Call the 'querymedia' callback.
556
; .Flags are set to zero for possible future extensions.
557
; .Flags are set to zero for possible future extensions.
557
        lea     edx, [esi+DISK.MediaInfo]
558
        lea     edx, [esi+DISK.MediaInfo]
558
        and     [edx+DISKMEDIAINFO.Flags], 0
559
        and     [edx+DISKMEDIAINFO.Flags], 0
559
        mov     al, DISKFUNC.querymedia
560
        mov     al, DISKFUNC.querymedia
560
        stdcall disk_call_driver, edx
561
        stdcall disk_call_driver, edx
561
; 3b. Check the result of the callback. Abort if it failed.
562
; 3b. Check the result of the callback. Abort if it failed.
562
        test    eax, eax
563
        test    eax, eax
563
        jnz     .noinsert
564
        jnz     .noinsert
564
; 3c. Allocate the cache unless disabled by the driver. Abort if failed.
565
; 3c. Allocate the cache unless disabled by the driver. Abort if failed.
565
        call    disk_init_cache
566
        call    disk_init_cache
566
        test    al, al
567
        test    al, al
567
        jz      .noinsert
568
        jz      .noinsert
568
; 3d. Acquire the lifetime reference for the media object.
569
; 3d. Acquire the lifetime reference for the media object.
569
        inc     [esi+DISK.MediaRefCount]
570
        inc     [esi+DISK.MediaRefCount]
570
; 3e. Scan for partitions. Ignore result; the list of partitions is valid even
571
; 3e. Scan for partitions. Ignore result; the list of partitions is valid even
571
; on errors.
572
; on errors.
572
        call    disk_scan_partitions
573
        call    disk_scan_partitions
573
; 3f. Media is inserted and available for use.
574
; 3f. Media is inserted and available for use.
574
        inc     [esi+DISK.MediaInserted]
575
        inc     [esi+DISK.MediaInserted]
575
.noinsert:
576
.noinsert:
576
; 4. Return.
577
; 4. Return.
577
        pop     edi esi ebx             ; restore used registers to be stdcall
578
        pop     edi esi ebx             ; restore used registers to be stdcall
578
        ret     8                       ; purge 2 dword arguments to be stdcall
579
        ret     8                       ; purge 2 dword arguments to be stdcall
579
 
580
 
580
; This function is a thunk for all functions of a disk driver.
581
; This function is a thunk for all functions of a disk driver.
581
; It checks whether the referenced function is implemented in the driver.
582
; It checks whether the referenced function is implemented in the driver.
582
; If so, this function jumps to the function in the driver.
583
; If so, this function jumps to the function in the driver.
583
; Otherwise, it jumps to the default implementation.
584
; Otherwise, it jumps to the default implementation.
584
; al = offset of function in the DISKFUNC structure;
585
; al = offset of function in the DISKFUNC structure;
585
; esi = pointer to the DISK structure;
586
; esi = pointer to the DISK structure;
586
; stack is the same as for the corresponding function except that the
587
; stack is the same as for the corresponding function except that the
587
; first parameter (void* userdata) is prepended automatically.
588
; first parameter (void* userdata) is prepended automatically.
588
disk_call_driver:
589
disk_call_driver:
589
        movzx   eax, al ; eax = offset of function in the DISKFUNC structure
590
        movzx   eax, al ; eax = offset of function in the DISKFUNC structure
590
; 1. Prepend the first argument to the stack.
591
; 1. Prepend the first argument to the stack.
591
        pop     ecx     ; ecx = return address
592
        pop     ecx     ; ecx = return address
592
        push    [esi+DISK.UserData]     ; add argument
593
        push    [esi+DISK.UserData]     ; add argument
593
        push    ecx     ; save return address
594
        push    ecx     ; save return address
594
; 2. Check that the required function is inside the table. If not, go to 5.
595
; 2. Check that the required function is inside the table. If not, go to 5.
595
        mov     ecx, [esi+DISK.Functions]
596
        mov     ecx, [esi+DISK.Functions]
596
        cmp     eax, [ecx+DISKFUNC.strucsize]
597
        cmp     eax, [ecx+DISKFUNC.strucsize]
597
        jae     .default
598
        jae     .default
598
; 3. Check that the required function is implemented. If not, go to 5.
599
; 3. Check that the required function is implemented. If not, go to 5.
599
        mov     ecx, [ecx+eax]
600
        mov     ecx, [ecx+eax]
600
        test    ecx, ecx
601
        test    ecx, ecx
601
        jz      .default
602
        jz      .default
602
; 4. Jump to the required function.
603
; 4. Jump to the required function.
603
        jmp     ecx
604
        jmp     ecx
604
.default:
605
.default:
605
; 5. Driver does not implement the required function; use default implementation.
606
; 5. Driver does not implement the required function; use default implementation.
606
        jmp     dword [disk_default_callbacks+eax-4]
607
        jmp     dword [disk_default_callbacks+eax-4]
607
 
608
 
608
; The default implementation of DISKFUNC.querymedia.
609
; The default implementation of DISKFUNC.querymedia.
609
disk_default_querymedia:
610
disk_default_querymedia:
610
        push    DISK_STATUS_INVALID_CALL
611
        push    DISK_STATUS_INVALID_CALL
611
        pop     eax
612
        pop     eax
612
        ret     8
613
        ret     8
613
 
614
 
614
; The default implementation of DISKFUNC.read and DISKFUNC.write.
615
; The default implementation of DISKFUNC.read and DISKFUNC.write.
615
disk_default_read:
616
disk_default_read:
616
disk_default_write:
617
disk_default_write:
617
        push    DISK_STATUS_INVALID_CALL
618
        push    DISK_STATUS_INVALID_CALL
618
        pop     eax
619
        pop     eax
619
        ret     20
620
        ret     20
620
 
621
 
621
; The default implementation of DISKFUNC.close, DISKFUNC.closemedia and
622
; The default implementation of DISKFUNC.close, DISKFUNC.closemedia and
622
; DISKFUNC.flush.
623
; DISKFUNC.flush.
623
disk_default_close:
624
disk_default_close:
624
disk_default_closemedia:
625
disk_default_closemedia:
625
disk_default_flush:
626
disk_default_flush:
626
        xor     eax, eax
627
        xor     eax, eax
627
        ret     4
628
        ret     4
628
 
629
 
629
; The default implementation of DISKFUNC.adjust_cache_size.
630
; The default implementation of DISKFUNC.adjust_cache_size.
630
disk_default_adjust_cache_size:
631
disk_default_adjust_cache_size:
631
        mov     eax, [esp+8]
632
        mov     eax, [esp+8]
632
        ret     8
633
        ret     8
633
 
634
 
634
; This is an internal function called from 'disk_media_changed' when a new media
635
; This is an internal function called from 'disk_media_changed' when a new media
635
; is detected. It creates the list of partitions for the media.
636
; is detected. It creates the list of partitions for the media.
636
; If media is not partitioned, then the list consists of one partition which
637
; If media is not partitioned, then the list consists of one partition which
637
; covers all the media.
638
; covers all the media.
638
; esi = pointer to the DISK structure.
639
; esi = pointer to the DISK structure.
639
disk_scan_partitions:
640
disk_scan_partitions:
640
; 1. Initialize .NumPartitions and .Partitions fields as zeros: empty list.
641
; 1. Initialize .NumPartitions and .Partitions fields as zeros: empty list.
641
        and     [esi+DISK.NumPartitions], 0
642
        and     [esi+DISK.NumPartitions], 0
642
        and     [esi+DISK.Partitions], 0
643
        and     [esi+DISK.Partitions], 0
643
; 2. Currently we can work only with 512-bytes sectors. Check this restriction.
644
; 2. Currently we can work only with 512-bytes sectors. Check this restriction.
644
; The only exception is 2048-bytes CD/DVD, but they are not supported yet by
645
; The only exception is 2048-bytes CD/DVD, but they are not supported yet by
645
; this code.
646
; this code.
646
        cmp     [esi+DISK.MediaInfo.SectorSize], 512
647
        cmp     [esi+DISK.MediaInfo.SectorSize], 512
647
        jz      .doscan
648
        jz      .doscan
648
        DEBUGF 1,'K : sector size is %d, only 512 is supported\n',[esi+DISK.MediaInfo.SectorSize]
649
        DEBUGF 1,'K : sector size is %d, only 512 is supported\n',[esi+DISK.MediaInfo.SectorSize]
649
        ret
650
        ret
650
.doscan:
651
.doscan:
651
; 3. Acquire the buffer for MBR and bootsector tests. See the comment before
652
; 3. Acquire the buffer for MBR and bootsector tests. See the comment before
652
; the 'partition_buffer_users' variable.
653
; the 'partition_buffer_users' variable.
653
        mov     ebx, mbr_buffer         ; assume the global buffer is free
654
        mov     ebx, mbr_buffer         ; assume the global buffer is free
654
        lock inc [partition_buffer_users]
655
        lock inc [partition_buffer_users]
655
        jz      .buffer_acquired        ; yes, it is free
656
        jz      .buffer_acquired        ; yes, it is free
656
        lock dec [partition_buffer_users]       ; no, we must allocate
657
        lock dec [partition_buffer_users]       ; no, we must allocate
657
        stdcall kernel_alloc, 512*3
658
        stdcall kernel_alloc, 512*3
658
        test    eax, eax
659
        test    eax, eax
659
        jz      .nothing
660
        jz      .nothing
660
        xchg    eax, ebx
661
        xchg    eax, ebx
661
.buffer_acquired:
662
.buffer_acquired:
662
; MBR/EBRs are organized in the chain. We use a loop over MBR/EBRs, but no
663
; MBR/EBRs are organized in the chain. We use a loop over MBR/EBRs, but no
663
; more than MAX_NUM_PARTITION times.
664
; more than MAX_NUM_PARTITION times.
664
; 4. Prepare things for the loop.
665
; 4. Prepare things for the loop.
665
; ebp will hold the sector number for current MBR/EBR.
666
; ebp will hold the sector number for current MBR/EBR.
666
; [esp] will hold the sector number for current extended partition, if there
667
; [esp] will hold the sector number for current extended partition, if there
667
; is one.
668
; is one.
668
; [esp+4] will hold the counter that prevents long loops.
669
; [esp+4] will hold the counter that prevents long loops.
669
        push    ebp             ; save ebp
670
        push    ebp             ; save ebp
670
        push    MAX_NUM_PARTITIONS      ; the counter of max MBRs to process
671
        push    MAX_NUM_PARTITIONS      ; the counter of max MBRs to process
671
        xor     ebp, ebp        ; start from sector zero
672
        xor     ebp, ebp        ; start from sector zero
672
        push    ebp             ; no extended partition yet
673
        push    ebp             ; no extended partition yet
673
.new_mbr:
674
.new_mbr:
674
; 5. Read the current sector.
675
; 5. Read the current sector.
675
; Note that 'read' callback operates with 64-bit sector numbers, so we must
676
; Note that 'read' callback operates with 64-bit sector numbers, so we must
676
; push additional zero as a high dword of sector number.
677
; push additional zero as a high dword of sector number.
677
        mov     al, DISKFUNC.read
678
        mov     al, DISKFUNC.read
678
        push    1
679
        push    1
679
        stdcall disk_call_driver, ebx, ebp, 0, esp
680
        stdcall disk_call_driver, ebx, ebp, 0, esp
680
        pop     ecx
681
        pop     ecx
681
; 6. If the read has failed, abort the loop.
682
; 6. If the read has failed, abort the loop.
682
        dec     ecx
683
        dec     ecx
683
        jnz     .mbr_failed
684
        jnz     .mbr_failed
684
; 7. Check the MBR/EBR signature. If it is wrong, abort the loop.
685
; 7. Check the MBR/EBR signature. If it is wrong, abort the loop.
685
; Soon we will access the partition table which starts at ebx+0x1BE,
686
; Soon we will access the partition table which starts at ebx+0x1BE,
686
; so we can fill its address right now. If we do it now, then the addressing
687
; so we can fill its address right now. If we do it now, then the addressing
687
; [ecx+0x40] is shorter than [ebx+0x1fe]: one-byte offset vs 4-bytes offset.
688
; [ecx+0x40] is shorter than [ebx+0x1fe]: one-byte offset vs 4-bytes offset.
688
        lea     ecx, [ebx+0x1be]        ; ecx -> partition table
689
        lea     ecx, [ebx+0x1be]        ; ecx -> partition table
689
        cmp     word [ecx+0x40], 0xaa55
690
        cmp     word [ecx+0x40], 0xaa55
690
        jnz     .mbr_failed
691
        jnz     .mbr_failed
691
; 8. The MBR is treated differently from EBRs. For MBR we additionally need to
692
; 8. The MBR is treated differently from EBRs. For MBR we additionally need to
692
; execute step 9 and possibly step 10.
693
; execute step 9 and possibly step 10.
693
        test    ebp, ebp
694
        test    ebp, ebp
694
        jnz     .mbr
695
        jnz     .mbr
695
; The partition table can be present or not present. In the first case, we just
696
; The partition table can be present or not present. In the first case, we just
696
; read the MBR. In the second case, we just read the bootsector for a
697
; read the MBR. In the second case, we just read the bootsector for a
697
; filesystem.
698
; filesystem.
698
; The following algorithm is used to distinguish between these cases.
699
; The following algorithm is used to distinguish between these cases.
699
; A. If at least one entry of the partition table is invalid, this is
700
; A. If at least one entry of the partition table is invalid, this is
700
;    a bootsector. See the description of 'is_partition_table_entry' for
701
;    a bootsector. See the description of 'is_partition_table_entry' for
701
;    definition of validity.
702
;    definition of validity.
702
; B. If all entries are empty (filesystem type field is zero) and the first
703
; B. If all entries are empty (filesystem type field is zero) and the first
703
;    byte is jmp opcode (0EBh or 0E9h), this is a bootsector which happens to
704
;    byte is jmp opcode (0EBh or 0E9h), this is a bootsector which happens to
704
;    have zeros in the place of partition table.
705
;    have zeros in the place of partition table.
705
; C. Otherwise, this is an MBR.
706
; C. Otherwise, this is an MBR.
706
; 9. Test for MBR vs bootsector.
707
; 9. Test for MBR vs bootsector.
707
; 9a. Check entries. If any is invalid, go to 10 (rule A).
708
; 9a. Check entries. If any is invalid, go to 10 (rule A).
708
        call    is_partition_table_entry
709
        call    is_partition_table_entry
709
        jc      .notmbr
710
        jc      .notmbr
710
        add     ecx, 10h
711
        add     ecx, 10h
711
        call    is_partition_table_entry
712
        call    is_partition_table_entry
712
        jc      .notmbr
713
        jc      .notmbr
713
        add     ecx, 10h
714
        add     ecx, 10h
714
        call    is_partition_table_entry
715
        call    is_partition_table_entry
715
        jc      .notmbr
716
        jc      .notmbr
716
        add     ecx, 10h
717
        add     ecx, 10h
717
        call    is_partition_table_entry
718
        call    is_partition_table_entry
718
        jc      .notmbr
719
        jc      .notmbr
719
; 9b. Check types of the entries. If at least one is nonzero, go to 11 (rule C).
720
; 9b. Check types of the entries. If at least one is nonzero, go to 11 (rule C).
720
        mov     al, [ecx-30h+PARTITION_TABLE_ENTRY.Type]
721
        mov     al, [ecx-30h+PARTITION_TABLE_ENTRY.Type]
721
        or      al, [ecx-20h+PARTITION_TABLE_ENTRY.Type]
722
        or      al, [ecx-20h+PARTITION_TABLE_ENTRY.Type]
722
        or      al, [ecx-10h+PARTITION_TABLE_ENTRY.Type]
723
        or      al, [ecx-10h+PARTITION_TABLE_ENTRY.Type]
723
        or      al, [ecx+PARTITION_TABLE_ENTRY.Type]
724
        or      al, [ecx+PARTITION_TABLE_ENTRY.Type]
724
        jnz     .mbr
725
        jnz     .mbr
725
; 9c. Empty partition table or bootsector with many zeroes? (rule B)
726
; 9c. Empty partition table or bootsector with many zeroes? (rule B)
726
        cmp     byte [ebx], 0EBh
727
        cmp     byte [ebx], 0EBh
727
        jz      .notmbr
728
        jz      .notmbr
728
        cmp     byte [ebx], 0E9h
729
        cmp     byte [ebx], 0E9h
729
        jnz     .mbr
730
        jnz     .mbr
730
.notmbr:
731
.notmbr:
731
; 10. This is not an  MBR. The media is not partitioned. Create one partition
732
; 10. This is not an  MBR. The media is not partitioned. Create one partition
732
; which covers all the media and abort the loop.
733
; which covers all the media and abort the loop.
733
        stdcall disk_add_partition, 0, 0, \
734
        stdcall disk_add_partition, 0, 0, \
734
                dword [esi+DISK.MediaInfo.Capacity], dword [esi+DISK.MediaInfo.Capacity+4]
735
                dword [esi+DISK.MediaInfo.Capacity], dword [esi+DISK.MediaInfo.Capacity+4]
735
        jmp     .done
736
        jmp     .done
736
.mbr:
737
.mbr:
737
; 11. Process all entries of the new MBR/EBR
738
; 11. Process all entries of the new MBR/EBR
738
        lea     ecx, [ebx+0x1be]        ; ecx -> partition table
739
        lea     ecx, [ebx+0x1be]        ; ecx -> partition table
739
        push    0       ; assume no extended partition
740
        push    0       ; assume no extended partition
740
        call    process_partition_table_entry
741
        call    process_partition_table_entry
741
        add     ecx, 10h
742
        add     ecx, 10h
742
        call    process_partition_table_entry
743
        call    process_partition_table_entry
743
        add     ecx, 10h
744
        add     ecx, 10h
744
        call    process_partition_table_entry
745
        call    process_partition_table_entry
745
        add     ecx, 10h
746
        add     ecx, 10h
746
        call    process_partition_table_entry
747
        call    process_partition_table_entry
747
        pop     ebp
748
        pop     ebp
748
; 12. Test whether we found a new EBR and should continue the loop.
749
; 12. Test whether we found a new EBR and should continue the loop.
749
; 12a. If there was no next EBR, return.
750
; 12a. If there was no next EBR, return.
750
        test    ebp, ebp
751
        test    ebp, ebp
751
        jz      .done
752
        jz      .done
752
; Ok, we have EBR.
753
; Ok, we have EBR.
753
; 12b. EBRs addresses are relative to the start of extended partition.
754
; 12b. EBRs addresses are relative to the start of extended partition.
754
; For simplicity, just abort if an 32-bit overflow occurs; large disks
755
; For simplicity, just abort if an 32-bit overflow occurs; large disks
755
; are most likely partitioned with GPT, not MBR scheme, since the precise
756
; are most likely partitioned with GPT, not MBR scheme, since the precise
756
; calculation here would increase limit just twice at the price of big
757
; calculation here would increase limit just twice at the price of big
757
; compatibility problems.
758
; compatibility problems.
758
        pop     eax     ; load extended partition
759
        pop     eax     ; load extended partition
759
        add     ebp, eax
760
        add     ebp, eax
760
        jc      .mbr_failed
761
        jc      .mbr_failed
761
; 12c. If extended partition has not yet started, start it.
762
; 12c. If extended partition has not yet started, start it.
762
        test    eax, eax
763
        test    eax, eax
763
        jnz     @f
764
        jnz     @f
764
        mov     eax, ebp
765
        mov     eax, ebp
765
@@:
766
@@:
766
; 12c. If the limit is not exceeded, continue the loop.
767
; 12c. If the limit is not exceeded, continue the loop.
767
        dec     dword [esp]
768
        dec     dword [esp]
768
        push    eax     ; store extended partition
769
        push    eax     ; store extended partition
769
        jnz     .new_mbr
770
        jnz     .new_mbr
770
.mbr_failed:
771
.mbr_failed:
771
.done:
772
.done:
772
; 13. Cleanup after the loop.
773
; 13. Cleanup after the loop.
773
        pop     eax     ; not important anymore
774
        pop     eax     ; not important anymore
774
        pop     eax     ; not important anymore
775
        pop     eax     ; not important anymore
775
        pop     ebp     ; restore ebp
776
        pop     ebp     ; restore ebp
776
; 14. Release the buffer.
777
; 14. Release the buffer.
777
; 14a. Test whether it is the global buffer or we have allocated it.
778
; 14a. Test whether it is the global buffer or we have allocated it.
778
        cmp     ebx, mbr_buffer
779
        cmp     ebx, mbr_buffer
779
        jz      .release_partition_buffer
780
        jz      .release_partition_buffer
780
; 14b. If we have allocated it, free it.
781
; 14b. If we have allocated it, free it.
781
        xchg    eax, ebx
782
        xchg    eax, ebx
782
        call    free
783
        call    free
783
        jmp     .nothing
784
        jmp     .nothing
784
; 14c. Otherwise, release reference.
785
; 14c. Otherwise, release reference.
785
.release_partition_buffer:
786
.release_partition_buffer:
786
        lock dec [partition_buffer_users]
787
        lock dec [partition_buffer_users]
787
.nothing:
788
.nothing:
788
; 15. Return.
789
; 15. Return.
789
        ret
790
        ret
790
 
791
 
791
; This is an internal function called from disk_scan_partitions. It checks
792
; This is an internal function called from disk_scan_partitions. It checks
792
; whether the entry pointed to by ecx is a valid entry of partition table.
793
; whether the entry pointed to by ecx is a valid entry of partition table.
793
; The entry is valid if the first byte is 0 or 80h, the first sector plus the
794
; The entry is valid if the first byte is 0 or 80h, the first sector plus the
794
; length is less than twice the size of media. Multiplication by two is
795
; length is less than twice the size of media. Multiplication by two is
795
; required since the size mentioned in the partition table can be slightly
796
; required since the size mentioned in the partition table can be slightly
796
; greater than the real size.
797
; greater than the real size.
797
is_partition_table_entry:
798
is_partition_table_entry:
798
; 1. Check .Bootable field.
799
; 1. Check .Bootable field.
799
        mov     al, [ecx+PARTITION_TABLE_ENTRY.Bootable]
800
        mov     al, [ecx+PARTITION_TABLE_ENTRY.Bootable]
800
        and     al, 7Fh
801
        and     al, 7Fh
801
        jnz     .invalid
802
        jnz     .invalid
802
; 3. Calculate first sector + length. Note that .FirstAbsSector is relative
803
; 3. Calculate first sector + length. Note that .FirstAbsSector is relative
803
; to the MBR/EBR, so the real sum is ebp + .FirstAbsSector + .Length.
804
; to the MBR/EBR, so the real sum is ebp + .FirstAbsSector + .Length.
804
        mov     eax, ebp
805
        mov     eax, ebp
805
        xor     edx, edx
806
        xor     edx, edx
806
        add     eax, [ecx+PARTITION_TABLE_ENTRY.FirstAbsSector]
807
        add     eax, [ecx+PARTITION_TABLE_ENTRY.FirstAbsSector]
807
        adc     edx, 0
808
        adc     edx, 0
808
        add     eax, [ecx+PARTITION_TABLE_ENTRY.Length]
809
        add     eax, [ecx+PARTITION_TABLE_ENTRY.Length]
809
        adc     edx, 0
810
        adc     edx, 0
810
; 4. Divide by two.
811
; 4. Divide by two.
811
        shr     edx, 1
812
        shr     edx, 1
812
        rcr     eax, 1
813
        rcr     eax, 1
813
; 5. Compare with capacity. If the subtraction (edx:eax) - .Capacity does not
814
; 5. Compare with capacity. If the subtraction (edx:eax) - .Capacity does not
814
; overflow, this is bad.
815
; overflow, this is bad.
815
        sub     eax, dword [esi+DISK.MediaInfo.Capacity]
816
        sub     eax, dword [esi+DISK.MediaInfo.Capacity]
816
        sbb     edx, dword [esi+DISK.MediaInfo.Capacity+4]
817
        sbb     edx, dword [esi+DISK.MediaInfo.Capacity+4]
817
        jnc     .invalid
818
        jnc     .invalid
818
.valid:
819
.valid:
819
; 5. Return success: CF is cleared.
820
; 5. Return success: CF is cleared.
820
        clc
821
        clc
821
        ret
822
        ret
822
.invalid:
823
.invalid:
823
; 6. Return fail: CF is set.
824
; 6. Return fail: CF is set.
824
        stc
825
        stc
825
        ret
826
        ret
826
 
827
 
827
; This is an internal function called from disk_scan_partitions. It processes
828
; This is an internal function called from disk_scan_partitions. It processes
828
; the entry pointed to by ecx.
829
; the entry pointed to by ecx.
829
; * If the entry is invalid, just ignore this entry.
830
; * If the entry is invalid, just ignore this entry.
830
; * If the type is zero, just ignore this entry.
831
; * If the type is zero, just ignore this entry.
831
; * If the type is one of types for extended partition, store the address
832
; * If the type is one of types for extended partition, store the address
832
;   of this partition as the new MBR in [esp+4].
833
;   of this partition as the new MBR in [esp+4].
833
; * Otherwise, add the partition to the list of partitions for this disk.
834
; * Otherwise, add the partition to the list of partitions for this disk.
834
;   We don't use the type from the entry to identify the file system;
835
;   We don't use the type from the entry to identify the file system;
835
;   fs-specific checks do this more reliably.
836
;   fs-specific checks do this more reliably.
836
process_partition_table_entry:
837
process_partition_table_entry:
837
; 1. Check for valid entry. If invalid, return (go to 5).
838
; 1. Check for valid entry. If invalid, return (go to 5).
838
        call    is_partition_table_entry
839
        call    is_partition_table_entry
839
        jc      .nothing
840
        jc      .nothing
840
; 2. Check for empty entry. If invalid, return (go to 5).
841
; 2. Check for empty entry. If invalid, return (go to 5).
841
        mov     al, [ecx+PARTITION_TABLE_ENTRY.Type]
842
        mov     al, [ecx+PARTITION_TABLE_ENTRY.Type]
842
        test    al, al
843
        test    al, al
843
        jz      .nothing
844
        jz      .nothing
844
; 3. Check for extended partition. If extended, go to 6.
845
; 3. Check for extended partition. If extended, go to 6.
845
irp type,\
846
irp type,\
846
    0x05,\                 ; DOS: extended partition
847
    0x05,\                 ; DOS: extended partition
847
    0x0f,\                 ; WIN95: extended partition, LBA-mapped
848
    0x0f,\                 ; WIN95: extended partition, LBA-mapped
848
    0xc5,\                 ; DRDOS/secured: extended partition
849
    0xc5,\                 ; DRDOS/secured: extended partition
849
    0xd5                   ; Old Multiuser DOS secured: extended partition
850
    0xd5                   ; Old Multiuser DOS secured: extended partition
850
{
851
{
851
        cmp     al, type
852
        cmp     al, type
852
        jz      .extended
853
        jz      .extended
853
}
854
}
854
; 4. If we are here, that is a normal partition. Add it to the list.
855
; 4. If we are here, that is a normal partition. Add it to the list.
855
; Note that the first sector is relative to MBR/EBR.
856
; Note that the first sector is relative to MBR/EBR.
856
        mov     eax, ebp
857
        mov     eax, ebp
857
        xor     edx, edx
858
        xor     edx, edx
858
        add     eax, [ecx+PARTITION_TABLE_ENTRY.FirstAbsSector]
859
        add     eax, [ecx+PARTITION_TABLE_ENTRY.FirstAbsSector]
859
        adc     edx, 0
860
        adc     edx, 0
860
        push    ecx
861
        push    ecx
861
        stdcall disk_add_partition, eax, edx, \
862
        stdcall disk_add_partition, eax, edx, \
862
                [ecx+PARTITION_TABLE_ENTRY.Length], 0
863
                [ecx+PARTITION_TABLE_ENTRY.Length], 0
863
        pop     ecx
864
        pop     ecx
864
.nothing:
865
.nothing:
865
; 5. Return.
866
; 5. Return.
866
        ret
867
        ret
867
.extended:
868
.extended:
868
; 6. If we are here, that is an extended partition. Store the address.
869
; 6. If we are here, that is an extended partition. Store the address.
869
        mov     eax, [ecx+PARTITION_TABLE_ENTRY.FirstAbsSector]
870
        mov     eax, [ecx+PARTITION_TABLE_ENTRY.FirstAbsSector]
870
        mov     [esp+4], eax
871
        mov     [esp+4], eax
871
        ret
872
        ret
872
 
873
 
873
; This is an internal function called from disk_scan_partitions and
874
; This is an internal function called from disk_scan_partitions and
874
; process_partition_table_entry. It adds one partition to the list of
875
; process_partition_table_entry. It adds one partition to the list of
875
; partitions for the media.
876
; partitions for the media.
876
proc disk_add_partition stdcall uses ebx edi, start:qword, length:qword
877
proc disk_add_partition stdcall uses ebx edi, start:qword, length:qword
877
; 1. Check that this partition will not exceed the limit on total number.
878
; 1. Check that this partition will not exceed the limit on total number.
878
        cmp     [esi+DISK.NumPartitions], MAX_NUM_PARTITIONS
879
        cmp     [esi+DISK.NumPartitions], MAX_NUM_PARTITIONS
879
        jae     .nothing
880
        jae     .nothing
880
; 2. Check that this partition does not overlap with any already registered
881
; 2. Check that this partition does not overlap with any already registered
881
; partition. Since any file system assumes that the disk data will not change
882
; partition. Since any file system assumes that the disk data will not change
882
; outside of its control, such overlap could be destructive.
883
; outside of its control, such overlap could be destructive.
883
; Since the number of partitions is usually very small and is guaranteed not
884
; Since the number of partitions is usually very small and is guaranteed not
884
; to be large, the simple linear search is sufficient.
885
; to be large, the simple linear search is sufficient.
885
; 2a. Prepare the loop: edi will point to the current item of .Partitions
886
; 2a. Prepare the loop: edi will point to the current item of .Partitions
886
; array, ecx will be the current item, ebx will hold number of items left.
887
; array, ecx will be the current item, ebx will hold number of items left.
887
        mov     edi, [esi+DISK.Partitions]
888
        mov     edi, [esi+DISK.Partitions]
888
        mov     ebx, [esi+DISK.NumPartitions]
889
        mov     ebx, [esi+DISK.NumPartitions]
889
        test    ebx, ebx
890
        test    ebx, ebx
890
        jz      .partitionok
891
        jz      .partitionok
891
.scan_existing:
892
.scan_existing:
892
; 2b. Get the next partition.
893
; 2b. Get the next partition.
893
        mov     ecx, [edi]
894
        mov     ecx, [edi]
894
        add     edi, 4
895
        add     edi, 4
895
; The range [.FirstSector, .FirstSector+.Length) must be either entirely to
896
; The range [.FirstSector, .FirstSector+.Length) must be either entirely to
896
; the left of [start, start+length) or entirely to the right.
897
; the left of [start, start+length) or entirely to the right.
897
; 2c. Subtract .FirstSector - start. The possible overflow distinguish between
898
; 2c. Subtract .FirstSector - start. The possible overflow distinguish between
898
; cases "to the left" (2e) and "to the right" (2d).
899
; cases "to the left" (2e) and "to the right" (2d).
899
        mov     eax, dword [ecx+PARTITION.FirstSector]
900
        mov     eax, dword [ecx+PARTITION.FirstSector]
900
        mov     edx, dword [ecx+PARTITION.FirstSector+4]
901
        mov     edx, dword [ecx+PARTITION.FirstSector+4]
901
        sub     eax, dword [start]
902
        sub     eax, dword [start]
902
        sbb     edx, dword [start+4]
903
        sbb     edx, dword [start+4]
903
        jb      .less
904
        jb      .less
904
; 2d. .FirstSector is greater than or equal to start. Check that .FirstSector
905
; 2d. .FirstSector is greater than or equal to start. Check that .FirstSector
905
; is greater than or equal to start+length; the subtraction
906
; is greater than or equal to start+length; the subtraction
906
; (.FirstSector-start) - length must not cause overflow. Go to 2g if life is
907
; (.FirstSector-start) - length must not cause overflow. Go to 2g if life is
907
; good or to 2f in the other case.
908
; good or to 2f in the other case.
908
        sub     eax, dword [length]
909
        sub     eax, dword [length]
909
        sbb     edx, dword [length+4]
910
        sbb     edx, dword [length+4]
910
        jb      .overlap
911
        jb      .overlap
911
        jmp     .next_existing
912
        jmp     .next_existing
912
.less:
913
.less:
913
; 2e. .FirstSector is less than start. Check that .FirstSector+.Length is less
914
; 2e. .FirstSector is less than start. Check that .FirstSector+.Length is less
914
; than or equal to start. If the addition (.FirstSector-start) + .Length does
915
; than or equal to start. If the addition (.FirstSector-start) + .Length does
915
; not cause overflow, then .FirstSector + .Length is strictly less than start;
916
; not cause overflow, then .FirstSector + .Length is strictly less than start;
916
; since the equality is also valid, use decrement preliminarily. Go to 2g or
917
; since the equality is also valid, use decrement preliminarily. Go to 2g or
917
; 2f depending on the overflow.
918
; 2f depending on the overflow.
918
        sub     eax, 1
919
        sub     eax, 1
919
        sbb     edx, 0
920
        sbb     edx, 0
920
        add     eax, dword [ecx+PARTITION.Length]
921
        add     eax, dword [ecx+PARTITION.Length]
921
        adc     edx, dword [ecx+PARTITION.Length+4]
922
        adc     edx, dword [ecx+PARTITION.Length+4]
922
        jnc     .next_existing
923
        jnc     .next_existing
923
.overlap:
924
.overlap:
924
; 2f. The partition overlaps with previously registered partition. Say warning
925
; 2f. The partition overlaps with previously registered partition. Say warning
925
; and return with nothing done.
926
; and return with nothing done.
926
        dbgstr 'two partitions overlap, ignoring the last one'
927
        dbgstr 'two partitions overlap, ignoring the last one'
927
        jmp     .nothing
928
        jmp     .nothing
928
.next_existing:
929
.next_existing:
929
; 2g. The partition does not overlap with the current partition. Continue the
930
; 2g. The partition does not overlap with the current partition. Continue the
930
; loop.
931
; loop.
931
        dec     ebx
932
        dec     ebx
932
        jnz     .scan_existing
933
        jnz     .scan_existing
933
.partitionok:
934
.partitionok:
934
; 3. The partition has passed tests. Reallocate the partitions array for a new
935
; 3. The partition has passed tests. Reallocate the partitions array for a new
935
; entry.
936
; entry.
936
; 3a. Call the allocator.
937
; 3a. Call the allocator.
937
        mov     eax, [esi+DISK.NumPartitions]
938
        mov     eax, [esi+DISK.NumPartitions]
938
        inc     eax     ; one more entry
939
        inc     eax     ; one more entry
939
        shl     eax, 2  ; each entry is dword
940
        shl     eax, 2  ; each entry is dword
940
        call    malloc
941
        call    malloc
941
; 3b. Test the result. If failed, return with nothing done.
942
; 3b. Test the result. If failed, return with nothing done.
942
        test    eax, eax
943
        test    eax, eax
943
        jz      .nothing
944
        jz      .nothing
944
; 3c. Copy the old array to the new array.
945
; 3c. Copy the old array to the new array.
945
        mov     edi, eax
946
        mov     edi, eax
946
        push    esi
947
        push    esi
947
        mov     ecx, [esi+DISK.NumPartitions]
948
        mov     ecx, [esi+DISK.NumPartitions]
948
        mov     esi, [esi+DISK.Partitions]
949
        mov     esi, [esi+DISK.Partitions]
949
        rep movsd
950
        rep movsd
950
        pop     esi
951
        pop     esi
951
; 3d. Set the field in the DISK structure to the new array.
952
; 3d. Set the field in the DISK structure to the new array.
952
        xchg    [esi+DISK.Partitions], eax
953
        xchg    [esi+DISK.Partitions], eax
953
; 3e. Free the old array.
954
; 3e. Free the old array.
954
        call    free
955
        call    free
955
; 4. Recognize the file system.
956
; 4. Recognize the file system.
956
; 4a. Call the filesystem recognizer. It will allocate the PARTITION structure
957
; 4a. Call the filesystem recognizer. It will allocate the PARTITION structure
957
; with possible filesystem-specific fields.
958
; with possible filesystem-specific fields.
958
        call    disk_detect_partition
959
        call    disk_detect_partition
959
; 4b. Check return value. If zero, return with list not changed; so far only
960
; 4b. Check return value. If zero, return with list not changed; so far only
960
; the array was reallocated, this is ok for other code.
961
; the array was reallocated, this is ok for other code.
961
        test    eax, eax
962
        test    eax, eax
962
        jz      .nothing
963
        jz      .nothing
963
; 5. Insert the new partition to the list.
964
; 5. Insert the new partition to the list.
964
        stosd
965
        stosd
965
        inc     [esi+DISK.NumPartitions]
966
        inc     [esi+DISK.NumPartitions]
966
; 6. Return.
967
; 6. Return.
967
.nothing:
968
.nothing:
968
        ret
969
        ret
969
endp
970
endp
970
 
971
 
971
; This is an internal function called from disk_add_partition.
972
; This is an internal function called from disk_add_partition.
972
; It tries to recognize the file system on the partition and allocates the
973
; It tries to recognize the file system on the partition and allocates the
973
; corresponding PARTITION structure with filesystem-specific fields.
974
; corresponding PARTITION structure with filesystem-specific fields.
974
disk_detect_partition:
975
disk_detect_partition:
975
; This function inherits the stack frame from disk_add_partition. In stdcall
976
; This function inherits the stack frame from disk_add_partition. In stdcall
976
; with ebp-based frame arguments start from ebp+8, since [ebp]=saved ebp
977
; with ebp-based frame arguments start from ebp+8, since [ebp]=saved ebp
977
; and [ebp+4]=return address.
978
; and [ebp+4]=return address.
978
virtual at ebp+8
979
virtual at ebp+8
979
.start  dq      ?
980
.start  dq      ?
980
.length dq      ?
981
.length dq      ?
981
end virtual
982
end virtual
982
; When disk_add_partition is called, ebx contains a pointer to
983
; When disk_add_partition is called, ebx contains a pointer to
983
; a two-sectors-sized buffer. This function saves ebx in the stack
984
; a two-sectors-sized buffer. This function saves ebx in the stack
984
; immediately before ebp.
985
; immediately before ebp.
985
virtual at ebp-4
986
virtual at ebp-4
986
.buffer dd      ?
987
.buffer dd      ?
987
end virtual
988
end virtual
988
; 1. Read the bootsector to the buffer.
989
; 1. Read the bootsector to the buffer.
989
        mov     al, DISKFUNC.read
990
        mov     al, DISKFUNC.read
990
        mov     ebx, [.buffer]
991
        mov     ebx, [.buffer]
991
        add     ebx, 512
992
        add     ebx, 512
992
        push    1
993
        push    1
993
        stdcall disk_call_driver, ebx, dword [.start], dword [.start+4], esp
994
        stdcall disk_call_driver, ebx, dword [.start], dword [.start+4], esp
994
; 2. Run tests for all supported filesystems. If at least one test succeeded,
995
; 2. Run tests for all supported filesystems. If at least one test succeeded,
995
; go to 4.
996
; go to 4.
996
; For tests: qword [ebp+8] = partition start, qword [ebp+10h] = partition
997
; For tests: qword [ebp+8] = partition start, qword [ebp+10h] = partition
997
; length, [esp] = 0 if reading bootsector failed or 1 if succeeded,
998
; length, [esp] = 0 if reading bootsector failed or 1 if succeeded,
998
; ebx points to the buffer for bootsector.
999
; ebx points to the buffer for bootsector.
999
        call    fat_create_partition
1000
        call    fat_create_partition
1000
        test    eax, eax
1001
        test    eax, eax
1001
        jnz     .success
1002
        jnz     .success
1002
; 3. No file system has recognized the volume, so just allocate the PARTITION
1003
; 3. No file system has recognized the volume, so just allocate the PARTITION
1003
; structure without extra fields.
1004
; structure without extra fields.
1004
        push    sizeof.PARTITION
1005
        push    sizeof.PARTITION
1005
        pop     eax
1006
        pop     eax
1006
        call    malloc
1007
        call    malloc
1007
        test    eax, eax
1008
        test    eax, eax
1008
        jz      .nothing
1009
        jz      .nothing
1009
        mov     edx, dword [.start]
1010
        mov     edx, dword [.start]
1010
        mov     dword [eax+PARTITION.FirstSector], edx
1011
        mov     dword [eax+PARTITION.FirstSector], edx
1011
        mov     edx, dword [.start+4]
1012
        mov     edx, dword [.start+4]
1012
        mov     dword [eax+PARTITION.FirstSector+4], edx
1013
        mov     dword [eax+PARTITION.FirstSector+4], edx
1013
        mov     edx, dword [.length]
1014
        mov     edx, dword [.length]
1014
        mov     dword [eax+PARTITION.Length], edx
1015
        mov     dword [eax+PARTITION.Length], edx
1015
        mov     edx, dword [.length+4]
1016
        mov     edx, dword [.length+4]
1016
        mov     dword [eax+PARTITION.Length+4], edx
1017
        mov     dword [eax+PARTITION.Length+4], edx
1017
        mov     [eax+PARTITION.Disk], esi
1018
        mov     [eax+PARTITION.Disk], esi
1018
        and     [eax+PARTITION.FSUserFunctions], 0
1019
        and     [eax+PARTITION.FSUserFunctions], 0
1019
.success:
1020
.success:
1020
.nothing:
1021
.nothing:
1021
; 4. Return with eax = pointer to PARTITION or NULL.
1022
; 4. Return with eax = pointer to PARTITION or NULL.
1022
        pop     ecx
1023
        pop     ecx
1023
        ret
1024
        ret
1024
 
1025
 
1025
; This function is called from file_system_lfn.
1026
; This function is called from file_system_lfn.
1026
; This handler gets the control each time when fn 70 is called
1027
; This handler gets the control each time when fn 70 is called
1027
; with unknown item of root subdirectory.
1028
; with unknown item of root subdirectory.
1028
; in: esi -> name
1029
; in: esi -> name
1029
;     ebp = 0 or rest of name relative to esi
1030
;     ebp = 0 or rest of name relative to esi
1030
; out: if the handler processes path, it must not return in file_system_lfn,
1031
; out: if the handler processes path, it must not return in file_system_lfn,
1031
;      but instead pop return address and return directly to the caller
1032
;      but instead pop return address and return directly to the caller
1032
;      otherwise simply return
1033
;      otherwise simply return
1033
dyndisk_handler:
1034
dyndisk_handler:
1034
        push    ebx edi         ; save registers used in file_system_lfn
1035
        push    ebx edi         ; save registers used in file_system_lfn
1035
; 1. Acquire the mutex.
1036
; 1. Acquire the mutex.
1036
        mov     ecx, disk_list_mutex
1037
        mov     ecx, disk_list_mutex
1037
        call    mutex_lock
1038
        call    mutex_lock
1038
; 2. Loop over the list of DISK structures.
1039
; 2. Loop over the list of DISK structures.
1039
; 2a. Initialize.
1040
; 2a. Initialize.
1040
        mov     ebx, disk_list
1041
        mov     ebx, disk_list
1041
.scan:
1042
.scan:
1042
; 2b. Get the next item.
1043
; 2b. Get the next item.
1043
        mov     ebx, [ebx+DISK.Next]
1044
        mov     ebx, [ebx+DISK.Next]
1044
; 2c. Check whether the list is done. If so, go to 3.
1045
; 2c. Check whether the list is done. If so, go to 3.
1045
        cmp     ebx, disk_list
1046
        cmp     ebx, disk_list
1046
        jz      .notfound
1047
        jz      .notfound
1047
; 2d. Compare names. If names match, go to 5.
1048
; 2d. Compare names. If names match, go to 5.
1048
        mov     edi, [ebx+DISK.Name]
1049
        mov     edi, [ebx+DISK.Name]
1049
        push    esi
1050
        push    esi
1050
@@:
1051
@@:
1051
; esi points to the name from fs operation; it is terminated by zero or slash.
1052
; esi points to the name from fs operation; it is terminated by zero or slash.
1052
        lodsb
1053
        lodsb
1053
        test    al, al
1054
        test    al, al
1054
        jz      .eoin_dec
1055
        jz      .eoin_dec
1055
        cmp     al, '/'
1056
        cmp     al, '/'
1056
        jz      .eoin
1057
        jz      .eoin
1057
; edi points to the disk name.
1058
; edi points to the disk name.
1058
        inc     edi
1059
        inc     edi
1059
; edi points to lowercase name, this is a requirement for the driver.
1060
; edi points to lowercase name, this is a requirement for the driver.
1060
; Characters at esi can have any register. Lowercase the current character.
1061
; Characters at esi can have any register. Lowercase the current character.
1061
; This lowercasing works for latin letters and digits; since the disk name
1062
; This lowercasing works for latin letters and digits; since the disk name
1062
; should not contain other symbols, this is ok.
1063
; should not contain other symbols, this is ok.
1063
        or      al, 20h
1064
        or      al, 20h
1064
        cmp     al, [edi-1]
1065
        cmp     al, [edi-1]
1065
        jz      @b
1066
        jz      @b
1066
.wrongname:
1067
.wrongname:
1067
; 2f. Names don't match. Continue the loop.
1068
; 2f. Names don't match. Continue the loop.
1068
        pop     esi
1069
        pop     esi
1069
        jmp     .scan
1070
        jmp     .scan
1070
.notfound:
1071
.notfound:
1071
; The loop is done and no name matches.
1072
; The loop is done and no name matches.
1072
; 3. Release the mutex.
1073
; 3. Release the mutex.
1073
        call    mutex_unlock
1074
        call    mutex_unlock
1074
; 4. Return normally.
1075
; 4. Return normally.
1075
        pop     edi ebx         ; restore registers used in file_system_lfn
1076
        pop     edi ebx         ; restore registers used in file_system_lfn
1076
        ret
1077
        ret
1077
; part of 2d: the name matches partially, but we must check that this is full
1078
; part of 2d: the name matches partially, but we must check that this is full
1078
; equality.
1079
; equality.
1079
.eoin_dec:
1080
.eoin_dec:
1080
        dec     esi
1081
        dec     esi
1081
.eoin:
1082
.eoin:
1082
        cmp     byte [edi], 0
1083
        cmp     byte [edi], 0
1083
        jnz     .wrongname
1084
        jnz     .wrongname
1084
; We found the addressed DISK structure.
1085
; We found the addressed DISK structure.
1085
; 5. Reference the disk.
1086
; 5. Reference the disk.
1086
        lock inc [ebx+DISK.RefCount]
1087
        lock inc [ebx+DISK.RefCount]
1087
; 6. Now we are sure that the DISK structure is not going to die at least
1088
; 6. Now we are sure that the DISK structure is not going to die at least
1088
; while we are working with it, so release the global mutex.
1089
; while we are working with it, so release the global mutex.
1089
        call    mutex_unlock
1090
        call    mutex_unlock
1090
        pop     ecx             ; pop from the stack saved value of esi
1091
        pop     ecx             ; pop from the stack saved value of esi
1091
; 7. Acquire the mutex for media object.
1092
; 7. Acquire the mutex for media object.
1092
        pop     edi             ; restore edi
1093
        pop     edi             ; restore edi
1093
        lea     ecx, [ebx+DISK.MediaLock]
1094
        lea     ecx, [ebx+DISK.MediaLock]
1094
        call    mutex_lock
1095
        call    mutex_lock
1095
; 8. Get the media object. If it is not NULL, reference it.
1096
; 8. Get the media object. If it is not NULL, reference it.
1096
        xor     edx, edx
1097
        xor     edx, edx
1097
        cmp     [ebx+DISK.MediaInserted], dl
1098
        cmp     [ebx+DISK.MediaInserted], dl
1098
        jz      @f
1099
        jz      @f
1099
        mov     edx, ebx
1100
        mov     edx, ebx
1100
        inc     [ebx+DISK.MediaRefCount]
1101
        inc     [ebx+DISK.MediaRefCount]
1101
@@:
1102
@@:
1102
; 9. Now we are sure that the media object, if it exists, is not going to die
1103
; 9. Now we are sure that the media object, if it exists, is not going to die
1103
; at least while we are working with it, so release the mutex for media object.
1104
; at least while we are working with it, so release the mutex for media object.
1104
        call    mutex_unlock
1105
        call    mutex_unlock
1105
        mov     ecx, ebx
1106
        mov     ecx, ebx
1106
        pop     ebx eax         ; restore ebx, pop return address
1107
        pop     ebx eax         ; restore ebx, pop return address
1107
; 10. Check whether the fs operation wants to enumerate partitions (go to 11)
1108
; 10. Check whether the fs operation wants to enumerate partitions (go to 11)
1108
; or work with some concrete partition (go to 12).
1109
; or work with some concrete partition (go to 12).
1109
        cmp     byte [esi], 0
1110
        cmp     byte [esi], 0
1110
        jnz     .haspartition
1111
        jnz     .haspartition
1111
; 11. The fs operation wants to enumerate partitions.
1112
; 11. The fs operation wants to enumerate partitions.
1112
; 11a. Only "list directory" operation is applicable to / path. Check
1113
; 11a. Only "list directory" operation is applicable to / path. Check
1113
; the operation code. If wrong, go to 13.
1114
; the operation code. If wrong, go to 13.
1114
        cmp     dword [ebx], 1
1115
        cmp     dword [ebx], 1
1115
        jnz     .access_denied
1116
        jnz     .access_denied
1116
; 11b. If the media is inserted, use 'fs_dyndisk_next' as an enumeration
1117
; 11b. If the media is inserted, use 'fs_dyndisk_next' as an enumeration
1117
; procedure. Otherwise, use 'fs_dyndisk_next_nomedia'.
1118
; procedure. Otherwise, use 'fs_dyndisk_next_nomedia'.
1118
        mov     esi, fs_dyndisk_next_nomedia
1119
        mov     esi, fs_dyndisk_next_nomedia
1119
        test    edx, edx
1120
        test    edx, edx
1120
        jz      @f
1121
        jz      @f
1121
        mov     esi, fs_dyndisk_next
1122
        mov     esi, fs_dyndisk_next
1122
@@:
1123
@@:
1123
; 11c. Let the procedure from fs_lfn.inc do the job.
1124
; 11c. Let the procedure from fs_lfn.inc do the job.
1124
        jmp     file_system_lfn.maindir_noesi
1125
        jmp     file_system_lfn.maindir_noesi
1125
.haspartition:
1126
.haspartition:
1126
; 12. The fs operation has specified some partition.
1127
; 12. The fs operation has specified some partition.
1127
; 12a. Store parameters for callback functions.
1128
; 12a. Store parameters for callback functions.
1128
        push    edx
1129
        push    edx
1129
        push    ecx
1130
        push    ecx
1130
; 12b. Store callback functions.
1131
; 12b. Store callback functions.
1131
        push    dyndisk_cleanup
1132
        push    dyndisk_cleanup
1132
        push    fs_dyndisk
1133
        push    fs_dyndisk
1133
        mov     edi, esp
1134
        mov     edi, esp
1134
; 12c. Let the procedure from fs_lfn.inc do the job.
1135
; 12c. Let the procedure from fs_lfn.inc do the job.
1135
        jmp     file_system_lfn.found2
1136
        jmp     file_system_lfn.found2
1136
.access_denied:
1137
.access_denied:
1137
; 13. Fail the operation with the appropriate code.
1138
; 13. Fail the operation with the appropriate code.
1138
        mov     dword [esp+32], ERROR_ACCESS_DENIED
1139
        mov     dword [esp+32], ERROR_ACCESS_DENIED
1139
.cleanup:
1140
.cleanup:
1140
; 14. Cleanup.
1141
; 14. Cleanup.
1141
        mov     esi, ecx        ; disk*dereference assume that esi points to DISK
1142
        mov     esi, ecx        ; disk*dereference assume that esi points to DISK
1142
.cleanup_esi:
1143
.cleanup_esi:
1143
        test    edx, edx        ; if there are no media, we didn't reference it
1144
        test    edx, edx        ; if there are no media, we didn't reference it
1144
        jz      @f
1145
        jz      @f
1145
        call    disk_media_dereference
1146
        call    disk_media_dereference
1146
@@:
1147
@@:
1147
        call    disk_dereference
1148
        call    disk_dereference
1148
; 15. Return.
1149
; 15. Return.
1149
        ret
1150
        ret
1150
 
1151
 
1151
; This is a callback for cleaning up things called from file_system_lfn.found2.
1152
; This is a callback for cleaning up things called from file_system_lfn.found2.
1152
dyndisk_cleanup:
1153
dyndisk_cleanup:
1153
        mov     esi, [edi+8]
1154
        mov     esi, [edi+8]
1154
        mov     edx, [edi+12]
1155
        mov     edx, [edi+12]
1155
        jmp     dyndisk_handler.cleanup_esi
1156
        jmp     dyndisk_handler.cleanup_esi
1156
 
1157
 
1157
; This is a callback for enumerating partitions called from
1158
; This is a callback for enumerating partitions called from
1158
; file_system_lfn.maindir in the case of inserted media.
1159
; file_system_lfn.maindir in the case of inserted media.
1159
; It just increments eax until DISK.NumPartitions reached and then
1160
; It just increments eax until DISK.NumPartitions reached and then
1160
; cleans up.
1161
; cleans up.
1161
fs_dyndisk_next:
1162
fs_dyndisk_next:
1162
        cmp     eax, [ecx+DISK.NumPartitions]
1163
        cmp     eax, [ecx+DISK.NumPartitions]
1163
        jae     .nomore
1164
        jae     .nomore
1164
        inc     eax
1165
        inc     eax
1165
        clc
1166
        clc
1166
        ret
1167
        ret
1167
.nomore:
1168
.nomore:
1168
        pusha
1169
        pusha
1169
        mov     esi, ecx
1170
        mov     esi, ecx
1170
        call    disk_media_dereference
1171
        call    disk_media_dereference
1171
        call    disk_dereference
1172
        call    disk_dereference
1172
        popa
1173
        popa
1173
        stc
1174
        stc
1174
        ret
1175
        ret
1175
 
1176
 
1176
; This is a callback for enumerating partitions called from
1177
; This is a callback for enumerating partitions called from
1177
; file_system_lfn.maindir in the case of missing media.
1178
; file_system_lfn.maindir in the case of missing media.
1178
; In this case we create one pseudo-partition.
1179
; In this case we create one pseudo-partition.
1179
fs_dyndisk_next_nomedia:
1180
fs_dyndisk_next_nomedia:
1180
        cmp     eax, 1
1181
        cmp     eax, 1
1181
        jae     .nomore
1182
        jae     .nomore
1182
        inc     eax
1183
        inc     eax
1183
        clc
1184
        clc
1184
        ret
1185
        ret
1185
.nomore:
1186
.nomore:
1186
        pusha
1187
        pusha
1187
        mov     esi, ecx
1188
        mov     esi, ecx
1188
        call    disk_dereference
1189
        call    disk_dereference
1189
        popa
1190
        popa
1190
        stc
1191
        stc
1191
        ret
1192
        ret
1192
 
1193
 
1193
; This is a callback for doing real work with selected partition.
1194
; This is a callback for doing real work with selected partition.
1194
; Currently this is just placeholder, since no file systems are supported.
1195
; Currently this is just placeholder, since no file systems are supported.
1195
; edi = esp -> {dd fs_dyndisk, dd dyndisk_cleanup, dd pointer to DISK, dd media object}
1196
; edi = esp -> {dd fs_dyndisk, dd dyndisk_cleanup, dd pointer to DISK, dd media object}
1196
; ecx = partition number, esi+ebp = ASCIIZ name
1197
; ecx = partition number, esi+ebp = ASCIIZ name
1197
fs_dyndisk:
1198
fs_dyndisk:
1198
        dec     ecx     ; convert to zero-based partition index
1199
        dec     ecx     ; convert to zero-based partition index
1199
        pop     edx edx edx eax ; edx = pointer to DISK, eax = NULL or edx
1200
        pop     edx edx edx eax ; edx = pointer to DISK, eax = NULL or edx
1200
        test    eax, eax
1201
        test    eax, eax
1201
        jz      .nomedia
1202
        jz      .nomedia
1202
.main:
1203
.main:
1203
        cmp     ecx, [edx+DISK.NumPartitions]
1204
        cmp     ecx, [edx+DISK.NumPartitions]
1204
        jae     .notfound
1205
        jae     .notfound
1205
        mov     eax, [edx+DISK.Partitions]
1206
        mov     eax, [edx+DISK.Partitions]
1206
        mov     eax, [eax+ecx*4]
1207
        mov     eax, [eax+ecx*4]
1207
        mov     edi, [eax+PARTITION.FSUserFunctions]
1208
        mov     edi, [eax+PARTITION.FSUserFunctions]
1208
        test    edi, edi
1209
        test    edi, edi
1209
        jz      .nofs
1210
        jz      .nofs
1210
        mov     ecx, [ebx]
1211
        mov     ecx, [ebx]
1211
        cmp     [edi], ecx
1212
        cmp     [edi], ecx
1212
        jbe     .unsupported
1213
        jbe     .unsupported
1213
        push    edx
1214
        push    edx
1214
        push    ebp
1215
        push    ebp
1215
        mov     ebp, eax
1216
        mov     ebp, eax
1216
        call    dword [edi+4+ecx*4]
1217
        call    dword [edi+4+ecx*4]
1217
        pop     ebp
1218
        pop     ebp
1218
        pop     edx
1219
        pop     edx
1219
        mov     dword [esp+32], eax
1220
        mov     dword [esp+32], eax
1220
        mov     dword [esp+20], ebx
1221
        mov     dword [esp+20], ebx
1221
.cleanup:
1222
.cleanup:
1222
        mov     esi, edx
1223
        mov     esi, edx
1223
        call    disk_media_dereference
1224
        call    disk_media_dereference
1224
        call    disk_dereference
1225
        call    disk_dereference
1225
        ret
1226
        ret
1226
.nofs:
1227
.nofs:
1227
        mov     dword [esp+32], ERROR_UNKNOWN_FS
1228
        mov     dword [esp+32], ERROR_UNKNOWN_FS
1228
        jmp     .cleanup
1229
        jmp     .cleanup
1229
.notfound:
1230
.notfound:
1230
        mov     dword [esp+32], ERROR_FILE_NOT_FOUND
1231
        mov     dword [esp+32], ERROR_FILE_NOT_FOUND
1231
        jmp     .cleanup
1232
        jmp     .cleanup
1232
.unsupported:
1233
.unsupported:
1233
        mov     dword [esp+32], ERROR_UNSUPPORTED_FS
1234
        mov     dword [esp+32], ERROR_UNSUPPORTED_FS
1234
        jmp     .cleanup
1235
        jmp     .cleanup
1235
.nomedia:
1236
.nomedia:
1236
        test    ecx, ecx
1237
        test    ecx, ecx
1237
        jnz     .notfound
1238
        jnz     .notfound
1238
        test    byte [edx+DISK.DriverFlags], DISK_NO_INSERT_NOTIFICATION
1239
        test    byte [edx+DISK.DriverFlags], DISK_NO_INSERT_NOTIFICATION
1239
        jz      .deverror
1240
        jz      .deverror
1240
; if the driver does not support insert notifications and we are the only fs
1241
; if the driver does not support insert notifications and we are the only fs
1241
; operation with this disk, issue the fake insert notification; if media is
1242
; operation with this disk, issue the fake insert notification; if media is
1242
; still not inserted, 'disk_media_changed' will detect this and do nothing
1243
; still not inserted, 'disk_media_changed' will detect this and do nothing
1243
        lea     ecx, [edx+DISK.MediaLock]
1244
        lea     ecx, [edx+DISK.MediaLock]
1244
        call    mutex_lock
1245
        call    mutex_lock
1245
        cmp     [edx+DISK.MediaRefCount], 1
1246
        cmp     [edx+DISK.MediaRefCount], 1
1246
        jnz     .noluck
1247
        jnz     .noluck
1247
        call    mutex_unlock
1248
        call    mutex_unlock
1248
        push    edx
1249
        push    edx
1249
        stdcall disk_media_changed, edx, 1
1250
        stdcall disk_media_changed, edx, 1
1250
        pop     edx
1251
        pop     edx
1251
        lea     ecx, [edx+DISK.MediaLock]
1252
        lea     ecx, [edx+DISK.MediaLock]
1252
        call    mutex_lock
1253
        call    mutex_lock
1253
        cmp     [edx+DISK.MediaInserted], 0
1254
        cmp     [edx+DISK.MediaInserted], 0
1254
        jz      .noluck
1255
        jz      .noluck
1255
        lock inc [edx+DISK.MediaRefCount]
1256
        lock inc [edx+DISK.MediaRefCount]
1256
        call    mutex_unlock
1257
        call    mutex_unlock
1257
        xor     ecx, ecx
1258
        xor     ecx, ecx
1258
        jmp     .main
1259
        jmp     .main
1259
.noluck:
1260
.noluck:
1260
        call    mutex_unlock
1261
        call    mutex_unlock
1261
.deverror:
1262
.deverror:
1262
        mov     dword [esp+32], ERROR_DEVICE
1263
        mov     dword [esp+32], ERROR_DEVICE
1263
        mov     esi, edx
1264
        mov     esi, edx
1264
        call    disk_dereference
1265
        call    disk_dereference
1265
        ret
1266
        ret
1266
 
1267
 
1267
; This function is called from file_system_lfn.
1268
; This function is called from file_system_lfn.
1268
; This handler is called when virtual root is enumerated
1269
; This handler is called when virtual root is enumerated
1269
; and must return all items which can be handled by this.
1270
; and must return all items which can be handled by this.
1270
; It is called several times, first time with eax=0
1271
; It is called several times, first time with eax=0
1271
; in: eax = 0 for first call, previously returned value for subsequent calls
1272
; in: eax = 0 for first call, previously returned value for subsequent calls
1272
; out: eax = 0 => no more items
1273
; out: eax = 0 => no more items
1273
;      eax != 0 => buffer pointed to by edi contains name of item
1274
;      eax != 0 => buffer pointed to by edi contains name of item
1274
dyndisk_enum_root:
1275
dyndisk_enum_root:
1275
        push    edx             ; save register used in file_system_lfn
1276
        push    edx             ; save register used in file_system_lfn
1276
        mov     ecx, disk_list_mutex    ; it will be useful
1277
        mov     ecx, disk_list_mutex    ; it will be useful
1277
; 1. If this is the first call, acquire the mutex and initialize.
1278
; 1. If this is the first call, acquire the mutex and initialize.
1278
        test    eax, eax
1279
        test    eax, eax
1279
        jnz     .notfirst
1280
        jnz     .notfirst
1280
        call    mutex_lock
1281
        call    mutex_lock
1281
        mov     eax, disk_list
1282
        mov     eax, disk_list
1282
.notfirst:
1283
.notfirst:
1283
; 2. Get next item.
1284
; 2. Get next item.
1284
        mov     eax, [eax+DISK.Next]
1285
        mov     eax, [eax+DISK.Next]
1285
; 3. If there are no more items, go to 6.
1286
; 3. If there are no more items, go to 6.
1286
        cmp     eax, disk_list
1287
        cmp     eax, disk_list
1287
        jz      .last
1288
        jz      .last
1288
; 4. Copy name from the DISK structure to edi.
1289
; 4. Copy name from the DISK structure to edi.
1289
        push    eax esi
1290
        push    eax esi
1290
        mov     esi, [eax+DISK.Name]
1291
        mov     esi, [eax+DISK.Name]
1291
@@:
1292
@@:
1292
        lodsb
1293
        lodsb
1293
        stosb
1294
        stosb
1294
        test    al, al
1295
        test    al, al
1295
        jnz     @b
1296
        jnz     @b
1296
        pop     esi eax
1297
        pop     esi eax
1297
; 5. Return with eax = item.
1298
; 5. Return with eax = item.
1298
        pop     edx             ; restore register used in file_system_lfn
1299
        pop     edx             ; restore register used in file_system_lfn
1299
        ret
1300
        ret
1300
.last:
1301
.last:
1301
; 6. Release the mutex and return with eax = 0.
1302
; 6. Release the mutex and return with eax = 0.
1302
        call    mutex_unlock
1303
        call    mutex_unlock
1303
        xor     eax, eax
1304
        xor     eax, eax
1304
        pop     edx             ; restore register used in file_system_lfn
1305
        pop     edx             ; restore register used in file_system_lfn
1305
        ret
1306
        ret