;Copyright (C) 1999-2000 Konstantin Boldyshev <konst@linuxassembly.org>
;
;$Id: fcd.asm,v 0.1 (C) 2001 Paul Hayter
;
; FCD
;
; Hacked up asmutils tool. Finds the first CDROM and then creates a link to
; it in the current directory
;
%include "system.inc"

CODESEG

mediastr db	'/proc/ide/ide0/hda/media',0
helperstr db	'0a0b1c1d',0
lf	db	0x0a
dev	db	'/dev',0
cdrom	db	'cdrom',0

proc_dev db	'none',0
proc_mpt db	'/proc',0
proc_fs	db	'proc',0

devcd	db	'/dev/cdrom',0
cdmpt	db	'/cdrom',0
iso	db	'iso9660',0
ext2	db	'ext2',0
blank	db	0

src_file db	'/cdrom/rootfs',0
src_file2 db	'/cdrom/rootfs.lz',0
dest_file db	'/dev/ram1',0
ram_mnt	db	'/ram',0
ram_dev	db	'/ram/dev',0
slash	db	'/',0
loading1 db	'Loading rootfs ...',0x0a,0
loading2 db	'Loading rootfs.lz .....',0x0a,0

;decomp stuff
llstuff	equ	8
hl1stuff equ	5
hl2stuff equ	10
hf2stuff equ	33

START:
	cld
	_mov	esi,mediastr
	_mov	edi,mediabuf
	call	cp_string

	call	mount_proc

; Try to open /proc/ide/ide0/hda/media, then /proc/ide/ide0/hdb/media ...
; Assume that the first one that says 'cdrom' is our boot CD
	_mov	esi,helperstr
	cld
.l2:	lodsb
	or	al,al
	je	near .l1
	mov	[edi + 13],al
	lodsb
	mov	[edi + 17],al
	sys_open edi,O_RDONLY
	mov	ebp,eax
	test	eax,eax
	js	.l2
;We've got the file open. Read it to see if it says 'cdrom'
	_mov	ebx, Buf
	mov	long [ ebx ] , 0
	sys_read ebp,ebx,BufSize
	push	eax
	sys_close ebp
	pop	eax
        test    eax,eax
        js	near .l2
; We've read something from it
	_mov	ebx,Buf
	cmp	long [ ebx ], "cdro"
	je	near .found_cd
	jmp	near .l2
.l1:
	sys_exit 0

; At this point our mediabuf should have the right name in it, which is 
; enough for us to make a symlink

.found_cd:
	sys_chdir dev
	mov	esi, mediabuf + 15
	mov	byte [ esi + 3 ], 0
; create the /dev/cdrom ->hdx symlink
	sys_symlink esi,cdrom
	mov	ebp,esi
; mount the cdrom
	call	mount_cdrom

	call	dd_filesystem

	call	mount_ram

	sys_chdir ram_dev
	sys_symlink mediabuf + 15,cdrom

	sys_chdir slash
	sys_umount ram_mnt
	sys_umount cdmpt
	sys_umount proc_mpt
	sys_exit 0





dd_filesystem:
	sys_open src_file,O_RDONLY
	test	eax,eax
	jns	.no_error
	sys_open src_file2, O_RDONLY
	test	eax,eax
	jns	dd_compressed_fs
	_mov	eax,1
	ret
.no_error:
	push	eax
	mov	esi,loading1
	call	prt_string
	pop	eax
	mov	esi,eax

	sys_open dest_file,O_WRONLY|O_CREAT|O_TRUNC
	test	eax,eax
	jns	.no_error2
	sys_close esi
	_mov	eax,2
	ret
.no_error2:
	mov	edi, eax

.l1:	sys_read esi,dd_buf,dd_buf_size
	test	eax,eax
	jz	.no_more_data
	js	.read_err
	mov	edx,eax
	sys_write edi,dd_buf,edx
	jmp	.l1
.read_err:
	sys_close edi
	sys_close esi
	_mov	eax,3
	ret
.no_more_data:
	sys_close edi
	sys_close esi
	_mov	eax,0	
	ret
dd_compressed_fs:
; eax should be set to the rootfs.lz filehandle
	push	eax
	mov	esi,loading2
	call	prt_string
	pop	eax

        mov     ebp,eax
        sys_lseek ebp,0, SEEK_END
        push    eax             ; eax = lenght of compressed file
        sys_lseek ebp,0, SEEK_SET
        pop     eax
        mov     [ data_length ], eax
        mov     esi,dcBuf
        add     esi,dcBufSize
        sub     esi, eax
        mov     ecx, eax
        sys_read ebp,esi,ecx
        test    eax,eax
        jns     .read_ok
        sys_close ebp
	mov	eax,3
        ret
.read_ok:
        sys_close ebp
        lodsd           ; load the first 4 bytes containing the real length
        mov     [ actual_size ] , eax
        mov     [ lz_start ], esi

        call    decompress
                         
        mov     edi , [ actual_size ]
        sys_open dest_file, O_WRONLY|O_CREAT|O_TRUNC
        test eax,eax
        jns     .wr_open_ok
	mov	eax,5
	ret
.wr_open_ok:
        mov     ebp,eax
        sys_write ebp,dcBuf,edi
        sys_close ebp
	xor	eax,eax
	ret

decompress:
        xor     ebp,ebp
        xor     ecx,ecx
        xor     eax,eax
        xor     ebx,ebx

        mov     edi,dcBuf ; Destination offset

        ;push    edi                    ; Push edi for the final ret
        pusha
        mov     eax,esi
        add     eax, [ data_length ]
        mov     [ end_point ] , eax

; Main loop -----------------------------------------------------------------

main_loop:
eoff:
        cmp     esi,[end_point]      ; EOF?
        jb     noquit
        mov     [ dest_end ] , edi
        popa
        xor     edi, edi
        ret
noquit:
        call    get_bit                 ; Compressed/uncompressed data next?
        jc      compressed

; Handle uncompressed data --------------------------------------------------
        mov     cl,8                    ; Uncompressed -> Get next 8 bits
        cdq                             ; No fix-ups (clear edx)

        call    get_data                ; Get byte
        xchg    eax,ebx                   ; Store the byte
        stosb


        ;jmp is 5 bytes long, clc jnc is only 3, we win 2 bytes !
        ;jmp     main_loop               ; Loop
        clc
        jnc     main_loop

; Handle compressed data ----------------------------------------------------

compressed:
ll:     mov     dl,llstuff                   ; Maximum number of bits in a row

bit_loop:
        call    get_bit                 ; Loop until CF = 0
        jnc     c_getpos

        inc     ecx                      ; Increase lenght

        dec     edx                      ; Max number of bits read?
        jnz     bit_loop                ; Nope -> Keep reading

        call    get_huffman             ; Yepp -> Get huffman-coded lenght
        mov     ecx,ebx                   ; Lenght must be in cx

c_getpos:
        jecxz    lenght_1                ; Lenght 1? -> Do something else....

        push    ecx                      ; Save lengt
        call    get_huffman             ; Get huffman-coded position
        pop     ecx                      ; Restore lenght

c_copy:
        push    esi                      ; Save old source

        mov     esi,edi                   ; Calculate new source offset
        sub     esi,ebx

        inc     ecx                      ; Fix lenght
        rep movsb                       ; Copy duplicate data

        pop     esi                      ; Restore source offset

        ;jmp     main_loop               ; Loop
        clc
        jnc     main_loop

lenght_1:
        mov     cl,4                    ; Get 4 bits of data for position
        cdq                             ; Fix-up value 
        inc     edx                      ; (dx = 1)

        call    get_data                ; Get data

        ;jmp     c_copy                  ; Go back to loop
        clc
        jnc     c_copy

; Get one bit of data -------------------------------------------------------

; Returns:
;     CF - Value of the bit

gb_next_byte:
        xor     eax,eax                 ; Very Important
        lodsb                           ; Get one byte

        mov     ah,1                    ; Mark the end of data
        xchg    ebp,eax                   ; Move it to bp

get_bit:
        shr     ebp,1                    ; Get bit to CF
        jz      gb_next_byte            ; No more bits left in dx?
        ret

; Get huffman-coded number --------------------------------------------------

; Returns:
;     bx - The number

get_huffman:
        mov     cx,hl1stuff                    ; Assume 3 bits for the number
        cdq                             ; Fix-up value
        inc     edx                      ; (dx = 1)

        call    get_bit                 ; Get huffman bit
        jnc     get_data                ; Was 0 -> Values were correct

        mov     cl,hl2stuff           ; Was 1 -> 5 bits for the number
        mov     dl,hf2stuff           ; Fix-up value

; Get n bits of data --------------------------------------------------------

; Input:
;     cx - Number of bits wanted
;     dx - Fix-up value to be added to the result

; Returns:
;     bx - The requested number

get_data:
        xor     ebx,ebx

gd_loop:
        call    get_bit                 ; Get bit
        rcl     ebx,1                    ; Store it
        loop    gd_loop                 ; Loop
        add     ebx,edx                   ; Fix the value
        ret


mount_ram:
	sys_mount dest_file,ram_mnt,ext2,0xc0ed0000,blank
	ret

mount_cdrom:
	sys_mount devcd,cdmpt,iso,0xc0ed0001,blank
	ret


mount_proc:
	mov	ebx, proc_dev
	mov	ecx, proc_mpt
	mov	edx, proc_fs
	mov	esi,0
	sys_mount
	ret


; esi points to zero terminated string
; edi is the destination
cp_string:
	push	esi
	push	edi
	cld
.cp_next:
	lodsb
	or	al,al
	je	.null_end
	stosb
	jmp 	near .cp_next
.null_end:
	stosb
	pop	edi
	pop	esi
	ret

; esi points to a zero ended string to print
prt_string:
	pushad
	push	esi
	_mov	ecx,0
	jmp	near .l2
.l1:	inc	esi
	inc	ecx
.l2:	cmp	[esi],byte 0
	jnz	.l1
	pop	esi
	sys_write STDOUT,esi,ecx
	sys_write STDOUT,lf,1
	popad
	ret


UDATASEG

BufSize	equ	128
Buf	resb	BufSize

dd_buf_size equ	1024
dd_buf	resb	dd_buf_size

mediabuf resb	40

; decompression stuff
dcBufSize equ     4194304+8192
dcBuf     resb    dcBufSize

end_point       resb    4
decompress_to   resb    4
dest_end        resb    4
data_length     resb    4
actual_size     resb    4
lz_start        resb    4

END
