Subversion Repositories Kolibri OS

Rev

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

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