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

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

Reimplemented 'LVM_GetDriveLetter' [v1.1.1-testing]

The new method uses SI which points to the IPT entry for the partition.
The IPT entry contains all info needed to load the corresponding LVM
sector. This does away with distinguishing between primary and logical
partitions and also removes ugly and possibly faulty LBA adjustments.

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: 21.5 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
59IFDEF AUX_DEBUG
60 IF 0
61 DBG_TEXT_OUT_AUX 'LVM_GetSectorCRC:'
62 PUSHRF
63 ;~ call DEBUG_DumpRegisters
64 ;~ call AuxIO_DumpParagraph
65 ;~ call AuxIO_TeletypeNL
66 POPRF
67 ENDIF
68ENDIF
69
70 push word ptr [si+LocLVM_CRC+00]
71 push word ptr [si+LocLVM_CRC+02]
72 push si
73 mov word ptr [si+LocLVM_CRC], 0
74 mov word ptr [si+LocLVM_CRC+2], 0
75 mov ax, -1
76 mov dx, -1
77 mov cx, 512
78 LVM_GSCRC_Loop:
79 xor bh, bh
80 mov bl, al ; Save last byte to BL
81 mov al, ah
82 mov ah, dl
83 mov dl, dh
84 xor dh, dh ; SHR DX:AX, 8
85 xor bl, [si]
86 inc si ; XOR last byte with [data]
87 shl bx, 1
88 shl bx, 1
89 xor ax, word ptr [LVM_CRCTable+bx+0]
90 xor dx, word ptr [LVM_CRCTable+bx+2] ; XOR with CRC-Table
91 loop LVM_GSCRC_Loop
92 pop si
93 pop word ptr [si+LocLVM_CRC+2]
94 pop word ptr [si+LocLVM_CRC]
95 ret
96LVM_GetSectorCRC EndP
97
98; Checks ds:[SI], if a valid LVM Signature is found (sets carry in that case)
99; This does not check for valid LVM CRC (which also needs to be done)
100; In: DS:SI - Sector that needs to get checked...
101; Out: Carry set, if valid LVM signature found
102; Destroyed: None
103LVM_CheckSectorSignature Proc Near
104 test byte ptr [CFG_IgnoreLVM], 1 ; We are supposed to ignore LVM, so
105 jnz LVMCSS_InvalidSignature ; any sector is bad!
106 cmp word ptr [si+LocLVM_SignatureStart], 5202h
107 jne LVMCSS_InvalidSignature
108 cmp word ptr [si+LocLVM_SignatureStart+2], 'BM'
109 jne LVMCSS_InvalidSignature
110 cmp word ptr [si+LocLVM_SignatureStart+4], 'MP'
111 jne LVMCSS_InvalidSignature
112 cmp word ptr [si+LocLVM_SignatureStart+6], 'DF'
113 jne LVMCSS_InvalidSignature
114 stc
115 ret
116 LVMCSS_InvalidSignature:
117 clc
118 ret
119LVM_CheckSectorSignature EndP
120
121; Checks Sector for a valid LVM CRC is encountered
122; First one should check for a valid signature and call this later.
123; In: DS:SI - Sector that needs to get checked...
124; Out: Carry set, if LVM CRC valid
125; Destroyed: None
126LVM_CheckSectorCRC Proc Near Uses ax bx dx
127 call IsSectorBufferZero ; Zero sector implies bad CRC
128 jz LVMCSCRC_BadCRC
129 call LVM_GetSectorCRC ; Only use after CRC table is valid
130 cmp ax, word ptr [si+LocLVM_CRC]
131 jne LVMCSCRC_BadCRC
132 cmp dx, word ptr [si+LocLVM_CRC+2]
133 jne LVMCSCRC_BadCRC
134 stc ; Indicate CRC is OK
135 ret
136 LVMCSCRC_BadCRC:
137 clc ; Indicate BAD CRC
138 ret
139LVM_CheckSectorCRC EndP
140
141; Checks if a sector is a valid LVM-sector
142; Sector is considered valid LVM-sector if both signature and CRC are correct.
143; IN : DS:SI - Buffer with LVM-sector that needs to be checked...
144; OUT : AL.0 - 1 -> LVM Signature found
145; AL.1 - 1 -> CRC OK
146; CY - Signature and CRC OK, otherwise none or invalid LVM sector
147; Destroyed: None
148LVM_ValidateSector Proc Near
149 xor ax, ax ; Assume no Signature or valid CRC
150 call LVM_CheckSectorSignature ; CF=1 -> Signature OK
151 rcl al, 1 ; Store CF in AL.0
152 call LVM_CheckSectorCRC ; CF=1 -> CRC OK
153 rcl ah, 1 ; Store CF in AH.0
154 shl ah, 1 ; Move it to AH.1
155 or al, ah ; Merge CY results to AL
156 cmp al, 3 ; AH=3 -> Signature and CRC OK
157 clc ; Assume invalid LVM-sector
158 jne @F
159 stc ; AH=3 -> Indicate valid LVM-sector
160 @@:
161 mov ah, 0 ; Don't leave garbage in AH
162 ret
163LVM_ValidateSector EndP
164
165; Updates Sector with valid LVM CRC
166; This one doesn't check, if it's really an LVM sector, so check before!
167; In: DS:SI - Sector that needs to get checked...
168; Out: None, CRC updated
169; Destroyed: None
170LVM_UpdateSectorCRC Proc Near Uses ax dx
171 call LVM_GetSectorCRC
172 mov word ptr [si+LocLVM_CRC], ax
173 mov word ptr [si+LocLVM_CRC+2], dx
174 ret
175LVM_UpdateSectorCRC EndP
176
177; Searches for a partition in LVM Information Sector and sets SI to point to
178; the LVM-entry. It will also set CARRY then.
179; In: DX:AX - LBA starting sector of partition to be searched
180; DS:SI - Valid (previously checked) LVM-Information-Sector
181; Out: Carry set, if partition found
182; DS:SI - points to LVM information entry
183; Destroyed: None
184
185; INVALID LVM RECORD WHEN STICK INSERTED !
186
187LVM_SearchForPartition Proc Near Uses cx
188
189IFDEF AUX_DEBUG
190 IF 0
191 DBG_TEXT_OUT_AUX 'LVM_SearchForPartition:'
192 PUSHRF
193 call DEBUG_DumpRegisters
194 ;~ call AuxIO_DumpParagraph
195 ;~ call AuxIO_TeletypeNL
196 POPRF
197 ENDIF
198ENDIF
199
200 cmp byte ptr [si+LocLVM_SignatureStart], LocLVM_SignatureByte0
201 jne LVMSFP_NotFound ; Quick Check, if LVM sector there
202 add si, LocLVM_StartOfEntries
203 mov cl, LocLVM_MaxEntries
204 LVMSFP_Loop:
205 cmp ax, [si+LocLVM_PartitionStart]
206 jne LVMSFP_NextEntry
207 cmp dx, [si+LocLVM_PartitionStart+2]
208 je LVMSFP_FoundIt
209 LVMSFP_NextEntry:
210 add si, LocLVM_LenOfEntry
211 dec cl
212 jnz LVMSFP_Loop
213 LVMSFP_NotFound:
214 clc
215 ret
216 LVMSFP_FoundIt:
217 stc
218 ret
219LVM_SearchForPartition EndP
220
221
222;------------------------------------------------------------------------------
223; Get the LVM drive-letter for a partition (if available)
224;------------------------------------------------------------------------------
225; IN : SI - Pointer to IPT entry for partition
226; OUT : AL - LVM drive-letter
227; : SI - Pointer to LVM entry in loaded LVM record
228; : CF=1 - No valid LVM sector found, AL not valid
229; NOTE : Besides the drive-letter, AL can be 0 (LVM hidden) or '*' (LVM auto)
230;------------------------------------------------------------------------------
231LVM_GetDriveLetter Proc Near Uses bx cx dx di
232
233IFDEF AUX_DEBUG
234 IF 0
235 DBG_TEXT_OUT_AUX 'LVM_GetDriveLetter:'
236 PUSHRF
237 call DEBUG_DumpRegisters
238 ;~ call AuxIO_DumpParagraph
239 ;~ call AuxIO_TeletypeNL
240 POPRF
241 ENDIF
242ENDIF
243
244 ; Save IPT pointer
245 mov di, si
246
247 ; Get the LBA addresses of the MBR or EBR from the IPT entry
248 mov dl, [si+LocIPT_Drive] ; BIOS disk number
249 mov ax, [si+LocIPT_AbsolutePartTable+00h] ; LBA lo MBR/EBR
250 mov bx, [si+LocIPT_AbsolutePartTable+02h] ; LBA hi MBR/EBR
251
252 ; Try to load the corresponding LVM sector
253 mov si, offset [LVMSector] ; Pointer to buffer
254 call DriveIO_LoadLVMSectorXBR ; Try to load LVM sector
255 jc LVM_GetDriveLetter_no_lvm ; No success
256
257 ; Recall IPT pointer
258 mov si, di
259
260 ; Locate the LVM entry for the partition
261 mov ax, [si+LocIPT_AbsoluteBegin+00h] ; LBA lo of partition
262 mov dx, [si+LocIPT_AbsoluteBegin+02h] ; LBA hi of partition
263 mov si, offset [LVMSector] ; Loaded LVM sector
264 call LVM_SearchForPartition ; Locate entry
265 jnc LVM_GetDriveLetter_no_lvm ; Entry not found
266
267 ; Get the LVM drive-letter
268 mov al, [si+LocLVM_VolumeLetter] ; Can be 0,'*',letter
269
270 ; We're done, indicate success and return
271 clc
272 jmp LVM_GetDriveLetter_done
273
274 LVM_GetDriveLetter_no_lvm:
275 ; Indicate no LVM drive-letter found
276 xor ax, ax
277 mov si, ax
278 stc
279
280 LVM_GetDriveLetter_done:
281
282IFDEF AUX_DEBUG
283 IF 0
284 DBG_TEXT_OUT_AUX 'lgdl_lvmsec'
285 PUSHRF
286 call DEBUG_DumpRegisters
287 mov si, offset [LVMSector]
288 call AuxIO_DumpSector
289 ;~ call AuxIO_DumpParagraph
290 ;~ call AuxIO_TeletypeNL
291 POPRF
292 ENDIF
293ENDIF
294
295 ret
296LVM_GetDriveLetter EndP
297
298
299
300; Sets a drive-letter in the LVM-info of a partition. (if it exists)
301; In: BX:CX - LBA starting sector of partition to be searched
302; DL = Physical Disk in BIOS notation. (80h+)
303; AL = DriveLetter to set (can be zero to hide partition from LVM)
304; Out: CY=1 if LVM-info found, 0 if no LVM-info.
305LVM_SetDriveLetter Proc Near Uses bx cx dx si di ds es
306
307 local disk:byte
308 local drive_letter:byte
309 local pri_ind:byte
310 local lvm_log_high:word
311 local lvm_log_low:word
312 ; For primary partitions this information is stored in the last
313 ; sector of track0; for all four partition entries in case they
314 ; they are all primary ones.
315 ;
316 ; LVM DLAT info for logical partitions is stored in the sector
317 ; preceding the start of the partition.
318 ;
319 ; Because the LVM info of a logical partition is the easiest to find,
320 ; we do that first. The LVM info for primary partitions is located
321 ; dependent on the geometry in use, so we use a special locater
322 ; call for that. Also, since the LVM info for primaries contains
323 ; info on all 4 entries, we need the partition index to obtain the
324 ; correct drive-letter.
325 ;
326
327IFDEF AUX_DEBUG
328 IF 0
329 DBG_TEXT_OUT_AUX 'LVM_SetDriveLetter:'
330 PUSHRF
331 ;~ call DEBUG_DumpRegisters
332 ;~ call AuxIO_DumpParagraph
333 ;~ call AuxIO_TeletypeNL
334 POPRF
335 ENDIF
336ENDIF
337
338 mov [disk], dl
339
340 ; Store the drive-letter for later use
341 mov [drive_letter], al
342
343
344 ; See if this is a primary partition
345 ; CY will be set if it is and AL will contain the 0-based
346 ; index in the P-table.
347 ; If it's a logical partition, CY will be clear and AL
348 ; will be set to 0ffh indicating an invalid index.
349 call PART_IsPrimaryPartition
350 mov al,0
351 rcl al,1 ; CY if primary
352 mov dh,al ; Save PRI or LOG
353 mov [pri_ind],al
354
355 ; Save PRI/LOG indicator for later use
356 push dx
357
358 ; Load *possible* LVM sector
359 ; This load is only valid if the partition is logical, in which case
360 ; the LVM sector is below the start of the partition.
361 ; If primary, the LVM sector is at a location that
362 ; DriveIO_LoadMasterLVMSector will find out.
363
364 ; Push LBA address
365 push bx
366 push cx
367
368 ; Adjust for logical LVM-sector
369 sub cx,1
370 sbb bx,0
371
372 ; Store LBA address of LVM-sector
373 mov [lvm_log_low],cx
374 mov [lvm_log_high],bx
375
376 ; Load the LVM sector
377 push si
378 push di
379 mov si,offset [LVMSector]
380 mov di,ds
381 mov ax, cx ; LBA low is now in AX
382 call DriveIO_ReadSectorLBA
383 pop di
384 pop si
385
386 ; Restore LBA address
387 pop cx
388 pop bx
389
390 ; Restore PRI/LOG partition indicator in DH
391 pop dx
392
393 ; Test PRI or not
394 test dh,dh
395 ; It's not a PRI so we can use the previously loaded LVM sector
396 jz LVM_SetDriveLetter_is_not_pri
397
398 ;
399 ; It's a PRI so we use the special locator function.
400 ; This locator takes care of extended OS/2 geometry should that be used
401 ;
402 call DriveIO_LoadMasterLVMSector
403 jnc LVM_SetDriveLetter_null_lvm_dl
404
405 mov ax, word ptr [MasterLVMLBA] ; ARRAY VAN MAKEN !
406 mov [lvm_log_low], ax
407 mov [lvm_log_high], 0
408
409 LVM_SetDriveLetter_is_not_pri:
410
411 ;
412 ; At this stage the LVM-info sector has been loaded at [LVMSector].
413 ; From here we look for an LVM entry for the partition.
414 ; If one is found, based on it's LBA-start, it's driveletter is used
415 ; in case byte 25h in the BPB is zero.
416 ;
417
418 ; Search for the partition in the LVM info.
419 ; If found, CY is set and SI points to LVM entry.
420 push si
421 mov ax,cx
422 mov dx,bx
423 mov si,offset [LVMSector]
424 call LVM_SearchForPartition
425 mov bx,si ; BX now points to LVM entry
426 pop si
427
428 mov al,0 ; Setup null driveletter
429 ; Oops, no valid LVM record was used so we have a null driveletter.
430 jnc LVM_SetDriveLetter_null_lvm_dl
431
432 ;
433 ; At this point BX points to the LVM-entry related to the
434 ; partition, whether it was a logical or a primary one.
435 ;
436 mov al, [drive_letter]
437 mov [bx+LocLVM_VolumeLetter],al
438
439 mov si, offset [LVMSector]
440 call LVM_UpdateSectorCRC
441
442 mov dl, [disk]
443 mov bx, [lvm_log_high]
444 mov ax, [lvm_log_low]
445
446 call DriveIO_SaveSector
447
448 LVM_SetDriveLetter_null_lvm_dl:
449 ret
450LVM_SetDriveLetter EndP
451
452
453
454; Removes a given drive-letter from the whole LVM information sector
455; In: CH - drive-letter (ascii)
456; DS:SI - LVM-Information-Sector
457; Out: LVM-Information-Sector updated (including LVM CRC)
458; Destroyed: None
459LVM_RemoveVolLetterFromSector Proc Near Uses cx
460
461IFDEF AUX_DEBUG
462 IF 0
463 DBG_TEXT_OUT_AUX 'LVM_RemoveVolLetterFromSector:'
464 PUSHRF
465 ;~ call DEBUG_DumpRegisters
466 ;~ call AuxIO_DumpParagraph
467 ;~ call AuxIO_TeletypeNL
468 POPRF
469 ENDIF
470ENDIF
471
472 cmp bptr [si+LocLVM_SignatureStart], LocLVM_SignatureByte0
473 jne LVMRVLFS_Done ; Quick Check, if LVM sector there
474 push si
475 add si, LocLVM_StartOfEntries
476 mov cl, LocLVM_MaxEntries
477 LVMRVLFS_Loop:
478 cmp ch, [si+LocLVM_VolumeLetter]
479 jne LVMRVLFS_NextEntry
480 ; Reset drive-letter, if matched
481 mov bptr [si+LocLVM_VolumeLetter], 0 ; ASSIGN NEXT FREE HERE... (DOET DUBBEL ALS ZELFDE DL ALS SYS)
482 LVMRVLFS_NextEntry:
483 add si, LocLVM_LenOfEntry
484 dec cl
485 jnz LVMRVLFS_Loop
486 pop si
487 call LVM_UpdateSectorCRC
488 LVMRVLFS_Done:
489 ret
490LVM_RemoveVolLetterFromSector EndP
491
492; Reassigns LVM volume driveletter
493; Will remove the drive-letter from any volume that got it currently
494; and finally change the drive-letter of the given partition
495; In: AL - drive-letter
496; DS:SI - points to partition, that needs that driveletter
497; Out: None
498; Destroyed: AX
499
500LVM_DoLetterReassignment Proc Near Uses bx cx dx si di
501
502IFDEF AUX_DEBUG
503 IF 0
504 DBG_TEXT_OUT_AUX 'LVM_DoLetterReassignment:'
505 PUSHRF
506 ;~ call DEBUG_DumpRegisters
507 ;~ call AuxIO_DumpParagraph
508 ;~ call AuxIO_TeletypeNL
509 POPRF
510 ENDIF
511ENDIF
512
513 mov di, si ; Save SI in DI (Partition-pointer)
514 mov ch, al ; and AL in CH (drive-letter)
515 xor bx, bx
516 mov cl, CFG_Partitions
517 or cl, cl
518 jz LVMDLR_SkipRemove
519
520 LVMDLR_RemoveLoop:
521 cmp bptr [PartitionVolumeLetters+bx], ch
522 jne LVMDLR_NextPartition
523 ; One volume that has our wanted drive-letter, so remove it!
524 mov dl, bl
525 call PART_GetPartitionPointer ; DL - partition -> SI
526 ; Now set CurPartition_Location for the DriveIO-functions to work
527 mov ax, wptr [si+LocIPT_AbsolutePartTable]
528 mov wptr [CurPartition_Location+0], ax
529 mov ax, wptr [si+LocIPT_AbsolutePartTable+2]
530 mov wptr [CurPartition_Location+2], ax
531 mov ax, wptr [si+LocIPT_LocationPartTable+1]
532 mov wptr [CurPartition_Location+6], ax
533 mov ah, bptr [si+LocIPT_LocationPartTable+0]
534 mov al, [si+LocIPT_Drive]
535 mov wptr [CurPartition_Location+4], ax
536 call DriveIO_LoadLVMSector ; SI points now to LVM-Sector
537 call LVM_RemoveVolLetterFromSector
538
539 call DriveIO_SaveLVMSector ; Save sector
540
541 LVMDLR_NextPartition:
542 inc bx
543 dec cl
544 jnz LVMDLR_RemoveLoop
545
546 LVMDLR_SkipRemove:
547 ; Set CurPartition_Location information of destination partition
548 mov ax, wptr [di+LocIPT_AbsolutePartTable]
549 mov wptr [CurPartition_Location+0], ax
550 mov ax, wptr [di+LocIPT_AbsolutePartTable+2]
551 mov wptr [CurPartition_Location+2], ax
552 mov ah, bptr [di+LocIPT_LocationPartTable+0]
553 mov al, [di+LocIPT_Drive]
554 mov wptr [CurPartition_Location+4], ax
555 mov ax, wptr [di+LocIPT_LocationPartTable+1]
556 mov wptr [CurPartition_Location+6], ax
557 call DriveIO_LoadLVMSector ; SI points now to LVM-Sector
558 mov ax, wptr [di+LocIPT_AbsoluteBegin]
559 mov dx, wptr [di+LocIPT_AbsoluteBegin+2]
560 mov di, si ; Save SI in DI
561 call LVM_SearchForPartition
562 jnc LVMDLR_DestPartNotFound
563 ; Set new volume letter
564 mov bptr [si+LocLVM_VolumeLetter], ch
565 mov si, di ; SI - LVM Sector again
566 call LVM_UpdateSectorCRC ; Update LVM-CRC now
567
568 call DriveIO_SaveLVMSector ; Save sector
569
570 LVMDLR_DestPartNotFound:
571 ; This here is done for safety, because we misuse CurPartition_Location
572 xor ax, ax
573 mov di, offset CurPartition_Location
574 mov cx, 4
575 rep stosw ; NUL out CurPartition_Location
576 ret
577LVM_DoLetterReassignment EndP
578
579
580; This walks the IPT and for each partition it obtains the LVM drive-letter
581; if available. This drive-letter is then marked as in-use in the Map.
582; The FreeDriveletterMap is used by the drive-letter reassignment function
583; to assign a new drive to a data-partition when a system-partition is booted
584; with the same drive-letter. The original drive-letter for the data-partition
585; is saved so it can be restored later when a system is booted that does not
586; use the drive-letter. Note that there can be multiple system-partitions
587; using the same drive-letter and data-partitions can become system-partition
588; by making them bootable. (and vice versa)
589LVM_ComposeFreeDriveletterMap Proc
590
591; get nr of partitions in IPT
592; for each partition get LVM drive-letter and reset bit in map.
593
594LVM_ComposeFreeDriveletterMap EndP
595
Note: See TracBrowser for help on using the repository browser.