|
Written by Gregory R. Panakkal
|
|
Sunday, 05 August 2007 |
|
Here is rest of the source code.... what I had termed as 'kernel' ... pretty much nothing, or rather its a simple program faking a dumb console.
You can find the bootloader code here.
Note: mouse handler code was not written by me... I kinda forgot who had written it, so credits goes to whoever wrote that.
Assembling Instruction tasm /t /m3 boot.asm elink boot.obj boot.com /bs /q tasm /t kernel.asm elink kernel.obj kernel.com /b /q copy /B boot.com+kernel.com image.img
Writing it to Floppy @echo off rawrite.exe -f image.img -d A
Please don't mail me asking for the corresponding utilities i had used, google 'em up :)
------------- <kernel.asm> ------------
;ßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßß ; TestOS ; Operating System Kernel ;ÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜ
.model tiny .code org 0h
start: ; Entry Point... .586
cli mov ax, 09000h mov ss, ax mov sp,0ffffh sti
mov bx, cs mov es, bx mov ds, bx xor si, si
call StartUpScreen
mov bx, cs mov es, bx mov ds, bx xor si, si
xor ah, ah mov al, 03h int 10h
main_loop:
call ShowPrompt call Check_Commands
jmp main_loop
;ßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßß ; Print A String Pointed by -SI- ;ÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜ
Print: mov al, DS:[SI] inc si or al,al jz short finished mov ah,0Eh mov bx,0007h int 10h jmp Print finished: retn
;ßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßß ; ShowPrompt ;ÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜ
ShowPrompt: mov si, offset Prompt call Print
mov si, offset Buffer KeyLoop: xor ah,ah ; Read Char From KeyBrd int 16h
mov byte ptr cs:[si], al mov byte ptr cs:[si+1], 00h
cmp al, 08h ; if BkSp key... jne kynext dec si cmp si, offset Buffer - 1 je Error mov ah,0Eh mov bx,0007h int 10h mov al, ' ' int 10h mov al,08h int 10h jmp KeyLoop
kynext: cmp al, 0Dh ; If enter key... je KeyLoop_end
mov ah,0Eh mov bx,0007h int 10h inc si jmp KeyLoop
Error: inc si call Beep jmp KeyLoop
KeyLoop_end: mov ah,0Eh mov bx,0007h mov al, 13d int 10h mov al, 10d int 10h retn
;ßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßß ; Compare String (Return CX = 0 if true else CX = 1) DI:Input String ;ÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜ Compare: mov di, offset Buffer mov cx, 128d cloop: mov al, DS:[SI] cmp al, 00h je cover cmp al, DS:[DI] jne cmismatch inc si inc di loop cloop cover: ; Compare Over! mov cx, 0000h retn cmismatch: ; A Mismatch mov cx, 00001h retn
;ßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßß ; Check For Command ;ÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜ
Check_Commands: mov si, offset dir ; 'dir' command call Compare jcxz DIR_HANDLER
mov si, offset cls ; 'cls' command call Compare jcxz CLS_HANDLER
mov si, offset ver ; 'ver' command call Compare jcxz VER_HANDLER
mov si, offset cpu_id ; 'cpuid' command call Compare jcxz CPUID_HANDLER
mov si, offset restart ; 'restart' command call Compare jcxz RESTART_HANDLER
mov si, offset help ; 'help' command call Compare jcxz HELP_HANDLER
mov si, offset paint ; 'paint' command call Compare jcxz PAINT_HANDLER
mov si, offset ErrorMsg call Print retn
;Ûßßßßßßßßßßßßßßßßßßß ;Û DIR_HANDLER ;ÛÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜ
DIR_HANDLER: mov si, offset NotImplemented call Print call main_loop
;Ûßßßßßßßßßßßßßßßßßßß ;Û CLS_HANDLER ;ÛÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜ
CLS_HANDLER: xor ah, ah mov al, 3h int 10h call main_loop
;Ûßßßßßßßßßßßßßßßßßßß ;Û VER_HANDLER ;ÛÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜ
VER_HANDLER: mov si, offset VersionMsg call Print call main_loop
;Ûßßßßßßßßßßßßßßßßßßß ;Û CPUID_HANDLER ;ÛÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜ
CPUID_HANDLER: xor eax, eax cpuid mov si, offset vendorid mov [si], ebx mov [si+4], edx mov [si+8], ecx mov si, offset vendorid2 call Print mov si, offset vendorid call Print call main_loop
;Ûßßßßßßßßßßßßßßßßßßß ;Û RESTART_HANDLER ;ÛÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜ
RESTART_HANDLER: db 0eah,0,0,0ffh,0ffh
;Ûßßßßßßßßßßßßßßßßßßß ;Û HELP_HANDLER ;ÛÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜ
HELP_HANDLER: mov si, offset HelpMsg call Print call main_loop
;Ûßßßßßßßßßßßßßßßßßßß ;Û PAINT_HANDLER ;ÛÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜ
PAINT_HANDLER:
mov CS:Paint_Active, 1 mov ax,13h int 10h mov cx, 199d mov bx, 0A000h mov es, bx
show_color: mov ax, cx mov bx, 320d mul bx mov di, ax mov byte ptr ES:[DI], cl mov byte ptr ES:[DI+1], cl mov byte ptr ES:[DI+2], cl mov byte ptr ES:[DI+3], cl dec cl cmp cl, 0 jne show_color mov CS:Color, 4 loop_pnt: call Paint_Utility mov ah, 1h int 16h je loop_pnt
xor ah, ah int 16h
cmp al, 27d jne loop_pnt
paint_quit: mov ax,3h int 10h mov CS:Paint_Active, 0 call main_loop
;ßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßß ; Start Up Screen ;ÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜ
StartUpScreen: mov ah, 02h xor dx, dx xor bh, bh int 10h
mov al,'Û' mov bx,75 mov cx,80*25 mov ah,9 rep int 10h
mov dx,0B19h mov ah,2 int 10h
mov si, offset WelcomeMsg call Print
call Delay
xor ax, ax mov es, ax mov word ptr es:[1Ch*4], offset Clock_Handler mov es:[1Ch*4+2], cs call Mouse_Handler mov bx, cs mov es, bx mov ds, bx retn
;ßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßß ; Wait Some Time Dear... ;ÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜ
Delay: mov cx,20 mov dx,62500 mov ah,86h int 15h retn
;ßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßß ; Beep ;ÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜ Beep: mov al, 7 mov ah, 0Eh mov bh, 0h int 10h retn
;ßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßß ; Command Applicable ;ÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜ
dir db "dir",0 ; Directory Listing cls db "cls",0 ; Clear Screen cpu_id db "cpuid",0 ; Display CPU Vendor ID ver db "ver",0 ; Display OS Version help db "help",0 ; Display Help restart db "restart",0 ; Restart Computer paint db "paint",0 ; Start Paint!
;ßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßß ; Various Messages Displayed ;ÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜ
WelcomeMsg db "T e s t Operating System",0 Prompt db 13,10," @Stake> ",0 ErrorMsg db " Bad Command Or FileName",0 VersionMsg db " TestOS Version 1.0",0 NotImplemented db " Command Not Implemented",0 vendorid2 db " CPU Vendor ID : ",0 vendorid db " ",0 HelpMsg db 13,10,"Commands:",13,10,"dir - list dir contents",13,10,"cls - clear screen",13,10,"ver - display os version",13,10,"cpuid - display cpu vendor",13,10,"restart - restart pc",13,10,"paint - Paint Clone_Lft Click (Sel Color/PutPix)",13,10,"help - this help",13,10,0
;ßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßß ; Clock Handler ;ÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜ
Clock_Handler: Push Ax Push Bx Push Cx Push Dx Push Si Push Di Push Bp
Push Ds Push Es
mov si, offset Time mov bx, cs mov ds, bx mov es, bx
cmp CS:Paint_Active, 0 jne Clock_End
xor ah, ah int 1Ah ; CX:DX
mov ax, cx mov bl, 10d ; AL- ans AH-rem div bl add al, 30h mov [si], al add ah, 30h mov [si+1], ah
mov ax, dx xor dx, dx mov bx, 444h div bx ; AX-ans DX-rem mov bl, 10d div bl add al, 30h mov [si+3], al add ah, 30h mov [si+4], ah
mov ax, dx xor dx, dx mov bx, 18d div bx ; AX-ans DX-rem mov bl, 10d div bl add al, 30h mov [si+6], al add ah, 30h mov [si+7], ah
mov ah, 13h mov al, 00h mov bh, 00h mov bl, 75 mov cx, 8 mov dh, 0 mov dl, 72 mov bp, offset Time ; ES : BP int 10h Clock_End: Pop Es Pop Ds
Pop Bp Pop Di Pop Si Pop Dx Pop Cx Pop Bx Pop Ax iret
Time db '00:00:00',0
;ßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßß ; Mouse Handler ;ÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜ Mouse_Handler: xor ax, ax mov es, ax call InitMouse mov ax, 1 int 33h retn
;±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±± HideMouse: pusha mov ax, cs mov ds, ax
mov Active, 1 mov cx, _X mov dx, _Y
mov ax, 0A000h mov es, ax mov ax, 320d mul dx add ax, cx mov di, ax
; restore OldMouse mov bx, offset Mouse1 mov bp, Old mov si, offset OldScr mov cx, MaxY @HYRestore: push cx mov cx, MaxX @HXRestore: mov al, [si] inc si mov ah, es:[bp] cmp ah, ds:[bx] jne short @HNoRestore mov es:[bp], al @HNoRestore: inc bx inc bp loop @HXRestore add bp, 320-MaxY pop cx loop @HYRestore popa ret
;±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±± ShowMouse: call NewMouse mov cs:_X, 0 mov cs:_Y, 0 mov cs:Active, 1 pop bx iret
;±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±± NewMouse: pusha mov ax, 0a000h mov es, ax
mov ax, cs mov ds, ax
mov cx, _X mov dx, _Y
mov ax, 320d mul dx add ax, cx mov di, ax
; restore OldMouse mov bx, offset Mouse1 mov bp, Old mov si, offset OldScr mov cx, MaxY @YRestore: push cx mov cx, MaxX @XRestore: mov al, [si] inc si mov ah, es:[bp] cmp ah, ds:[bx] jne short @NoRestore mov es:[bp], al @NoRestore: inc bx inc bp loop @XRestore add bp, 320-MaxY pop cx loop @YRestore
mov Old, di mov bp, di mov si, offset OldScr
mov cx, MaxY @YSave: push cx mov cx, MaxX @XSave: mov al, es:[bp] mov [si], al inc si inc bp loop @XSave pop cx add bp, 320-MaxY loop short @YSave
; plot new mouse mov dx, 03dah @WaitRet: in al, dx test al, 1 jnz short @WaitRet
mov si, offset mouse1 mov cx, MaxY @YLoop: push cx mov cx, MaxX @XLoop: mov al, cs:[si] inc si cmp al, 99 je short @NoPlot mov es:[di], al @NoPlot: inc di loop @XLoop add di, 320-MaxY pop cx loop @YLoop popa ret
;±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±± MHandler: push ax bx cx dx di bp ds es mov ax, cs mov ds, ax
mov dx, MPort in al, dx test al, 64 jz short @NoProtByte mov BCnter, 0 @NoProtByte: mov bx, BCnter cmp bx, 2 jae short @Complete
inc BCnter mov [Mprot+bx], al jmp short @@Exit
@Complete: mov [MProt+bx], al ; save last byte... xor ax, ax mov [BCnter], ax
mov al, [Mprot] test al, 32 setnz left test al, 16 setnz right
mov bx, ax and al, 3 shl al, 6 add al, [Mprot+1] cmp al, 128 jbe short @NoXCorrection neg al sub _x, ax jnb short @go2
mov _x, 0 jmp short @go2 @NoXCorrection: add _X, ax cmp _x, 319 jb short @go2 mov _x, 319 @go2:
and bl, 12 shl bl, 4 add bl, [Mprot+2] cmp bl, 128 jbe short @NoYCorrection neg bl sub _y, bx jnb short @go1
mov _y, 0 jmp short @go1 @NoYCorrection: add _Y, bx cmp _y, 199 jb short @go1 mov _y, 199 @go1: call NewMouse @@Exit: pop es ds bp di dx cx bx mov al, 20h out 20h, al pop ax iret
;±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±± ResetMouse: pop bx mov bx, 2 dec ax iret
;±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±± ReturnState: ;Bit(s) Descrition ; 0 left button pressed if 1 ; 1 right button pressed if 1 pop bx
xor bx, bx mov bl, cs:right shl bl, 1 add bl, cs:left
mov cx, cs:_x mov dx, cs:_y iret ;±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±± SetMousePos: ;INT 33 - MS MOUSE v1.0+ - POSITION MOUSE CURSOR ; AX = 0004h ; CX = column ; DX = row mov cs:_X, cx mov cs:_Y, dx cmp cs:Active, 0 jz short @NotActive call NewMouse @NotActive: ret ;±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±± Jmptable dw offset ResetMouse dw offset ShowMouse dw offset HideMouse dw offset ReturnState dw offset SetMousePos Int33h: push bx mov bx, ax shl bx, 1 jmp JmpTable+bx pop bx @Exit: iret
;±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±± InitMouse: cli in al,21h jmp $+2 jmp $+2
and al, not 2 shl (Mirq-1); enable mouse-irq out 21h, al
mov dx, MPort+3 mov al, 80h ; set baudrate to 1200 out dx, al sub dx, 3 mov ax, 115200 / 1200 out dx, al inc dx mov al, ah out dx, al
add dx, 2 mov al, 2 out dx, al ; 7 N 1
sub dx, 2 mov al, 1 out dx, al ; enable int's...
add dx, 3 mov al, 1 or 2 or 8 ; raise DTR, RTS, OUT2 out dx, al
sub dx, 4 in al, dx ; ACK mouse, else no irq-call!
mov al, 20h ; ACK Int. out 20h, al
; now install new mouse-handler
mov eax, es:[(8+Mirq) shl 2] mov Oldint, eax mov word ptr es:[(8+Mirq) shl 2], offset MHandler mov word ptr es:[(8+Mirq) shl 2]+2, cs
mov eax, es:[4*33h] mov Old33h, eax mov word ptr es:[33h*4], offset Int33h mov word ptr es:[33h*4]+2, cs
sti ret
MC equ 0 MaxX equ 4 MaxY equ 4 MPort equ 03f8h MIrq equ 4
OldScr db 4*4 dup (?) Old dw 0 _x dw 0 _y dw 0 Left db 0 Right db 0 Active db 0 MProt db 3 dup (?) BCnter dw ? OldInt dd ? Old33h dd ?
label Mouse1 byte db 15,15,15,15 db 15,15,99,99 db 15,99,15,99 db 15,99,99,15
;ßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßß ; PAINT UTILITY ;ÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜ Paint_Utility: cmp left, 1 jne paint_end
mov bx, 0A000h mov es, bx
mov cx, CS:_X cmp cx, 4 ja putpixelbrush
mov dx, 320d mov ax, CS:_Y dec ax mul dx ; DX:AX <- AX*DX mov bx, ax mov dx, CS:_X dec dx add bx, dx mov al, byte ptr es:[bx] mov CS:Color, al jmp paint_end
putpixelbrush: mov dx, 320d mov ax, CS:_Y mul dx mov bx, ax mov dx, CS:_X add bx, dx mov al, CS:Color mov byte ptr es:[bx], al
paint_end: retn
Paint_Active db 00h Color db 00h
;ßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßß ; Key Board Buffer ;ÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜ
Buffer db 128 dup(0)
end start
------------- </kernel.asm> -----------
|
|
Last Updated ( Sunday, 05 August 2007 )
|
Share this page...
|