All pastes #273650 Raw Edit

Mine

public text v1 · immutable
·published 2006-12-10 01:30 UTC
rendered paste body
bootsectorpos equ 0x7c00
%include "fat.inc"
%define BOCHS
[BITS 16]

ORG 0

jmp start
oldirq6ip dw 0
oldirq6cs dw 0
irqcalled db 0
lpmotoron db "Turning motor on",13,10,0
lpcalibrating db "Calibrating drive",13,10,0
lpseeking db "Seeking head",13,10,0
lpsector db "Checking sector ID",13,10,0
lpdma db "Opening dma channel",13,10,0
lpreading db "Reading sector",13,10,0
lpphasetwo db "Receiving sector info",13,10,0
lpmotoroff db "Turning motor off",13,10,0
lpdone db "Done",13,10,0

lpnoint db "Interrupt not called!",13,10,0

lpkeypressed db "Key pressed",13,10,0

lptimer db "Timer interrupt",13,10,0

sector db 16
track db 0
head db 1

keypressed db 0

sto db 0
stl db 0
stz db 0
readtrack db 0
readhead db 0
readsector db 0
readsecsize db 0

oldmpic db 0
oldspic db 0

rootdirpos dd 0
rootdirsize dd 0
rootdirloadpos dd 0

sectorspace times 514 db 0

; check for protected or V86 mode. Code from Freedows '98 ldr_asm.asm
; Copyright (C) 1997 Joachim Breitsprecher <j.breitsprecher@schwaben.de>
start:	mov ax,cs
	mov ds,ax
	mov es,ax
	smsw ax
	test al,1		; look at PE bit of MSW (CR0)
	je start2
				; exit to DOS with error code 1
	db 0xea
	dw 0x0000
	dw 0xffff

; set base of code/data descriptors to CS<<4/DS<<4 (CS=DS)
start2:	xor ebx,ebx
	mov bx,cs		; BX=segment
	shl ebx,4		; EBX=linear address of segment base
	mov eax,ebx
	mov [gdt1 + 2],ax
	mov [gdt2 + 2],ax
	mov [gdt3 + 2],ax
	shr eax,16
	mov [gdt1 + 4],al
	mov [gdt2 + 4],al
	mov [gdt3 + 4],al
	mov [gdt1 + 7],ah
	mov [gdt2 + 7],ah
	mov [gdt3 + 7],ah
; point gdtr to the gdt, point idtr to the idt
	add ebx,gdt		; EBX=linear address of gdt
	mov [gdtr + 2],ebx
	add ebx,idt - gdt	; EBX=linear address of idt
	mov [idtr + 2],ebx
; disable interrupts
	;cli
; load GDT and IDT for full protected mode
	lgdt [gdtr]
	lidt [idtr]
; save real-mode CS in BP
	mov bp,cs
;set up irq masks
;	in al,0x20
;	mov [oldmpic],al
;	in al,0xa0
;	mov [oldspic],al
;	mov al,0xfc
;	out 0x20,al
;	mov al,0xff
;	out 0xa0,al
; set PE [protected mode enable] bit and go
	mov eax,cr0
	or al,1
	mov cr0,eax
	jmp SYS_CODE_SEL:do_pm
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;	32-bit protected mode
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
[BITS 32]
do_pm:	mov ax,SYS_DATA_SEL
	mov ds,ax		; not segments anymore: SELECTORS
	mov ss,ax
	nop
	mov esp,0xf000
	mov es,ax
	mov fs,ax
	mov gs,ax
; say hello!
	lea esi,[hi_msg]
	call wrstr
; try an interrupt
	int 0x20


; copy info from first sector 
mov ax,LINEAR_SEL
mov ds,ax
mov es,ax
mov esi,0x7c00
mov edi,eof
mov ecx,BootSectorValues.end
cld
rep movsb
; reinstate segment values
mov ax,SYS_DATA_SEL
mov ds,ax
mov es,ax

; use this info to find the root dir
xor eax,eax
mov al,[eof+BootSectorValues.FatCopies]
mul word [eof+BootSectorValues.SectorsPerFAT]
inc ax
inc ax
mov [rootdirpos],eax

; calculate rootdir size
xor eax,eax
mov ax,[eof+BootSectorValues.RootDirEntries]
shr ax,4	;16 entries per sector so div by 16=2^4
mov [rootdirsize],eax

; load rootdir straight after values

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;TODO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;                      Get the routine from bootloader that calcs
;                      track and head and stuff, make into routine

;call floppystuff
;mov byte [sector],2
;xor cx,cx
;mov [CsrX],cx
;inc byte [CsrY]
;call floppystuff



; switch to 16-bit protected mode on your way to real mode
	jmp REAL_CODE_SEL:do_16

;here we set keyboard interrupts to work
IBF_loop:
in al,0x64			;check keyboard buffer isn't full
and al,2			;test IBF flag
jz IBF_loop		;if not then loop
ret
	
;here we set keyboard interrupts to work
OBF_loop:
in al,0x64			;check keyboard buffer isn't full
and al,1			;test OBF flag
jnz OBF_loop		;if not then loop
ret
	
waitforkeyboardirq:
mov al,[keypressed]
or al,al
jz waitforkeyboardirq
ret
	
printhex8:
push ecx
push eax
push edx
mov ecx,2
mov dl,al
nexthex8:

rol dl,4
mov al,0x0f
and al,dl
add al,0x90
daa
adc al,0x40
daa

call wrch
loop nexthex8

pop edx
pop eax
pop ecx
ret

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;	character-output video routine
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
wrch:	push gs
	push ecx
	push ebx
	push eax
		mov ax,LINEAR_SEL
		mov gs,ax
; (Y * 80 + X) * 2 --> EAX
		movzx eax,byte [CsrY]
		mov cl,80
		mul cl
		add al,[CsrX]
		adc ah,0
		shl eax,1
; EAX + 0xB8000 --> EBX; store char
		lea ebx,[eax + 0xB8000]
		pop eax
		push eax
		mov [gs:ebx],al
; advance cursor
		mov cx,[CsrX]
		inc cl
		cmp cl,80	; cursor off right side of screen?
		jb wrch2
		xor cl,cl	; yes, wrap to left side...
		inc ch		; ...and down one line
		cmp ch,25	; cursor off bottom of screen?
		jb wrch2
		xor ch,ch	; yes, wrap to top left corner (no scroll)
wrch2:		mov [CsrX],cx
	pop eax
	pop ebx
	pop ecx
	pop gs
	ret
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;	string-output video routine
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
wrstr:	push esi
	push eax
	push ecx
		cld
		jmp wrstr2
wrstr1:		call wrch
wrstr2:		lodsb
		cmp al,13
		je setcr
		cmp al,10
		je setlf
		or al,al
		jne wrstr1
	pop ecx
	pop eax
	pop esi
	ret
setcr:
xor cx,cx
mov [CsrX],cl
jmp wrstr2
setlf:
inc byte [CsrY]
jmp wrstr2

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;	default handler for interrupts/exceptions
;	prints " Unhandled interrupt!"
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
unhand:	cli
	lea esi,[unhand_msg]
	call wrstr
	jmp $
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;	handler for INT 0x20
;	prints " Hey, INT 0x20 occured!"
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
isr20:	push esi
		lea esi,[isr20_msg]
		call wrstr
	pop esi
	iret
	

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;	16-bit protected mode
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
[BITS 16]
; switch to 16-bit stack and data
do_16:	mov ax,REAL_DATA_SEL
	mov ds,ax
	mov ss,ax
	nop
; push real-mode CS:IP
	lea bx,[do_rm]
	push bp
	push bx
; clear PE [protected mode enable] bit and return to real mode
		mov eax,cr0
		and al,0xFE
		mov cr0,eax
		retf		; jumps to do_rm
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;	16-bit real mode again
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; restore real-mode segment register values
do_rm:	mov ax,cs
	mov ds,ax
	mov ss,ax
	nop
	mov es,ax
	mov fs,ax
	mov gs,ax
; point to real-mode IDTR
	lidt [ridtr]
; re-enable interrupts
	sti
; exit to DOS with errorlevel 0
	xor ax,ax
	int 0x16

	mov ax,0x0e50
	xor bx,bx
	int 0x10

	xor ax,ax
	int 0x16

	db 0xea
	dw 0x0000
	dw 0xffff
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;	data
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
CsrX:	db 0
CsrY:	db 0

hi_msg:	db "Hello, how's it going?", 0

unhand_msg:
	db " Unhandled interrupt!", 0

isr20_msg:
	db " Hey, INT 0x20 occured!", 0
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;	16-bit limit/32-bit linear base address of GDT and IDT
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
gdtr:	dw gdt_end - gdt - 1	; GDT limit
	dd gdt			; linear, physical address of GDT

idtr:	dw idt_end - idt - 1	; IDT limit
	dd idt			; linear, physical address of IDT

; an IDTR 'appropriate' for real mode
ridtr:	dw 0xFFFF		; limit=0xFFFF
	dd 0			; base=0
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;	global descriptor table (GDT)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; null descriptor
gdt:	dw 0			; limit 15:0
	dw 0			; base 15:0
	db 0			; base 23:16
	db 0			; type
	db 0			; limit 19:16, flags
	db 0			; base 31:24
; linear data segment descriptor
LINEAR_SEL	equ	$-gdt
	dw 0xFFFF		; limit 0xFFFFF
	dw 0			; base 0
	db 0
	db 0x92			; present, ring 0, data, expand-up, writable
	db 0xCF			; page-granular, 32-bit
	db 0
; code segment descriptor
SYS_CODE_SEL	equ	$-gdt
gdt1:	dw 0xFFFF
	dw 0			; (base gets set above)
	db 0
	db 0x9A			; present, ring 0, code, non-conforming, readable
	db 0xCF
	db 0
; data segment descriptor
SYS_DATA_SEL	equ	$-gdt
gdt2:	dw 0xFFFF
	dw 0			; (base gets set above)
	db 0
	db 0x92			; present, ring 0, data, expand-up, writable
	db 0xCF
	db 0
; code segment descriptor that is 'appropriate' for real mode
; (16-bit, limit=0xFFFF)
REAL_CODE_SEL	equ	$-gdt
gdt3:	dw 0xFFFF
	dw 0			; (base gets set above)
	db 0
	db 0x9A			; present, ring 0, code, non-conforming, readable
	db 0			; byte-granular, 16-bit
	db 0
; data segment descriptor that is 'appropriate' for real mode
; (16-bit, limit=0xFFFF)
REAL_DATA_SEL	equ	$-gdt
gdt4:	dw 0xFFFF
	dw 0			; (base gets set above)
	db 0
	db 0x92			; present, ring 0, data, expand-up, writable
	db 0			; byte-granular, 16-bit
	db 0
gdt_end:
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;	interrupt descriptor table (IDT)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; 32 reserved interrupts:
idt:	dw unhand		; entry point 15:0
	dw SYS_CODE_SEL		; selector
	db 0			; word count
	db 0x8E			; type (32-bit Ring 0 interrupt gate)
	dw 0			; entry point 31:16 (XXX - unhand >> 16)

	dw unhand
	dw SYS_CODE_SEL
	db 0
	db 0x8E
	dw 0

	dw unhand
	dw SYS_CODE_SEL
	db 0
	db 0x8E
	dw 0

	dw unhand
	dw SYS_CODE_SEL
	db 0
	db 0x8E
	dw 0

	dw unhand
	dw SYS_CODE_SEL
	db 0
	db 0x8E
	dw 0

	dw unhand
	dw SYS_CODE_SEL
	db 0
	db 0x8E
	dw 0

	dw unhand
	dw SYS_CODE_SEL
	db 0
	db 0x8E
	dw 0

	dw unhand
	dw SYS_CODE_SEL
	db 0
	db 0x8E
	dw 0

	dw systimer
	dw SYS_CODE_SEL	;int 08h - system timer
	db 0
	db 0x8E
	dw 0

	dw keyboard_handler
	dw SYS_CODE_SEL	;int 09h - irq 1 - keyboard
	db 0
	db 0x8E
	dw 0

	dw unhand
	dw SYS_CODE_SEL
	db 0
	db 0x8E
	dw 0

	dw unhand
	dw SYS_CODE_SEL
	db 0
	db 0x8E
	dw 0

	dw unhand
	dw SYS_CODE_SEL
	db 0
	db 0x8E
	dw 0

	dw unhand
	dw SYS_CODE_SEL
	db 0
	db 0x8E
	dw 0

	dw myirq
	dw SYS_CODE_SEL
	db 0		;int 0eh
	db 0x8E
	dw 0

	dw unhand
	dw SYS_CODE_SEL
	db 0
	db 0x8E
	dw 0

	dw unhand
	dw SYS_CODE_SEL
	db 0
	db 0x8E
	dw 0

	dw unhand
	dw SYS_CODE_SEL
	db 0
	db 0x8E
	dw 0

	dw unhand
	dw SYS_CODE_SEL
	db 0
	db 0x8E
	dw 0

	dw unhand
	dw SYS_CODE_SEL
	db 0
	db 0x8E
	dw 0

	dw unhand
	dw SYS_CODE_SEL
	db 0
	db 0x8E
	dw 0

	dw unhand
	dw SYS_CODE_SEL
	db 0
	db 0x8E
	dw 0

	dw unhand
	dw SYS_CODE_SEL
	db 0
	db 0x8E
	dw 0

	dw unhand
	dw SYS_CODE_SEL
	db 0
	db 0x8E
	dw 0

	dw unhand
	dw SYS_CODE_SEL
	db 0
	db 0x8E
	dw 0

	dw unhand
	dw SYS_CODE_SEL
	db 0
	db 0x8E
	dw 0

	dw unhand
	dw SYS_CODE_SEL
	db 0
	db 0x8E
	dw 0

	dw unhand
	dw SYS_CODE_SEL
	db 0
	db 0x8E
	dw 0

	dw unhand
	dw SYS_CODE_SEL
	db 0
	db 0x8E
	dw 0

	dw unhand
	dw SYS_CODE_SEL
	db 0
	db 0x8E
	dw 0

	dw unhand
	dw SYS_CODE_SEL
	db 0
	db 0x8E
	dw 0

	dw unhand
	dw SYS_CODE_SEL
	db 0
	db 0x8E
	dw 0
; user interrupt handler
	dw isr20
	dw SYS_CODE_SEL
	db 0
	db 0x8E
	dw 0


idt_end:


[bits 32]
;keyboard_handler - handles the keyboard
keyboard_handler:
cli
push eax
in al,0x60
mov byte[keypressed],al
call printhex8
pop eax
push esi
mov esi,lpkeypressed
call wrstr
pop esi
sti
iret


;systimer - handles the system clock interrupt
systimer:
cli
push esi
mov esi,lptimer
call wrstr
pop esi
sti
nop
iret

cli		;disable interrupts
xor ax,ax	;get original int 0Eh
mov es,ax
mov dx,[es:0x0e*4]
mov [oldirq6ip],dx
mov dx,[es:0x0e*4+2]
mov [oldirq6cs],dx	;save pointer
lea dx,[myirq]
mov [es:0x0e*4],dx	;and hook our irq handler in there
mov dx,cs
mov [es:0x0e*4+2],dx
mov ax,cs
mov ds,ax	;set up segments
mov es,ax
sti		;and re-enable interrupts	

[BITS 32]
floppystuff:

call motor_on
call recal
call seek
call dma_open

call disk_read

call motor_off

mov esi,lpdone
call printchar

;here we print what we found:

mov esi,sectorspace
call printchar

;should be fun :P

ret

xor ax,ax
int 0x16

db 0xea
dw 0x0000
dw 0xffff

;mov ah,0x4c
;int 0x21

;-------------------------------------------------
;our irq handler
myirq:
mov al,0x20
out 0x20,al
mov byte[irqcalled],1
iret

;-------------------------------------------------
;waits for an interrupt
irq_wait:
mov ecx,0xfffff
irq_loop:
cmp byte[irqcalled],1
je irq_done
loop irq_loop	;loop when using bochs, jmp when using real comp 
mov esi,lpnoint
call printchar
irq_done:
ret

;-------------------------------------------------
;floppy drive motor on
motor_on:
mov al,0x1c
mov dx,0x3F2
OUT dx, al	;drive A selected, motor on, controller on, use DMA and IRQ
mov esi,lpmotoron
call printchar
ret

;-------------------------------------------------
;floppy drive motor off
motor_off:
xor al,al
mov dx,0x3F2
OUT dx, al	;no drive selected, motor off, controller off, no DMA no IRQ
mov esi,lpmotoroff
call printchar
ret



;-------------------------------------------------
;recalibrate head to 0
recal:
mov esi,lpcalibrating	;print message
call printchar
mov byte [irqcalled],0	;reset irq-called flag
mov al,7
call send_byte		;send recalibrate command
xor al,al
call send_byte
call irq_wait		;wait for irq 6
mov al,8
call send_byte		;check if actually recalibrated
call get_byte
push ax
call get_byte
pop ax
and al,0x10
or al,al
jne recal


ret

;-------------------------------------------------
;seeks to the sector we want
seek:
mov esi,lpseeking
call printchar
mov al,0x0f		;seek head/track command
call send_byte
mov al,[head]
shl al,2		;head #=bit 2, bits 1&0=0 (drive 0)
call send_byte
mov al,[track]		;send track number
call send_byte
call irq_wait		;wait for interrupt
mov al,0x08
call send_byte		;check if we're on the right track lol track
call get_byte
call get_byte
cmp al,[track]
jne seek		;if not, then re-seek

ret

;-------------------------------------------------
;receives a byte from the controller
get_byte:
call controller_wait
mov dx,0x3f5
in al,dx
ret

;-------------------------------------------------
;sends a byte to the controller
send_byte:
push ax
call controller_wait
mov dx,0x3f5
pop ax
out dx,al
ret

;-------------------------------------------------
;waits for the controller to be ready
controller_wait:
mov dx,0x3f4
in al,dx
and al,0x80
cmp al,0x80
jne controller_wait
ret

;-------------------------------------------------
;checks that we're all good to go
sector_id:

ret

;-------------------------------------------------
;read the sector
disk_read:
mov esi,lpreading
call printchar
mov al,0x46	;read sector command
call send_byte
mov al,[head]
shl al,2
call send_byte	;bit 2=head, bits 1&0=drive (drive 0)
mov al,[track]
call send_byte	;send track #
mov al,[head]
call send_byte	;send head again
mov al,[sector]
call send_byte	;send sector number
mov al,2
call send_byte	;send sector size, 128*2^x (128*2^2=512)
mov al,[sector]
call send_byte	;last sector to read
mov al,27
call send_byte	;magic number for 3 1/2 floppy
mov al,0xff
call send_byte	;given sector size, so this is -1

;now receive results
mov byte [irqcalled],0
call irq_wait
mov esi,lpphasetwo
call printchar

%ifdef BOCHS
ret
%endif

call get_byte
mov [sto],al	;status registers 0-2
call get_byte
mov [stl],al
call get_byte
mov [stz],al
call get_byte	;track
mov [readtrack],al
call get_byte	;head
mov [readhead],al
call get_byte	;sector
mov [readsector],al
call get_byte	;secsize
mov [readsecsize],al

ret

;-------------------------------------------------
;open the dma channel
dma_open
mov esi,lpdma
call printchar
cli	;disable interrupts

mov al,4	;mask channel
add al,2	;channel 2
out 0x0a,al

xor al,al	;clear flip-flop
out 0x0c,al

mov al,0x56	;dma transfer - single mode, cld, write to mem, channel 2
out 0x0b,al

xor eax,eax
mov ax,bp
shl eax,4	;set up page and offset for writing data
add eax,sectorspace

mov dx,4
out dx,al	;set offset for memory write
mov al,ah
out dx,al

inc dx
mov ax,0x200
out dx,al	;set memory length
mov al,ah
out dx,al

shr eax,16
mov dx,0x81
out dx,al	;set page

mov al,2
out 0x0a,al	;unmask channel

sti	;enable interrupts
ret

pointer dd 0
;-------------------------------------------------
;printchar - DS:SI=ptr to null-terminated string
printchar:
jmp wrstr
ret

eof: