flat assembler
Message board for the users of flat assembler.

Index > OS Construction > Boot sector example that loads a secondary binary file.

Goto page 1, 2  Next
Author
Thread Post new topic Reply to topic
Mac2004



Joined: 15 Dec 2003
Posts: 314
Mac2004 08 Jan 2007, 18:26
I saw somewhere in this board questions about secondary file loading by a boot sector.

Here's my very simple boot sector example that loads a binary file into memory and executes it. I have kept the source as simple as possible because it should serve as an example. I hope somebody can find it useful for hobby OS development. I have included the whole package in the zip-file below.

So here's the boot sector code:

Code:

;=============================================================================
; Boot loader that loads a secondary file and executes it.
; Written in 2007 by Mac2004. 
;
; This code has been kept intentionally VERY simple and all extra stuff 
; have been left out. I hope this will help people trying to write their
; own OS's. Having a working boot loader is a essential towards own OS.  
; The boot sector loads a binary file from sector 2 to 18 and then 
; executes it.
;
; You use this code only at you own risk. I don't take any responsibility
; what happens to your data etc. If you don't understand this code,
; don't use it!
;
;
; installation instructions.
;----------------------------
; You can write boot sector and the secondary file on disk with Partcopy
; which can be found through Google.
;
; pcopy min_boot.bin 0 200 -f0  -->      write boot sector code on floppy a:
;
; pcopy 2nd_file.bin 0 2200 -f0 200 -->  write secondary file right
;                                        after the boot sector a:
;
; version history:
; ------------------
;
; 2007-21-3       fixed a stack pointer bug.
;=============================================================================

        org     7C00h                           ;bios puts us here!

use16                                           ;use 16-bit code

code_start:
        jmp     start
        nop                                     ;fasm requires this no-operation command

;========================================
; Main boot sector code starts from here.
;========================================

start:
        push    cs
        pop     ds                              ;ds=cs (0)

        ; Setup the stack.
        ;----------------
        cli                                     ; Disable interrupts
        mov ax, 0x9000                          ; Put stack at 0x90000
        mov ss, ax                              ; SS = 9000 and
;       mov sp, 0                               ;
        mov sp, 0F800h                          ; set stack pointer to  0xf800
        sti                                     ; Enable interrupts

        mov    byte[bootdrv],dl                 ;save the boot drive number

        ;print that we're alive!
        ;-----------------------

        mov si, loading_msg                     ; Print a message
        call putstr

        ;-----------------------
        ;Load 17 sectors!
        ;-----------------------

.load:
        mov     ax,0x1000
        mov     es,ax                           ;set segment to 0x1000
        mov     bx,0                            ;offset= 0

        mov     dl,byte[bootdrv]
        mov     dh,0                            ;set Head
        mov     cl,2                            ;set Sector
        mov     ch,0                            ;set track

        mov     ah,2                            ;bios int 0x13 function ah=2, read sectors
        mov     al,17                           ;read one sector

        int     0x13                            ;call bios
        jnc     ok_load_setup                   ;if ok - continue

        mov si, error_msg                               ; Print a message
        call putstr
        jmp .load 

ok_load_setup:

        mov si, ok_msg                          ; Print a message
        call putstr

        ;---------------------------
        ; Jump to the loaded program
        ;---------------------------
       mov sp, 0                                ; Restore stack pointer

       mov ax, 0x1000
       mov es, ax
       mov ds, ax
       push word 0x1000
       push word 0
       retf


;==================================================
;Procedures used by the boot sector code.
;==================================================

;***********************************************************
; putstr: Print a 0-terminated string (SI=pointer to string)
;
;  Input: SI=pointer to string.
;
;  Output: --
;***********************************************************

putstr:
        lodsb
        or al,al
        jz  putstrd
        mov ah,0x0E
        mov bx,0x0007
        int 0x10
        jmp putstr
putstrd:
        retn


;==================================================
;Variables used by the boot sector code.
;==================================================


bootdrv                 db 0                            ; bootdrive number 
loading_msg             db 'Booting...',13,10,0
ok_msg                  db 'OK!',13,10,0
error_msg               db 'Error!',13,10,0


;////////////////////////////////////////////////////////////////////
;////////////////////////////////////////////////////////////////////

;fill rest of boot sector to meet exactly 512 bytes
       rb 7C00h+512-2-$                                 ;fill up to the boot record signature
       db 055h,0AAh                                     ;the signature itself

    


and here's the secondary file code

Code:

;=====================================================================
; An example of secondary file to be loaded by the boot loader.
; Written in 2007 by Mac2004.
;
; You use this code only at you own risk.
; If you don't understand this code, don't use it!
;=====================================================================

        mov ax, 1000h                                   ; Update segment registers
        mov ds, ax
        mov es, ax

        ;A quick hack to reserve some extra space to see
        ;whether multiple sector loading works or not.
        ;-----------------------------------------------
       jmp reserve_space_dummy

reservation: times 6*512 db 0
reserve_space_dummy:

        ;Print something to show that we truly are here.
        ;-----------------------------------------------
        mov si, msg                                     ; Print a message
        call putstr

        mov ax,206
        mov cl,'3'
        mov ch,' '
        call RM_PutChar

hang:                                                   ; Just hang
        jmp hang

;****************************************************************
; putstr: Print a 0-terminated string (SI=pointer to string)
;
;  Input: SI=pointer to string
;
;  Output: --
;****************************************************************

putstr:
        lodsb
        or al,al
        jz  .putstrd
        mov ah,0x0E
        mov bx,0x0007
        int 0x10
        jmp putstr
.putstrd:
        ret
;************************************************************
; RM_PutChar-   Prints one text mode char  at specified
;               position.
;
; input:  ax-  startaddress in bytes
;         cx - char to be printed
; output: --
;************************************************************

RM_PutChar:

        push es
        pusha

        mov dx,ax               ;save Startaddress

        push ax
        mov ax,0xB800
        mov es, ax
        pop ax
        mov bx,0

        add ax,dx       

        ;write actual char
        ;------------------
        
        add bx, ax              ;get start position
        mov [es:bx],cx          ;print char
        shr bx,1                ;calculate correct x-position for cursor
.done:
        popa
        pop es
        ret       ; end of procedure


msg     db 'Greetings from the secondary file....',13,10,0


    


Description:
Download
Filename: Min_boot.zip
Filesize: 3.16 KB
Downloaded: 646 Time(s)



Last edited by Mac2004 on 15 Nov 2007, 19:37; edited 3 times in total
Post 08 Jan 2007, 18:26
View user's profile Send private message Reply with quote
vsoly



Joined: 03 Aug 2005
Posts: 4
Location: Latvia
vsoly 20 Mar 2007, 08:29
Hello!
The example dont work in Bochs. I compile all files but work only boot file, it write "OK". Maybe in Bochs kernel file is out of 17 sectors?
Post 20 Mar 2007, 08:29
View user's profile Send private message Reply with quote
Hayden



Joined: 06 Oct 2005
Posts: 132
Hayden 20 Mar 2007, 12:34
How about a bootcode that does a checksum, if checksum is bad load
bootcode#2 from abs sector 2, then do checksum if good then load program from abs sector 3, otherwise print "boot code damaged!"

It's good practice to reserve the 2nd boot sector. Its also good practice to fill out the partition info that is reserved by the BIOS. ie: the 'BIOS Parameter Block'. Various INT 13h handlers will look for information here.

Hence your bootsector above may not work on some machines.
Post 20 Mar 2007, 12:34
View user's profile Send private message Reply with quote
vsoly



Joined: 03 Aug 2005
Posts: 4
Location: Latvia
vsoly 20 Mar 2007, 13:42
It is possible call kernel by filename, or it does not work? If it possible, what method is better, by filename or by sector number?
Post 20 Mar 2007, 13:42
View user's profile Send private message Reply with quote
Mac2004



Joined: 15 Dec 2003
Posts: 314
Mac2004 20 Mar 2007, 16:25
Thank you all for testing!

vsoly: I didn't test my boot sector with Bochs, because i don't have it.
I may have a fix for your problem. I found out that my boot code was not working properly on one pc I bought after posting this example.

I came to realize that the problem was with setting the sp to zero. It worked with every other pc I tested, but not with last pc I bought.

original code:
Code:
        ; Setup the stack.
        ;----------------
        cli                                     ; Disable interrupts
        mov ax, 0x9000                          ; Put stack at 0x90000
        mov ss, ax                              ; SS = 9000 and
        mov sp, 0                               ; SP = 0000 => Stack = 90000 <==(PROBLEM)
        sti                                     ; Enable interrupts
    


the solution:
Code:
        ; Setup the stack.
        ;----------------
        cli                     ; Disable interrupts
        mov ax, 0x9000          ; Put stack at 0x90000
        mov ss, ax              ; SS = 9000 and
;       mov sp, 0               ; SP = 0000 => Stack = 90000
        mov     sp,0F800h       ; offset for stack 
        sti                     ; Enable interrupts

    


After loading the secondary file you need set the sp back zero before jumping to the next level.


Rest of the boot code after all sectors are loaded:
Code:
       ;----------------------------------
       ; Jump to the loaded program
       ;----------------------------------
        mov sp, 0               ; Restore stack pointer back to zero

       
       mov ax, 0x1000
       mov es, ax
       mov ds, ax
       push word 0x1000                         
       push word 0
       retf
    



Just let me know if this fix will work with the bochs. If it works I will update the example code and the zip- package as well

regards,
Mac2004


Last edited by Mac2004 on 20 Mar 2007, 17:23; edited 1 time in total
Post 20 Mar 2007, 16:25
View user's profile Send private message Reply with quote
Mac2004



Joined: 15 Dec 2003
Posts: 314
Mac2004 20 Mar 2007, 17:00
vsoly wrote:
It is possible call kernel by filename, or it does not work? If it possible, what method is better, by filename or by sector number?


When loading a binary file, bios only loads a bunch of sectors from disk to memory. At this point there's no true file system present. Setting up the file system is a task of the secondary file which is loaded by the boot sector. I hope this will help you Smile


I guess you have seen some examples that load fat12 or fat16 files. My example does not use fat due to the fact that i want use my own file system.

regards,
Mac2004


Last edited by Mac2004 on 21 Mar 2007, 15:23; edited 2 times in total
Post 20 Mar 2007, 17:00
View user's profile Send private message Reply with quote
Mac2004



Joined: 15 Dec 2003
Posts: 314
Mac2004 20 Mar 2007, 17:22
Quote:
It's good practice to reserve the 2nd boot sector. Its also good practice to fill out the partition info that is reserved by the BIOS. ie: the 'BIOS Parameter Block'. Various INT 13h handlers will look for information here.



I agree with you about the 2nd boot sector Smile

As fas as I know BIOS Parameter Block is a DOS thing and I'am not using DOS stuff here.

Adding BPB to my example is not very complicated. Thanx for you comments, Hayden! Smile

regards,
Mac2004
Post 20 Mar 2007, 17:22
View user's profile Send private message Reply with quote
vsoly



Joined: 03 Aug 2005
Posts: 4
Location: Latvia
vsoly 21 Mar 2007, 05:32
Unfortunelly dont work under Bochs. I think, what under Bochs cannot point second sector. The kernel file is placed with easy "copy->paste" operation.

About FAT loading! Thanks, good idea Smile
Post 21 Mar 2007, 05:32
View user's profile Send private message Reply with quote
Mac2004



Joined: 15 Dec 2003
Posts: 314
Mac2004 21 Mar 2007, 15:07
Quote:

Unfortunelly dont work under Bochs. I think, what under Bochs cannot point second sector. The kernel file is placed with easy "copy->paste" operation.



Have you tried my example with real pc instead of Bochs? I will update my example with the above stack pointer fix.

I'am not very familiar with the Bochs, because I prefer real pc's.

regards
Mac2004
Post 21 Mar 2007, 15:07
View user's profile Send private message Reply with quote
Mac2004



Joined: 15 Dec 2003
Posts: 314
Mac2004 21 Mar 2007, 16:05
I have updated the code and the zip package. Updated version includes the stack pointer fix.

regards,
Mac2004
Post 21 Mar 2007, 16:05
View user's profile Send private message Reply with quote
hckr83



Joined: 12 Nov 2006
Posts: 86
Location: usa
hckr83 24 Mar 2007, 15:53
I have made a very simple FS that is extremely easy to implement that you may be intrested in

also, if you use ABS and do one sector at a time, it should be simple to fix the sector limit
Post 24 Mar 2007, 15:53
View user's profile Send private message Visit poster's website AIM Address Yahoo Messenger Reply with quote
Mac2004



Joined: 15 Dec 2003
Posts: 314
Mac2004 25 Mar 2007, 12:49
Quote:

I have made a very simple FS that is extremely easy to implement that you may be intrested in


Yes, please. Improvements are by all means welcome. Smile

Quote:

also, if you use ABS and do one sector at a time, it should be simple to fix the sector limit


It seems that some pc's have problems with doing multiple sector loading??
My code worked with all the pc's (6) I have tested.

Perhaps it is time to make a one sector at the time loader as well?

regards,
Mac2004
Post 25 Mar 2007, 12:49
View user's profile Send private message Reply with quote
Hayden



Joined: 06 Oct 2005
Posts: 132
Hayden 25 Mar 2007, 16:32
Windows 2k/XP does lots of single sector reads at bootup even when it has checked for IBM/MS Extended read capabilties. ( dont know why )

If there are hard drives present on the system you might want to try interrupt 40h for floppy disk reads under bochs.
Post 25 Mar 2007, 16:32
View user's profile Send private message Reply with quote
Mac2004



Joined: 15 Dec 2003
Posts: 314
Mac2004 25 Mar 2007, 20:09
Quote:

Windows 2k/XP does lots of single sector reads at bootup even when it has checked for IBM/MS Extended read capabilties. ( dont know why )


Perhaps some pc's cannot handle correctly multiple sector loading? Sad

I have updated my boot sector. This version loads 1 sector at the time. Please see the attached file.


Description:
Download
Filename: min_boot2.zip
Filesize: 3.79 KB
Downloaded: 583 Time(s)



Last edited by Mac2004 on 15 Nov 2007, 19:43; edited 1 time in total
Post 25 Mar 2007, 20:09
View user's profile Send private message Reply with quote
hckr83



Joined: 12 Nov 2006
Posts: 86
Location: usa
hckr83 25 Mar 2007, 21:16
I have yet to make a spec thing for my FS, but I geuss I could write a bit of a draft here..

basically, it doesn't tell any info about the current device, Though it is usually assumed that it is on a 1.44mb floppy
There are no "system" sectors like there are in most OS's, this is designed so that it could be done anything with..

There is no index for finding files, you must scan through the whole floppy, when there are a lot of files this can be VERY slow, but for a simple thing with a few files it should work relatively well

The only way to identify if a sector is a start of a file, empty, or data of a file, is to check the very first byte of the sector(this starts at abs sector 2)
0x3C means start of file
0x2C means empty space
0x1C means reserved

any other value is assumed to be a corrupted sector

For the start of a file, the file info is stored like this,
- 0x3C
- word value of how many immediately following sectors
- string of 16 chars for the filename(null terminated)
- dword value of how many actual bytes in the file(this need not be used for a simple boot sector and you should use the above)
- attribute byte, in this format(going from bit 7 to bit 0 using | as a seperator)
read only|hidden|system|do not move me(for defrag apps)| everything else is unused
-now just the data of the file

note that no value is placed in the first byte of sectors in the "data" of a file, this is only placed at the first file sector

free space info is stored like this:
- 0x2C
- word value of how many immediately following sectors are free

reserved space info is stored like this:
-0x1C
- word value of how many immediately following sectors are free


It is really quite simple now isn't it?
you can add your own index file if wanted or something, whatever

the only bad thing about this design is that it doesn't support fragmentation, so a "space alignment" program may need to be made to correctly align spots of free space so as to make more free space readily available

also note that nothing in the boot sector is needed to be specified like in fat and most other FSs..(though this forces you to assume a lot)
Post 25 Mar 2007, 21:16
View user's profile Send private message Visit poster's website AIM Address Yahoo Messenger Reply with quote
Mac2004



Joined: 15 Dec 2003
Posts: 314
Mac2004 26 Mar 2007, 15:05
hckr83: I have got two ideas to improve your file system:

1) Every file could contain a link (sector number) to next file start. This improves searching because only one sector in each file needs to be read in order to find the next file.

or/and

2) A simple table of sectors and size placed on the first sectors of disk.
This allows faster file search to be implemented.

regards,
Mac2004
Post 26 Mar 2007, 15:05
View user's profile Send private message Reply with quote
Mac2004



Joined: 15 Dec 2003
Posts: 314
Mac2004 19 Sep 2010, 17:18
vsoly wrote:
Hello!
The example dont work in Bochs. I compile all files but work only boot file, it write "OK". Maybe in Bochs kernel file is out of 17 sectors?


I forgot to update this earlier:

Bochs and other emulators seem to require a full 1.44MB floppy image in order
to work. So the assembled code must be padded to fit exactly the 1.44mb size.


Regards
Mac2004
Post 19 Sep 2010, 17:18
View user's profile Send private message Reply with quote
baldr



Joined: 19 Mar 2008
Posts: 1651
baldr 20 Sep 2010, 17:45
Mac2004 wrote:
Bochs and other emulators seem to require a full 1.44MB floppy image in order to work.
Are you sure? Bochs 2.4.5 seems to be OK with 512-byte floppy images.
Post 20 Sep 2010, 17:45
View user's profile Send private message Reply with quote
egos



Joined: 10 Feb 2009
Posts: 144
egos 20 Sep 2010, 18:52
baldr is right. Bochs works on shortened disk images perfectly.
Post 20 Sep 2010, 18:52
View user's profile Send private message Reply with quote
edfed



Joined: 20 Feb 2006
Posts: 4330
Location: Now
edfed 20 Sep 2010, 19:58
it is also possible to load a .com program.

the algo is:

Code:
copy bootsector to 0:7E00h
jmp 0:7E00h

create PSP code at 1000h:0
load .com code at PSP+100h
far call 1000h:0

load C: bootsector at 0:7C00h
jmp 0:7C00h


PSP:
init segments
call near 100h
far ret
    


the PSP code is located at cs:0
the PSP command line parameter is at cs:80h, and is empty there.
the .com code is located at cs:100h (org 100h)
the .com code exits with a simple near ret
the PSP exits with a far ret
Code:
;version 13/05/2008 15:31;;;;;
comload:
use16
        org 7c00h
boot:
        cld
        cli
        mov ax,0800h
        mov ss,ax
        mov sp,7ff0h
        sti
        push cs word 0b800h
        pop fs ds
        mov [root+disk.drv],dl
        mov cx,512
        mov ax,0020h
        mov es,ax
        mov di,07c00h
        mov si,di
        rep movsb
        jmp 20h:@f
@@:
        push cs
        pop ds
        mov ax,[root.ptr+fptr.seg]
        mov es,ax
        xor di,di
        mov cx,psp.end-psp
        mov si,psp
        rep movsb
@@:
        mov si,root
        call disk
        mov dl,[si+disk.drv]
        mov bx,[si+disk.ptr]
        mov word[bx+fptr.off],0
        call far dword[bx+fptr.off]
        mov word[bx+fptr.off],100h
        jmp @b
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;     FUNCTIONS      ;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
psp:
        push ds es fs gs
        mov ax,cs
        mov ds,ax
        mov ax,100h
        call ax
        pop gs fs es ds
        mov dword[fs:0],'abcd'
        retf
.end:
include '../fool/disk.inc'
include '../fool/fptr.inc'
;align 4
macro Disk cmd,drv,cnt,chs,ptr {
        dd disk
        db cmd,drv
        dw cnt
        dd chs,ptr,0,0 }
root:
        Disk disk.read,disk.fd0,1,2,.ptr
.ptr:   dd 1000h:0100h,512
free = 510-(padding-$$)
padding rb free
        dw 0aa55h
bits = 12
    repeat bits/4
        d = '0' + free shr (bits-%*4) and 0Fh
        if d > '9'
            d = d + 'A'-'9'-1
        end if
        display d
    end repeat
display 'h free bytes ',13,10
    

disk.inc
this is the only way i found to play with BIOS sectors without any error. it's huge, but it is fiable.

Code:
disk:
.call=0    ; function
.cmd=4     ; drive command read or write
.drv=5     ; drive number, BIOS based
.cnt=6     ; count of sectors
.s=8       ; starting sector
.h=9       ; starting head
.c=10      ; starting cylinder

.ptr=12

.s0=16     ; number of sectors
.h0=17     ; number of heads
.c0=18     ; number of cylinders

.lba0=20   ; number of lba sectors

.read=2    ;
.write=3   ;

.fd0=0     ;
.fd1=1     ;
.fd2=2     ;
.fd3=3     ;
.hd0=80h   ;
.hd1=81h   ;
.hd2=82h   ;
.hd3=83h   ;

        push esi edi
        call .id
        mov edi,[si+.ptr]
        or edi,edi
        jne @f
        pop edi esi
        ret
@@:
        mov eax,[di+fptr.size]
        shr eax,1             ; ah is holding the sector count
        jc .1
        or al,al              ; if the mod 512 is not nul
        je @f
.1:
        inc ah                ; there is one extra sector to write
@@:
        movzx eax,ah
        mov [si+.cnt],ax     ; sectors to write
        mov al,[si+.s]
        mov ah,[si+.h]
        mov bx,[si+.c]
        mov cx,[si+.cnt]
        mov dx,[di+fptr.off]
        push ax bx cx dx es
.next:
        dec word[si+.cnt]
        jl .end
        push ax bx
        mov cx,bx
        mov bl,cl
        mov cl,ch
        mov ch,bl
        shl cl,6
        and cl,0c0h
        or cl,al
        mov dh,ah
        pushaw
        call .atom
        jnc @f
        popaw
        pushaw
        call .atom
        jnc @f
        popaw
        pushaw
        call .atom
        jnc @f
.error:
        popaw
        pop bx ax
        clc
        jmp .tchao
@@:
        add word[di+fptr.off],512
        popaw
        pop bx ax
        inc al
        cmp al,[si+.s0]
        jne @f
        mov al,1
        inc ah
        cmp ah,[si+.h0]
        jl @f
        mov ah,0
        inc bx
        cmp bx,[si+.c0]
        jl .next
        mov bx,0
@@:
        jmp .next
.atom:
        call .reset
        mov ax,[di+fptr.seg]
        or ax,ax
        jne @f
        mov ax,ds
@@:
        mov es,ax
        mov bx,[di+fptr.off]
        mov ah,[si+.cmd]
        mov al,1
        int 13h
        ret
.reset:
        mov dl,[si+.drv]
        mov ah,0
        int 13h
        ret
@@:
        mov word[si+.c0],0
        mov byte[si+.h0],0
        mov byte[si+.s0],0
        mov dword[si+.lba0],0
        clc
        ret
.id:
        cmp byte[si+.drv],0
        jns .floppy
        call .reset
        jc @b
        mov ah,8
        mov dl,[si+.drv]
        int 13h
        inc dh
        mov [si+.h0],dh
        mov bx,cx
        and cl,not 0c0h
        mov [si+.s0],cl
        mov cl,ch
        mov ch,bl
        shr ch,6
        inc cx
        mov [si+.c0],cx
@@:
        movzx eax,byte[si+.s0]
        movzx ebx,byte[si+.h0]
        movzx ecx,word[si+.c0]
        imul eax,ebx
        imul eax,ecx
        mov [si+.lba0],eax
        stc
        ret
.floppy:
        mov word[si+.c0],80
        mov byte[si+.h0],2
        mov byte[si+.s0],18
        jmp @b
.end:
        stc
.tchao:
        pop es dx cx bx ax
        mov [si+.s],al
        mov [si+.h],ah
        mov [si+.c],bx
        mov [di+fptr.off],dx
        mov [si+.cnt],cx
        cmp byte[si+.drv],0
        jl @f
        mov dx,3f2h
        out dx,al
@@:
        pop edi esi
        ret
    

fptr.inc
this is my handle for memory zones in real mode.
a single 8 bytes structure. a far pointer, and a size counter.
Code:
fptr:
.off=0
.seg=2
.size=4
    

reference to a fptr is made by loading it's local adress in ds.

Code:
fptr0: dd 1000h:0,0ffffh
...
mov eax,fptr0
call far dword[eax]
...
    


at home, bochs is ok to load it, launch .com and return. problem to load c:/boot


i just propose as a challenge... create the official fasm example for bootloader, different of the fat12 loader still present.

a collaborative project to bring the ultimate boot loader for os construction under fasm..

anyone interested?
Post 20 Sep 2010, 19:58
View user's profile Send private message Visit poster's website Reply with quote
Display posts from previous:
Post new topic Reply to topic

Jump to:  
Goto page 1, 2  Next

< Last Thread | Next Thread >
Forum Rules:
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum
You cannot attach files in this forum
You can download files in this forum


Copyright © 1999-2024, Tomasz Grysztar. Also on GitHub, YouTube.

Website powered by rwasa.