source: trunk/bootcode/special/lvm.asm@ 98

Last change on this file since 98 was 98, checked in by Ben Rietbroek, 8 years ago

Moved LVM sector validation funtion to 'lvm' module [v1.1.1-testing]

CAUTION:
This is a testbuild !
AirBoot uses the BIOS to access disks and a small coding error can trash
partition tables or other vital disk structures. You are advised to make
backups of TRACK0 and EBRs before using this testbuild. More info at:
https://rousseaux.github.io/netlabs.air-boot/pdf/AirBoot-v1.1.0-manual.pdf

File size: 20.8 KB
Line 
1; AiR-BOOT (c) Copyright 1998-2008 M. Kiewitz
2;
3; This file is part of AiR-BOOT
4;
5; AiR-BOOT is free software: you can redistribute it and/or modify it under
6; the terms of the GNU General Public License as published by the Free
7; Software Foundation, either version 3 of the License, or (at your option)
8; any later version.
9;
10; AiR-BOOT is distributed in the hope that it will be useful, but WITHOUT ANY
11; WARRANTY: without even the implied warranty of MERCHANTABILITY or FITNESS
12; FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
13; details.
14;
15; You should have received a copy of the GNU General Public License along with
16; AiR-BOOT. If not, see <http://www.gnu.org/licenses/>.
17;
18;---------------------------------------------------------------------------
19; AiR-BOOT / LVM
20;---------------------------------------------------------------------------
21
22IFDEF MODULE_NAMES
23DB 'LVM',0
24ENDIF
25
26LVM_InitCRCTable Proc Near
27 ; Initializes our LVM-CRC-Table
28 xor cl, cl
29 mov di, offset [LVM_CRCTable]
30 LVM_ICRCT_Loop:
31 ;movzx ax, cl
32 mov al,cl
33 mov ah,0
34 xor dx, dx ; DX:AX - CRC-Value
35 mov ch, 8
36 LVM_ICRCT_Loop2:
37 shr dx, 1
38 rcr ax, 1 ; Shift value 1 to the right
39 jnc LVM_ICRCT_NoXOR
40 xor dx, 0EDB8h
41 xor ax, 8320h
42 LVM_ICRCT_NoXOR:
43 dec ch
44 jnz LVM_ICRCT_Loop2
45 mov wptr [di+0], ax
46 mov wptr [di+2], dx
47 add di, 4
48 add cl, 1
49 jnc LVM_ICRCT_Loop
50 ret
51LVM_InitCRCTable EndP
52
53; Calculates an LVM-Sector CRC of a given sector
54; In: DS:SI - Points to Sector...
55; Out: DX:AX - LVM CRC
56; Destroyed: None
57LVM_GetSectorCRC Proc Near Uses bx cx
58 push word ptr [si+LocLVM_CRC+00]
59 push word ptr [si+LocLVM_CRC+02]
60 push si
61 mov word ptr [si+LocLVM_CRC], 0
62 mov word ptr [si+LocLVM_CRC+2], 0
63 mov ax, -1
64 mov dx, -1
65 mov cx, 512
66 LVM_GSCRC_Loop:
67 xor bh, bh
68 mov bl, al ; Save last byte to BL
69 mov al, ah
70 mov ah, dl
71 mov dl, dh
72 xor dh, dh ; SHR DX:AX, 8
73 xor bl, [si]
74 inc si ; XOR last byte with [data]
75 shl bx, 1
76 shl bx, 1
77 xor ax, word ptr [LVM_CRCTable+bx+0]
78 xor dx, word ptr [LVM_CRCTable+bx+2] ; XOR with CRC-Table
79 loop LVM_GSCRC_Loop
80 pop si
81 pop word ptr [si+LocLVM_CRC+2]
82 pop word ptr [si+LocLVM_CRC]
83 ret
84LVM_GetSectorCRC EndP
85
86; Checks ds:[SI], if a valid LVM Signature is found (sets carry in that case)
87; This does not check for valid LVM CRC (which also needs to be done)
88; In: DS:SI - Sector that needs to get checked...
89; Out: Carry set, if valid LVM signature found
90; Destroyed: None
91LVM_CheckSectorSignature Proc Near
92 test byte ptr [CFG_IgnoreLVM], 1 ; We are supposed to ignore LVM, so
93 jnz LVMCSS_InvalidSignature ; any sector is bad!
94 cmp word ptr [si+LocLVM_SignatureStart], 5202h
95 jne LVMCSS_InvalidSignature
96 cmp word ptr [si+LocLVM_SignatureStart+2], 'BM'
97 jne LVMCSS_InvalidSignature
98 cmp word ptr [si+LocLVM_SignatureStart+4], 'MP'
99 jne LVMCSS_InvalidSignature
100 cmp word ptr [si+LocLVM_SignatureStart+6], 'DF'
101 jne LVMCSS_InvalidSignature
102 stc
103 ret
104 LVMCSS_InvalidSignature:
105 clc
106 ret
107LVM_CheckSectorSignature EndP
108
109; Checks Sector for a valid LVM CRC is encountered
110; First one should check for a valid signature and call this later.
111; In: DS:SI - Sector that needs to get checked...
112; Out: Carry set, if LVM CRC valid
113; Destroyed: None
114LVM_CheckSectorCRC Proc Near Uses ax dx
115 call LVM_GetSectorCRC
116 cmp ax, word ptr [si+LocLVM_CRC]
117 jne LVMCSCRC_BadCRC
118 cmp dx, word ptr [si+LocLVM_CRC+2]
119 jne LVMCSCRC_BadCRC
120 stc
121 ret
122 LVMCSCRC_BadCRC:
123 clc
124 ret
125LVM_CheckSectorCRC EndP
126
127; See if a LVM-sector is valid.
128; In : si, pointer to sector
129; Out : CY if valid LVM sector, NC if not
130DriveIO_LVMSectorValid Proc Near
131 pusha
132
133 call LVM_CheckSectorSignature
134 ; NC if no signature found
135 jnc DriveIO_LVMSectorValid_End
136
137 call LVM_CheckSectorCRC
138 ; Force valid !!!
139 stc
140
141 DriveIO_LVMSectorValid_End:
142 popa
143 ret
144DriveIO_LVMSectorValid EndP
145
146; Updates Sector with valid LVM CRC
147; This one doesn't check, if it's really an LVM sector, so check before!
148; In: DS:SI - Sector that needs to get checked...
149; Out: None, CRC updated
150; Destroyed: None
151LVM_UpdateSectorCRC Proc Near Uses ax dx
152 call LVM_GetSectorCRC
153 mov word ptr [si+LocLVM_CRC], ax
154 mov word ptr [si+LocLVM_CRC+2], dx
155 ret
156LVM_UpdateSectorCRC EndP
157
158; Searches for a partition in LVM Information Sector and sets SI to point to
159; the LVM-entry. It will also set CARRY then.
160; In: DX:AX - LBA starting sector of partition to be searched
161; DS:SI - Valid (previously checked) LVM-Information-Sector
162; Out: Carry set, if partition found
163; DS:SI - points to LVM information entry
164; Destroyed: None
165LVM_SearchForPartition Proc Near Uses cx
166 cmp byte ptr [si+LocLVM_SignatureStart], LocLVM_SignatureByte0
167 jne LVMSFP_NotFound ; Quick Check, if LVM sector there
168 add si, LocLVM_StartOfEntries
169 mov cl, LocLVM_MaxEntries
170 LVMSFP_Loop:
171 cmp ax, [si+LocLVM_PartitionStart]
172 jne LVMSFP_NextEntry
173 cmp dx, [si+LocLVM_PartitionStart+2]
174 je LVMSFP_FoundIt
175 LVMSFP_NextEntry:
176 add si, LocLVM_LenOfEntry
177 dec cl
178 jnz LVMSFP_Loop
179 LVMSFP_NotFound:
180 clc
181 ret
182 LVMSFP_FoundIt:
183 stc
184 ret
185LVM_SearchForPartition EndP
186
187
188; Gets a drive-letter from the LVM-info of a partition. (if it exists)
189; In: BX:CX - LBA starting sector of partition to be searched
190; DL = Physical Disk in BIOS notation. (80h+)
191; Out: CY=1 if LVM-info found, 0 if no LVM-info.
192; AL - drive-letter from LVM-info or zero if no drive-letter
193; assigned or no LVM-info.
194LVM_GetDriveLetter Proc Near Uses bx cx dx si di ds es
195 ; For primary partitions this information is stored in the last
196 ; sector of track0; for all four partition entries in case they
197 ; they are all primary ones.
198 ;
199 ; LVM DLAT info for logical partitions is stored in the sector
200 ; preceding the start of the partition.
201 ;
202 ; Because the LVM info of a logical partition is the easiest to find,
203 ; we do that first. The LVM info for primary partitions is located
204 ; dependent on the geometry in use, so we use a special locater
205 ; call for that. Also, since the LVM info for primaries contains
206 ; info on all 4 entries, we need the partition index to obtain the
207 ; correct drive-letter.
208 ;
209
210 ; See if this is a primary partition
211 ; CY will be set if it is and AL will contain the 0-based
212 ; index in the P-table.
213 ; If it's a logical partition, CY will be clear and AL
214 ; will be set to 0ffh indicating an invalid index.
215 call PART_IsPrimaryPartition
216 mov al,0
217 rcl al,1 ; CY if primary
218 mov dh,al ; Save PRI or LOG
219
220 ; Save PRI/LOG indicator for later use
221 push dx
222
223 ; Load *possible* LVM sector
224 ; This load is only valid if the partition is logical, in which case
225 ; the LVM sector is below the start of the partition.
226 ; If primary, the LVM sector is at a location that
227 ; DriveIO_LoadMasterLVMSector will find out.
228
229 ; Push LBA address
230 push bx
231 push cx
232
233 ; Adjust for logical LVM-sector
234 sub cx,1
235 sbb bx,0
236
237 ; Load the LVM sector
238 push si
239 push di
240 mov si,offset [LVMSector]
241 mov di,ds
242 call DriveIO_LoadSectorLBA ; Change this to normal IO-routine !!!!!!
243 pop di
244 pop si
245
246 ; Restore LBA address
247 pop cx
248 pop bx
249
250 ; Restore PRI/LOG partition indicator in DH
251 pop dx
252
253 ; Test PRI or not
254 test dh,dh
255 ; It's not a PRI so we can use the previously loaded LVM sector
256 jz LVM_GetDriveLetter_is_not_pri
257
258 ;
259 ; It's a PRI so we use the special locator function.
260 ; This locator takes care of extended OS/2 geometry should that be used
261 ;
262 call DriveIO_LoadMasterLVMSector
263
264 LVM_GetDriveLetter_is_not_pri:
265
266
267 ;
268 ; At this stage the LVM-info sector has been loaded at [LVMSector].
269 ; From here we look for an LVM entry for the partition.
270 ; If one is found, based on it's LBA-start, it's driveletter is used
271 ; in case byte 25h in the BPB is zero.
272 ;
273
274
275 ; Search for the partition in the LVM info.
276 ; If found, CY is set and SI points to LVM entry.
277 push si
278 mov ax,cx
279 mov dx,bx
280 mov si,offset [LVMSector]
281 call LVM_SearchForPartition
282 mov bx,si ; BX now points to LVM entry
283 mov dx,0
284 pop si
285
286 mov al,0 ; Setup null driveletter
287 ; Oops, no valid LVM record was used so we have a null driveletter.
288 jnc LVM_GetDriveLetter_null_lvm_dl
289
290 ;
291 ; At this point BX points to the LVM-entry related to the
292 ; partition, whether it was a logical or a primary one.
293 ;
294 mov al,[bx+LocLVM_VolumeLetter]
295 ; Test for zero dtive-letter.
296 test al,al
297 ; Preset CY in case drive-letter is zero.
298 clc
299 jz LVM_GetDriveLetter_null_lvm_dl
300
301 ; We have a non-zero drive-letter, so set CY.
302 stc
303
304 LVM_GetDriveLetter_null_lvm_dl:
305 ret
306LVM_GetDriveLetter EndP
307
308
309
310; Sets a drive-letter in the LVM-info of a partition. (if it exists)
311; In: BX:CX - LBA starting sector of partition to be searched
312; DL = Physical Disk in BIOS notation. (80h+)
313; AL = DriveLetter to set (can be zero to hide partition from LVM)
314; Out: CY=1 if LVM-info found, 0 if no LVM-info.
315LVM_SetDriveLetter Proc Near Uses bx cx dx si di ds es
316 local disk:byte
317 local drive_letter:byte
318 local pri_ind:byte
319 local lvm_log_high:word
320 local lvm_log_low:word
321 ; For primary partitions this information is stored in the last
322 ; sector of track0; for all four partition entries in case they
323 ; they are all primary ones.
324 ;
325 ; LVM DLAT info for logical partitions is stored in the sector
326 ; preceding the start of the partition.
327 ;
328 ; Because the LVM info of a logical partition is the easiest to find,
329 ; we do that first. The LVM info for primary partitions is located
330 ; dependent on the geometry in use, so we use a special locater
331 ; call for that. Also, since the LVM info for primaries contains
332 ; info on all 4 entries, we need the partition index to obtain the
333 ; correct drive-letter.
334 ;
335
336 mov [disk], dl
337
338 ; Store the drive-letter for later use
339 mov [drive_letter], al
340
341
342 ; See if this is a primary partition
343 ; CY will be set if it is and AL will contain the 0-based
344 ; index in the P-table.
345 ; If it's a logical partition, CY will be clear and AL
346 ; will be set to 0ffh indicating an invalid index.
347 call PART_IsPrimaryPartition
348 mov al,0
349 rcl al,1 ; CY if primary
350 mov dh,al ; Save PRI or LOG
351 mov [pri_ind],al
352
353 ; Save PRI/LOG indicator for later use
354 push dx
355
356 ; Load *possible* LVM sector
357 ; This load is only valid if the partition is logical, in which case
358 ; the LVM sector is below the start of the partition.
359 ; If primary, the LVM sector is at a location that
360 ; DriveIO_LoadMasterLVMSector will find out.
361
362 ; Push LBA address
363 push bx
364 push cx
365
366 ; Adjust for logical LVM-sector
367 sub cx,1
368 sbb bx,0
369
370 ; Store LBA address of LVM-sector
371 mov [lvm_log_low],cx
372 mov [lvm_log_high],bx
373
374 ; Load the LVM sector
375 push si
376 push di
377 mov si,offset [LVMSector]
378 mov di,ds
379 call DriveIO_LoadSectorLBA ; Change this to normal IO-routine !!!!!!
380 pop di
381 pop si
382
383 ; Restore LBA address
384 pop cx
385 pop bx
386
387 ; Restore PRI/LOG partition indicator in DH
388 pop dx
389
390 ; Test PRI or not
391 test dh,dh
392 ; It's not a PRI so we can use the previously loaded LVM sector
393 jz LVM_SetDriveLetter_is_not_pri
394
395 ;
396 ; It's a PRI so we use the special locator function.
397 ; This locator takes care of extended OS/2 geometry should that be used
398 ;
399 call DriveIO_LoadMasterLVMSector
400 jnc LVM_SetDriveLetter_null_lvm_dl
401
402 mov ax, word ptr [MasterLVMLBA] ; ARRAY VAN MAKEN !
403 mov [lvm_log_low], ax
404 mov [lvm_log_high], 0
405
406 LVM_SetDriveLetter_is_not_pri:
407
408 ;
409 ; At this stage the LVM-info sector has been loaded at [LVMSector].
410 ; From here we look for an LVM entry for the partition.
411 ; If one is found, based on it's LBA-start, it's driveletter is used
412 ; in case byte 25h in the BPB is zero.
413 ;
414
415 ; Search for the partition in the LVM info.
416 ; If found, CY is set and SI points to LVM entry.
417 push si
418 mov ax,cx
419 mov dx,bx
420 mov si,offset [LVMSector]
421 call LVM_SearchForPartition
422 mov bx,si ; BX now points to LVM entry
423 pop si
424
425 mov al,0 ; Setup null driveletter
426 ; Oops, no valid LVM record was used so we have a null driveletter.
427 jnc LVM_SetDriveLetter_null_lvm_dl
428
429 ;
430 ; At this point BX points to the LVM-entry related to the
431 ; partition, whether it was a logical or a primary one.
432 ;
433 mov al, [drive_letter]
434 mov [bx+LocLVM_VolumeLetter],al
435
436 mov si, offset [LVMSector]
437 call LVM_UpdateSectorCRC
438
439 mov dl, [disk]
440 mov bx, [lvm_log_high]
441 mov ax, [lvm_log_low]
442
443 call DriveIO_SaveSector
444
445 LVM_SetDriveLetter_null_lvm_dl:
446 ret
447LVM_SetDriveLetter EndP
448
449
450
451; Removes a given drive-letter from the whole LVM information sector
452; In: CH - drive-letter (ascii)
453; DS:SI - LVM-Information-Sector
454; Out: LVM-Information-Sector updated (including LVM CRC)
455; Destroyed: None
456LVM_RemoveVolLetterFromSector Proc Near Uses cx
457 cmp bptr [si+LocLVM_SignatureStart], LocLVM_SignatureByte0
458 jne LVMRVLFS_Done ; Quick Check, if LVM sector there
459 push si
460 add si, LocLVM_StartOfEntries
461 mov cl, LocLVM_MaxEntries
462 LVMRVLFS_Loop:
463 cmp ch, [si+LocLVM_VolumeLetter]
464 jne LVMRVLFS_NextEntry
465 ; Reset drive-letter, if matched
466 mov bptr [si+LocLVM_VolumeLetter], 0 ; ASSIGN NEXT FREE HERE... (DOET DUBBEL ALS ZELFDE DL ALS SYS)
467 LVMRVLFS_NextEntry:
468 add si, LocLVM_LenOfEntry
469 dec cl
470 jnz LVMRVLFS_Loop
471 pop si
472 call LVM_UpdateSectorCRC
473 LVMRVLFS_Done:
474 ret
475LVM_RemoveVolLetterFromSector EndP
476
477; Reassigns LVM volume driveletter
478; Will remove the drive-letter from any volume that got it currently
479; and finally change the drive-letter of the given partition
480; In: AL - drive-letter
481; DS:SI - points to partition, that needs that driveletter
482; Out: None
483; Destroyed: AX
484
485LVM_DoLetterReassignment Proc Near Uses bx cx dx si di
486
487 IFDEF AUX_DEBUG
488 pusha
489 mov si, offset [dlra]
490 call AuxIO_Print
491 call AuxIO_Teletype
492 call AuxIO_TeletypeNL
493 popa
494 ENDIF
495
496 mov di, si ; Save SI in DI (Partition-pointer)
497 mov ch, al ; and AL in CH (drive-letter)
498 xor bx, bx
499 mov cl, CFG_Partitions
500 or cl, cl
501 jz LVMDLR_SkipRemove
502
503 LVMDLR_RemoveLoop:
504 cmp bptr [PartitionVolumeLetters+bx], ch
505 jne LVMDLR_NextPartition
506 ; One volume that has our wanted drive-letter, so remove it!
507 mov dl, bl
508 call PART_GetPartitionPointer ; DL - partition -> SI
509 ; Now set CurPartition_Location for the DriveIO-functions to work
510 mov ax, wptr [si+LocIPT_AbsolutePartTable]
511 mov wptr [CurPartition_Location+0], ax
512 mov ax, wptr [si+LocIPT_AbsolutePartTable+2]
513 mov wptr [CurPartition_Location+2], ax
514 mov ax, wptr [si+LocIPT_LocationPartTable+1]
515 mov wptr [CurPartition_Location+6], ax
516 mov ah, bptr [si+LocIPT_LocationPartTable+0]
517 mov al, [si+LocIPT_Drive]
518 mov wptr [CurPartition_Location+4], ax
519 call DriveIO_LoadLVMSector ; SI points now to LVM-Sector
520 call LVM_RemoveVolLetterFromSector
521
522 call DriveIO_SaveLVMSector ; Save sector
523
524 LVMDLR_NextPartition:
525 inc bx
526 dec cl
527 jnz LVMDLR_RemoveLoop
528
529 LVMDLR_SkipRemove:
530 ; Set CurPartition_Location information of destination partition
531 mov ax, wptr [di+LocIPT_AbsolutePartTable]
532 mov wptr [CurPartition_Location+0], ax
533 mov ax, wptr [di+LocIPT_AbsolutePartTable+2]
534 mov wptr [CurPartition_Location+2], ax
535 mov ah, bptr [di+LocIPT_LocationPartTable+0]
536 mov al, [di+LocIPT_Drive]
537 mov wptr [CurPartition_Location+4], ax
538 mov ax, wptr [di+LocIPT_LocationPartTable+1]
539 mov wptr [CurPartition_Location+6], ax
540 call DriveIO_LoadLVMSector ; SI points now to LVM-Sector
541 mov ax, wptr [di+LocIPT_AbsoluteBegin]
542 mov dx, wptr [di+LocIPT_AbsoluteBegin+2]
543 mov di, si ; Save SI in DI
544 call LVM_SearchForPartition
545 jnc LVMDLR_DestPartNotFound
546 ; Set new volume letter
547 mov bptr [si+LocLVM_VolumeLetter], ch
548 mov si, di ; SI - LVM Sector again
549 call LVM_UpdateSectorCRC ; Update LVM-CRC now
550
551 call DriveIO_SaveLVMSector ; Save sector
552
553 LVMDLR_DestPartNotFound:
554 ; This here is done for safety, because we misuse CurPartition_Location
555 xor ax, ax
556 mov di, offset CurPartition_Location
557 mov cx, 4
558 rep stosw ; NUL out CurPartition_Location
559 ret
560LVM_DoLetterReassignment EndP
561
562
563; This walks the IPT and for each partition it obtains the LVM drive-letter
564; if available. This drive-letter is then marked as in-use in the Map.
565; The FreeDriveletterMap is used by the drive-letter reassignment function
566; to assign a new drive to a data-partition when a system-partition is booted
567; with the same drive-letter. The original drive-letter for the data-partition
568; is saved so it can be restored later when a system is booted that does not
569; use the drive-letter. Note that there can be multiple system-partitions
570; using the same drive-letter and data-partitions can become system-partition
571; by making them bootable. (and vice versa)
572LVM_ComposeFreeDriveletterMap Proc
573
574; get nr of partitions in IPT
575; for each partition get LVM drive-letter and reset bit in map.
576
577LVM_ComposeFreeDriveletterMap EndP
578
Note: See TracBrowser for help on using the repository browser.