Moderators: simonsunnyboy, Mug UK, Zorro 2, Moderator Team
Code: Select all
; ---------------------------
; ATARI FORUM DEMO BOOTBLOCK
; ---------------------------
; (c) 2004 by Simon Sunnyboy / Paradize
; Version 23 May 2004
;
gemdos equ 1
xbios equ 14
bios equ 13
text
; init program
go: move.l sp,a5
lea stackend,sp
; calculate program and data size for TOS - to free unused space
movea.l 4(a5),a5 ; a5 points 100bytes below program start
move.l $c(a5),d0
add.l $14(a5),d0
add.l $1c(a5),d0
add.l #$100,d0
move.l d0,-(sp)
move.l a5,-(sp)
move.w #0,-(sp)
move.w #$4a,-(sp)
trap #gemdos ; SETBLOCK Gemdos
add.l #12,sp ; correct stack
tst.l d0
bne exit ; error occured? -> go to error
; -------------------------
; main program entry point:
; -------------------------
main:
pea my_palette
move.w #$26,-(sp)
trap #xbios
addq.l #6,sp
; print banner...
pea banner
move.w #9,-(sp)
trap #gemdos
addq.l #6,sp
; wait for keypress 'w' or 'q'
press_w:
move.w #8,-(sp)
trap #gemdos
addq.l #2,sp
; w pressed? - then write the bootblock...
cmpi #'w',d0
beq read_boot
cmpi #'W',d0
beq read_boot
; Q pressed? - then terminate program...
cmpi #'q',d0
beq exit
cmpi #'Q',d0
beq exit
cmpi #'t',d0
beq testboot
cmpi #'T',d0
beq testboot
; neither w nor q? - then get another keypress
bra press_w
; read old bootblock from disk including BPB
read_boot:
moveq.w #8,d0
bsr rw_boot
; transfer bootcode to buffer...
transfer_boot:
off: equ $1a
move.l #bootcode,a0
move.w #(bootcode_end-bootcode)/2,d0
move.l #boots+off+2,a1
.loop move.w (a0)+,(a1)+
dbf d0,.loop
move.w #$6000+off,boots
; calculate checksum to make bootcode executable on disk...
make_exec:
move.l #$00000001ffffffff,-(sp)
move.l #-1,-(sp)
move.l #boots,-(sp)
move.w #18,-(sp)
trap #14
lea.l 14(sp),sp
move.w d0,checksum
; write bootcode to disk....
write_boot:
moveq.w #9,d0
bsr rw_boot
; and return to program start....
jmp main
; test bootcode routine
testboot:
; run bootsector routine in supervisor
pea bootcode
move.w #$26,-(sp)
trap #xbios
addq.l #6,sp
move.w #8,-(sp)
trap #gemdos
addq.l #2,sp
jmp main
; terminate program properly and return to desktop or shell...
exit: clr.l -(sp)
trap #gemdos ; TERM PROCESS Gemdos
;------------------------
; SUBROUTINES/ FUNCTIONS
;------------------------
; subroutine reads and writes bootcode from disk
; to/from buffer
rw_boot:
move.w #1,-(sp)
move.l #0,-(sp)
move.w #1,-(sp)
move.w #0,-(sp)
clr.l -(sp)
move.l #boots,-(sp)
move.w d0,-(sp)
trap #14
lea.l 20(sp),sp
rts
; gets called in SUPER
my_palette:
move.w #$777,$FFFF8240.w
move.w #$000,$FFFF825E.w
rts
;-----------------------------------
data
; initialisierte Daten hier...
banner: dc.b 27,"b",15,27,"E",27,"p"
dc.b "------------------------------",13,10
dc.b "The Atari Forum Demo Bootblock",13,10
dc.b "------------------------------",13,10
dc.b 27,"qby Simon Sunnyboy/Paradize",13,10,13,10,10
dc.b "Please insert your disk in drive A and",13,10
dc.b "press 'w' to write a new bootsector.",13,10,13,10
dc.b "REMOVE WRITE PROTECTION TAB!",13,10,13,10,13,10
dc.b "Press 'q' to return to the desktop.",13,10,0
even
boots: ds.b 510
checksum: ds.b 2
even
; a nice raster bootblock
; ripped from a Megatari disk
;
bootcode:
pea bootmsg(pc)
move.w #9,-(sp) ; print text
trap #1
lea 6(sp),a7
move sr,-(sp) ; save irq status
ori.w #$700,sr
clr.l $42a.w ; reset vector
clr.l $426.w ; resvalid
move.w #$ea60,d0 ; loop count
move.w #$474,$ffff825c.w ; color 14 = white
lea $ffff825e.w,a0 ; indirect addressing of color 15
.loop:
clr.w (a0)
clr.w (a0)
clr.w (a0)
clr.w (a0)
clr.w (a0)
clr.w (a0)
move.w #$001,(a0)
move.w (a0),(a0)
move.w #$002,(a0)
move.w (a0),(a0)
move.w #$013,(a0)
move.w (a0),(a0)
move.w #$024,(a0)
move.w (a0),(a0)
move.w #$035,(a0)
move.w (a0),(a0)
move.w #$046,(a0)
move.w (a0),(a0)
move.w #$057,(a0)
move.w (a0),(a0)
move.w (a0),(a0)
move.w (a0),(a0)
move.w #$046,(a0)
move.w (a0),(a0)
move.w #$035,(a0)
move.w (a0),(a0)
move.w #$024,(a0)
move.w (a0),(a0)
move.w #$013,(a0)
move.w (a0),(a0)
move.w #$002,(a0)
move.w (a0),(a0)
move.w #$001,(a0)
move.w (a0),(a0)
clr.w (a0)
move.w (a0),$ffff8240.w
nop
; optional keypress exit
cmpi.b #$39,$fffffc02.w ; SPACE pressed?
beq.s .exit ; then exit
dbra d0,.loop
.exit:
move (sp)+,sr ; restore IRQ status
move.w #$000,$ffff8240.w ; restore background color
rts
bootmsg:
dc.b 27,'b',15,27,'E',27,'Y',11+32,10+32
dc.b "THE ATARI FORUM DEMO"
dc.b 27,'Y',13+32,3+32
dc.b 189,"'2004 http://www.atari-forum.com/ "
dc.b 27,"b",14,27,"Y",24+32,8+32
dc.b "THIS DISK IS VIRUS FREE!",0
bootcode_end: dc.b 0
; BOOTSECTOR CODE END
;
; stack
stkstart: ds.l 256
stackend: ds.l 1
simonsunnyboy wrote:I never had problems with calling GEMDOS or (X)BIOS from bootsector code.
Years ago Grazey/PHF provided me with a skeleton to write bootsectors to floppies. I use it since then. One of my earliest uses was for the Atari Forum Demo bootsector.
Source below, exchange the actual bootsector code between bootcode and bootcode_end labels, and make sure the code uses PC relative addressing (you cannot predict the RAM address used for execution of the boot code)
Code: Select all
/* Atari ST boot sector checksum fixer and code injector */
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
int main(int argc, char **argv) {
FILE *f, *f2;
unsigned short checksum;
unsigned short temp;
unsigned long load_address;
unsigned long fat_address;
int i;
int temp2;
char filenamebuf[13];
char firstpartname[9];
char secondpartname[4];
char *tempstr;
if( argc != 6 ) {
printf("Atari ST boot sector checksum fixer.\nUsage:\n%s diskimage.st boot_sector_code.img load_filename load_address_decimal fat_address_decimal\nThe boot sector code must be headerless raw binary, position-independent code. It can be a maximum of 452 bytes, but can be less.\n\n", argv[0]);
return(-1);
}
load_address = atoi(argv[4]);
fat_address = atoi(argv[5]);
f = fopen(argv[1], "rb+");
if(!f) {
printf("Couldn't open disk image.\n\n");
return(-1);
}
f2 = fopen(argv[2], "rb");
if(!f2) {
fclose(f);
printf("Couldn't open boot sector code file.\n\n");
return(-1);
}
fseek(f2, 0, SEEK_END);
if( ftell(f2) > 452 ) {
fclose(f2);
fclose(f);
printf("Boot sector code file is too long (maximum length 452 bytes)\n\n");
return(-1);
}
fseek(f2, 0, SEEK_SET);
/* Write initial branch instruction and the text "Loader" */
putc(0x60, f);
putc(0x38, f);
fwrite("Loader", 6, 1, f);
fflush(f);
fseek(f, 0x1e, SEEK_SET);
/* Write load address stuff */
putc(0, f); putc(0, f);
putc(0, f); putc(0, f);
putc(0, f); putc(0, f);
putc(0, f); putc(0, f);
putc((load_address >> 24) & 0xff, f);
putc((load_address >> 16) & 0xff, f);
putc((load_address >> 8) & 0xff, f);
putc(load_address & 0xff, f);
putc((fat_address >> 24) & 0xff, f);
putc((fat_address >> 16) & 0xff, f);
putc((fat_address >> 8) & 0xff, f);
putc(fat_address & 0xff, f);
strncpy(filenamebuf, argv[3], 12);
filenamebuf[12] = 0;
/* Convert filename to uppercase */
for( i = 0 ; ; i++ ) {
if( filenamebuf[i] == 0 ) break;
filenamebuf[i] = toupper(filenamebuf[i]);
}
/* Extract first part of filename before extension */
tempstr = strtok(filenamebuf, ".");
if( tempstr ) {
strcpy(firstpartname, tempstr);
} else {
firstpartname[0] = 0;
}
/* Extract filename extension */
tempstr = strtok(NULL, ".");
if( tempstr ) {
strcpy(secondpartname, tempstr);
} else {
secondpartname[0] = 0;
}
/* Pad first part of filename to 8 characters with spaces */
while( strlen(firstpartname) < 8 ) {
strcat(firstpartname, " ");
}
/* Pad extension to 3 characters with spaces */
while( strlen(secondpartname) < 3 ) {
strcat(secondpartname, " ");
}
/* Write full filename */
fwrite(firstpartname, 8, 1, f);
fwrite(secondpartname, 3, 1, f);
putc(0, f);
/* Write boot code */
for(;;) {
temp2 = getc(f2);
if( temp2 < 0 ) break;
putc(temp2, f);
}
fflush(f);
/* Calculate checksum */
fseek(f, 0, SEEK_SET);
checksum = 0;
for( i = 0 ; i < 255 ; i++ ) {
temp = (unsigned short) getc(f);
temp <<= 8;
temp |= (unsigned short) getc(f);
checksum += temp;
}
checksum = 0x1234 - checksum;
fseek(f, 510, SEEK_SET);
putc((checksum >> 8) & 0xff, f);
putc(checksum & 0xff, f);
fclose(f2);
fclose(f);
return(0);
}
Code: Select all
move.w #$0333,$ffff8240.w
move.l filename(pc),-(sp)
move.w #9,-(sp)
trap #1
addq.l #6,sp
move.l envstring(pc),-(sp)
move.l cmdline(pc),-(sp)
move.l filename(pc),-(sp)
move.w #0,-(sp)
move.w #$4b,-(sp)
trap #1
envstring:
dc.b 'PATH=',0,'A:\',0,0
cmdline:
dc.b 0
filename:
dc.b 'LOADER.TOS',0
simonsunnyboy wrote:(you cannot predict the RAM address used for execution of the boot code)
mikro wrote:Actually, this is an interesting point. As far as one TOS version is concerned, this should be a pretty explicit value, shouldn't it? I mean, it's the power cycle, it literally must be the same memory setup in every case.
Could be a nice optimisation for some hardcore boot intro.
mikro wrote:As far as one TOS version is concerned, this should be a pretty explicit value, shouldn't it?
ThorstenOtto wrote:Yes. of course. It is loaded into a static diskbuffer, which will remain the same between boots on the same TOS version. It only differs between TOS versions. But i can't see how this can be exposed to do anything useful. The address might be the same after a reboot, but the contents are of course already overwritten.
Foxie wrote:[I suppose the idea would be to write your code at that address, and then perform a load to bring in the remaining sectors after it. That would save needing to copy the code to a new address.
Can the MMU be disabled?
ThorstenOtto wrote:Can the MMU be disabled?
Of course it can, but i think it would be a bad idea. The tables are set up to map the I/O area from 0xffxxxxxx to 0x00ffffff, and also to mark that area as non-cacheable. Turning that off might have strange results when accessing I/O addresses.
Foxie wrote:I tested overwriting the area between os_end and the start of the basepage. The system blows up catastrophically. I didn't even get a chance to call GEMDOS before it crashed.
So it appears that os_end is not really the end of GEMDOS. It's using the area between os_end and basepage.
ThorstenOtto wrote:That was to be expected. That variable actually does not mean anything, when the GEMDOS is linked with other parts of the OS. The Atari/DR linker assigns addresses to variables in a very unpredictable manner (by walking down its internal hashlist). In practice, that means that every new symbol you use during linking, may lead to a totally different layout. That gave me quite some headaches when compiling the TOS sources.
Code: Select all
; transfer bootcode to buffer...
transfer_boot:
off equ $1a
move.l #bootcode,a0
move.w #(bootcode_end-bootcode)/2,d0
move.l #boots+off+2,a1
.loop: move.w (a0)+,(a1)+
dbf d0,.loop
move.w #$6000+off,boots
Code: Select all
; transfer bootcode to buffer...
transfer_boot:
off equ $1e ; offset to the boot code start
move.l #bootcode,a0 ; copy boot code from here
move.w #(bootcode_end-bootcode)/2,d0 ; number of words of code to copy
move.l #boots+off,a1 ; skip the the boot header
.loop: move.w (a0)+,(a1)+
dbf d0,.loop
move.w #$6000+off-2,boots ; populate $601C, BRA.S branch to code start
Code: Select all
; test bootcode routine
;
test_boot:
bsr.w read_boot ; Read boot sector
cmpi.w #$601a,boots ; Check for common BRA.S words
beq.w .run ; to make sure boot code is loaded
cmpi.w #$601c,boots
beq.w .run
bra.w wait_key
.run: pea boots ; Execute from buffer in supervisor
move.w #$26,-(sp)
trap #xbios
addq.l #6,sp
bra.w main
Users browsing this forum: No registered users and 1 guest