⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 hdd.8

📁 PC x386 bios source code
💻 8
📖 第 1 页 / 共 3 页
字号:
	mov	al,dl	;drive
	shl	al,4
	or	al,0a0h	;reserved bits
	mov	dx,hdc_drv
	out	dx,al	;set drive
	;
	; wait until HD ready, CX ticks
	;
hd_rdy:	add	cx,[m_timer]	;start time + max number of ticks
	mov	dx,hdc_stat
hd_rdy1:	in	al,dx
	test	al,80h
	jnz	hd_rdy2	;:busy
	test	al,40h
	jnz	hd_busy9	;:ready, carry clear
hd_rdy2:	cmp	cx,[m_timer]
	jns	hd_rdy1	;keep waiting
	jmp	hd_busy8
	;
	; issue command AL, wait for interrupt
	;
hd_cmd:	mov	byte [m_hdflag],0	;clear interrupt flag
	mov	dx,hdc_cmd
	out	dx,al
	
	; wait for HD interrupt
	
hd_int:	mov	cx,18*4	;4 seconds
	add	cx,[m_timer]	;start time + max number of ticks
hd_int1:	cli		;test in critical section as some
			;modern drives are "too fast" for
			;slower embedded boards.
	test	byte m_hdflag,0ffh	;interrupt ?
	jnz	hd_int9	;:yes, return NC
	cmp	cx,[m_timer]	;time-out ?
	js	hd_int8	;:yes, return CY
	sti		;end critical section, HLT follows
	hlt		;power-saving wait for next interrupt
	jmp	hd_int1
	
hd_int8:	stc		;time-out
	mov	al,80h	;status code
hd_int9:	sti		;re-enable interrupts !
	ret
	;
	; IRQ14 entry
	;
irq14:	push	ax
	push	ds
	xor	ax,ax	;BIOS segment
	mov	ds,ax
	mov	byte [m_hdflag],0ffh	;set interrupt flag
	mov	al,eoi
	out	pic1,al
	out	pic0,al
	pop	ds
	pop	ax
	iret
	;
	; set hard disk time-out
	;
#if def	HD_TIME
hd_timer:
	call	hd_sel	;select drive, wait for not busy
	jb	hd_tim9
	mov	dx,hdc_cnt
	mov	al,HD_TIME
	out	dx,al
	mov	al,0e3h
	call	hd_cmd	;issue command
	jb	hd_tim9
	mov	dl,low(hdc_err)
	in	al,dx
	and	al,7fh
	jz	hd_tim9
	sub	al,1	;ok ?
	jz	hd_tim9
	mov	al,20h
	stc
hd_tim9:	jmp	hd_exit0
#endif
	;
	; write CHS parameters to command file, including CHS translation
	;
hd_chs:	mov	dx,hdc_cnt	;sector count
	mov	al,[bp._al]
	out	dx,al
	inc	dx
	mov 	cl,[cs:di.dpt_shl]	;get shift count
#if def	HDD_LBA
	cmp	cl,0ffh	;LBA mode ?
	jz	hd_chs2
#endif
	mov	bx,[bp._cx]	;sector number, cylinder
	mov	al,bl	;sector number
	and	ax,3fh	;(need AH = 0 for divide)
	out	dx,al	;hdc_sec
	mov	al,[bp._dh]	;head number
	div 	byte [cs:di.dpt_phd]	;divide by physical heads
			;-> AL = heads, AH = cylinders
	inc	dx
	xchg	bl,bh	;swap cylinder
	shr	bh,6	;bit 7..6 become bits 9..8
	shl	bx,cl	;shift cylinder for CHS translation
	or	al,bl	;head
	out	dx,al	;hdc_cyl - cylinder low
	inc	dx
	mov	al,bh	;cylinder high
	out	dx,al	;hdc_cyh
	inc	dx
	in	al,dx	;hdc_drv
	or	al,ah	;heads
	out	dx,al
	ret
	;
	; LBA translation
	;
#if def	HDD_LBA
hd_chs2:	push 	eax	;save eax, ebx
	push 	ebx
	xor 	eax,eax
	mov	ax,[bp._cx]	;sector number, cylinder
	xchg	al,ah	;swap cylinder high, low
	shr	ah,6	;fix cylinder high
	mov 	ebx,eax
	shl 	eax,8	;cylinder * 255
	sub	eax,ebx
	xor	bx,bx
	mov	bl,[bp._dh]	;head number
	add 	eax,ebx	;add head
	mov 	ebx,eax
	shl 	eax,6	;cylinder * 255 + head * 63
	sub 	eax,ebx
	xor 	ebx,ebx
	mov	bl,[bp._cl]	;sector number
	and	bl,63
	dec	bx	;- 1
	add 	eax,ebx
	out	dx,al	;hdc_sec sector = LBA 7..0
	inc	dx
	shr	ax,8
	out	dx,al	;hdc_cyl cylinder low = LBA 15..8
	inc	dx
	shr 	eax,16
	out	dx,al	;hdc_cyh cylinder high = LBA 23..16
	inc	dx
	in	al,dx	;hdc_drv get drive
	and	al,0b0h	;keep reserved, drive select bits
	or	al,040h	;set LBA mode
	or	al,ah
	out	dx,al	;hdc_drv heads = LBA27..24
	pop 	ebx
	pop 	eax
	ret
#endif
	;
	; HD detect / init
	;
hd_init:

#if def	HD_WAIT
	;
	; Some drives take a long time to become responsive to commands,
	; because they only store very minimal firmware, and fetch the
	; actual code from disk. Some of them are allergic to being touched
	; before they are ready.
	;
#if !def	HD_WAITA
	cmp	word [m_rstflg],1234h	;Ctrl-Alt-Del ?
	jz	hd_wait9	;:skip wait
#endif
	xor	bx,bx	;clear second counter
	mov	si,msg_wait
	call	v_msg
	cmp	bx,HD_ENA	;0 delay ?
	jz	hd_wait3	;yes: bypass
	
hd_wait1:	mov	ax,18	;about 1 second
	add	ax,[m_timer]	;start time + max number of ticks
hd_wait2:	hlt		;low power wait, we'll be here for a
			;while
	cmp	ax,[m_timer]	;time-out ?
	jns	hd_wait2	;no: keep waiting
	
	cmp	bx,HD_ENA	;can we touch the drive now ?
	jb	hd_wait8	;:no
hd_wait3:	mov	al,0ffh	;place FF on the IDE bus (or loopback)
	mov	dx,hdc_dat
	out	dx,al
	mov	dl,low(hdc_stat)	;does the status register read non-FF ?
	in	al,dx
	cmp	al,0ffh
	jz	hd_wait8a	;FF: no drive attached, bail
	test	al,80h	;busy ?
	jnz	hd_wait8	;:don't touch
	mov	al,0a0h	;access master drive
	mov	dl,low(hdc_drv)
	out	dx,al
	out	iowait,ax
	mov	dl,low(hdc_stat)	;read status
	in	al,dx
	test	al,80h	;busy ?
	jnz	hd_wait8
	test	al,40h	;drive ready ?
	jnz	hd_wait8a	;:terminate the wait

hd_wait8:	mov	si,msg_dot	;display a dot each second
	call	v_msg
	inc	bx	;second counter
	cmp	bx,HD_WAIT
	jb	hd_wait1
	
hd_wait8a: mov	si,msg_crlf	;go to next line
	call	v_msg
hd_wait9:
#endif

	cli
	mov	ax,int13hd	;set interrupt vector
	xchg	[vec13],ax
	mov	[vec40],ax
	mov	ax,cs	;old INT13 becomes INT40
	xchg	[vec13+2],ax
	mov	[vec40+2],ax

	mov	word [vec41],hd_prm0	;set vectors to disk parameters
	mov	[vec41+2],cs
	mov	word [vec46],hd_prm1
	mov	[vec46+2],cs

	in	al,pic1+1	;enable HD interrupt
	and	al,0bfh
	out	iowait,ax
	out	pic1+1,al
	
	in	al,pic0+1	;enable cascade interrupt
	and	al,0fbh
	out	iowait,ax
	out	pic0+1,al
	sti

	mov	byte [m_hdcnt],2	;2 drives to start
	mov	byte [m_hdstat],0	;clear status
	
	mov	di,hd_prm0	;setup first drive
	mov	dl,80h
	mov	al,0a0h
#if ! def	HDD_PRES
	call	hd_pres	;check presence
	jb	hd_init1
#endif
	call	hd_set	;set parameters
	jb	hd_init1
	
	; Unfortunately, it is not that easy to detect the slave drive,
	; as the master drive will often drive the slave registers to
	; "safe" values when the slave is not present.
	;
	; It is supposed to be possible to detect number of drives with
	; the execute drive diagnostic command, but I don't see how.
	;
	; In the end, if the detection was incorrect, we will time out
	; (about a second) when trying to identify the drive.

	mov	dl,81h	;setup second drive
#if ! def	HDD_NOSLAVE
	mov	di,hd_prm1
	mov	al,0b0h
	call	hd_pres	;check presence
	jb	hd_init1
	call	hd_set	;set parameters
	jb	hd_init1	;:error
	inc	dx	;increment drive count if no error
#endif

hd_init1:	mov 	byte [cs:hd_top],dl	;store top hard disk number
	and	dl,7fh	;done - store number drives
	mov	byte [m_hdcnt],dl
	ret
	;
	; check drive presence, AL = A0 or B0
	;
hd_pres:	push	dx
	mov	dx,hdc_drv
	out	dx,al
	out	iowait,ax
	out	iowait,ax
	out	iowait,ax
	
	mov	dl,low(hdc_cnt)	;write test pattern
	mov	al,55h
	out	dx,al
	mov	dl,low(hdc_cyl)	;write negative pattern
	mov	al,0aah
	out	dx,al
	mov	dl,low(hdc_cnt)	;read test pattern
	in	al,dx
	xor	al,55h
	jz	hd_pres9	;:ok
hd_pres8:	stc
hd_pres9:	pop	dx
	ret
	;
	; set up drive DL
	;
hd_set:	mov	ah,25h	;get drive ID
	mov	bx,tmp_buf
	int	13h
	jb	hd_set9
	
#if def	cs_ide
	push	di	;save ^drive parameters
	mov	di,tmp_buf	;DS:DI points to identify buffer
	push	dx	;DL: drive
	call	cs_ide	;set drive timing parameters
	pop	dx
	pop	di
#endif
	cmp	word [tmp_buf+0],848ah	;CompactFlash ?
	jz	hd_set0	;:yes
	cmp	word [tmp_buf+0],844ah	;CompactFlash ? (new SanDisk)
	jz	hd_set0	;:yes
	test	byte [tmp_buf+1],80h	;ATAPI ?
	jz	hd_set0	;:no

	; note I/O base and drive ID of ATAPI CD-ROM
	; this is assumed to be the first ATAPI device found

#if def	CDBOOT
	cmp	byte [cs:d_cdbase],0	;is this the first ATAPI drive ?
	jnz	hd_set9	;:no
	mov	word [cs:d_cdbase],01f0h	;set address
	test	dl,1	;master ?
	jnz	hd_set9	;:slave, default
	mov 	byte [cs:d_cddrv],0a0h	;master drive
#endif
	
hd_set9:	stc		;error return
	ret	
	
hd_set0:	mov 	al,[tmp_buf+12]	;sectors
	mov 	[cs:di.dpt_sec],al
	mov 	[cs:di.dpt_psec],al
	mov 	al,[tmp_buf+94]	;multiple block size
	mov 	[cs:di.dpt_mul],al
	mov 	ax,[tmp_buf+2]	;cylinders
	mov 	[cs:di.dpt_pcyl],ax
	mov 	bl,[tmp_buf+6]	;heads
	mov 	[cs:di.dpt_phd],bl
	
	; CHS translation: shift cylinders right / heads left until
	; cylinders < 1024
	
	mov	bh,0	;shift count
#if def	FORCE_LBA
	cmp	ax,8191	;force LBA for high cylinder count
	ja	hd_lba
#endif

hd_set1:	cmp	ax,1024
	jb	hd_set2
	shr	ax,1	;cylinders / 2
	shl	bl,1	;heads * 2
#if def	HDD_LBA
	jb	hd_lba	;:overflow - use LBA mode for this drive
#else
	jb	hd_set9	;:overflow - cannot translate drive
#endif
	inc	bh	;count the shifts
	jmp	hd_set1

hd_set2:	mov 	[cs:di.dpt_cyl],ax
	mov 	[cs:di.dpt_head],bl
	mov 	[cs:di.dpt_shl],bh
	
	mov 	byte [cs:di.dpt_sig],0a0h	;signature

	mov	ah,9	;set drive parameters
	int	13h
	jb	hd_set9
	
	mov	ah,0dh	;reset drive
	int	13h
	
hd_set2b:
	push	dx
	mov	ah,8	;get max CHS
	int	13h
	mov	al,dh	;heads
	pop	dx
	jb	hd_set9
	
	mov	ah,4	;verify sectors
	mov	dh,al	;max head
	mov	al,cl	;max sector -> sector count
	and	al,3fh
	and	cl,0c0h	;start sector = 1
	or	cl,1
	sub	ch,1	;cylinder - 1
	jnb	hd_set3
	sub	cl,40h
hd_set3:	int	13h
	jb	hd_set9

#if def	HD_TIME
	mov	ah,23h	;set drive time-out
	mov	al,HD_TIME
	int	13h
#endif
	ret		;normal return

#if def	HDD_LBA
	;
	; determine LBA parameters (always 255 heads / 63 sectors)
	;
hd_lba:	test 	byte [tmp_buf+99],2	;LBA mode supported ?
	jz	hd_set9	;:no	

	push	dx	
	mov	ax,[tmp_buf+120]	;number of LBA sectors (low)
	mov	dx,[tmp_buf+122]	;(high)
	mov	bx,255*63	; / heads / sectors
	div	bx
	pop	dx

	; set drive parameters
	
	mov 	[cs:di.dpt_cyl],ax
	mov 	byte [cs:di.dpt_head],255	;255 heads
	mov	byte [cs:di.dpt_shl],0ffh	;special shift -> LBA mode
	mov	byte [cs:di.dpt_sec],63	;63 sectors
	jmp	hd_set2b	;note we don't set LBA parameters
#endif

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -