diff options
author | Robert de Bath <rdebath@poboxes.com> | 1996-11-03 22:33:35 +0100 |
---|---|---|
committer | Lubomir Rintel <lkundrak@v3.sk> | 2013-10-23 23:33:35 +0200 |
commit | c218c617b5be443b7968308506969ad2b726d73c (patch) | |
tree | 0051f396af56133d24fcf2ab757fabc78c1a09bf /bootblocks | |
parent | 0936b9aeab611665645a4e6bafaded7ca76dd189 (diff) | |
parent | 0d2fbe9b1bd284ce2cad55be17e8f2c896031a25 (diff) | |
download | dev86-c218c617b5be443b7968308506969ad2b726d73c.tar.gz |
Import Dev86src-0.0.8.tar.gzv0.0.8
Diffstat (limited to 'bootblocks')
-rw-r--r-- | bootblocks/Makefile | 65 | ||||
-rw-r--r-- | bootblocks/README | 62 | ||||
-rw-r--r-- | bootblocks/bootlist.s | 256 | ||||
-rw-r--r-- | bootblocks/com_bcc.s | 65 | ||||
-rw-r--r-- | bootblocks/i86_funcs.c | 190 | ||||
-rw-r--r-- | bootblocks/makeboot.c | 187 | ||||
-rw-r--r-- | bootblocks/minix.c | 537 | ||||
-rw-r--r-- | bootblocks/monitor.c | 353 | ||||
-rw-r--r-- | bootblocks/relocate.c | 77 | ||||
-rw-r--r-- | bootblocks/standalone.c | 309 | ||||
-rw-r--r-- | bootblocks/sysboot.s | 77 | ||||
-rw-r--r-- | bootblocks/tarboot.s | 509 | ||||
-rw-r--r-- | bootblocks/tich.s | 38 | ||||
-rw-r--r-- | bootblocks/tiny.s | 55 |
14 files changed, 2780 insertions, 0 deletions
diff --git a/bootblocks/Makefile b/bootblocks/Makefile new file mode 100644 index 0000000..0ed6e1d --- /dev/null +++ b/bootblocks/Makefile @@ -0,0 +1,65 @@ + +HOSTCC=cc +HOSTCCFLAGS=-O + +CC=bcc +CFLAGS=-ansi -O -Ms +AS=as86 +ASFLAGS=-0 +# LST=-l $*.lst + +nothing: + @more README + +all: makeboot monitor.out bin + +CSRC=minix.c +SSRC=tarboot.s tiny.s com_bcc.s tich.s sysboot.s bootlist.s + +encap: $(SSRC:s=v) $(CSRC:c=v) +bin: $(SSRC:s=bin) $(CSRC:c=bin) + +MOBJ=monitor.o i86_funcs.o relocate.o +MSRC=monitor.c i86_funcs.c relocate.c + +install: + +monitor.out: $(MOBJ) + $(CC) $(CFLAGS) $(MOBJ) -o monitor.out + +monitor: $(MSRC) + @rm -f $(MOBJ) + make 'CFLAGS=-ansi -O' monitor.out + mv monitor.out monitor + @rm -f $(MOBJ) + +minix.s: minix.c + bcc -Mf -O -S minix.c + +makeboot: tarboot.v sysboot.v makeboot.c + $(HOSTCC) $(HOSTCCFLAGS) -o makeboot makeboot.c + +clean: + rm -f monitor makeboot minix.s *.o *.bin *.out *.lst *.sym *.v + +tgz: minix.bin monitor.out makeboot + tar cfV bootblocks.tar ENIAC monitor.out \ + README Makefile \ + $(MSRC) standalone.c makeboot.c \ + $(CSRC) $(SSRC) \ + makeboot minix.bin + makeboot bootblocks.tar + gzip -f9 bootblocks.tar + +distribution: + tar czf /tmp/bootblocks.tar.gz README Makefile \ + $(MSRC) standalone.c makeboot.c \ + $(CSRC) $(SSRC) + +.SUFFIXES: .bin .v + +.s.bin: + $(AS) $(ASFLAGS) -b $*.bin -s $*.sym -l $*.lst $*.s + +.s.v: + as86_encap $*.s $*.v $*_ $(ASFLAGS) $(LST) diff --git a/bootblocks/README b/bootblocks/README new file mode 100644 index 0000000..c57f3aa --- /dev/null +++ b/bootblocks/README @@ -0,0 +1,62 @@ + +To install the tarfile bootsector +--------------------------------- + + Create the makeboot program: + +$ make makeboot + +Create the tarfile + +$ tar cvfV /dev/fd0 ENIAC monitor.out item2 item3 + +Make it bootable + +$ makeboot /dev/fd0 + +Note, the distribution tar file is made using this procedure and can be booted +if uncompressed and copied onto a raw floppy. + +To install the minixfs boot sector +---------------------------------- + + Make a minix filesystem on the floppy: + +$ mkfs -t minix /dev/fd0 1440 + +$ mkfs -t minix /dev/fd0 1200 + + Make the bootblock program. + +$ make minix.bin + + Install it + +$ cp minix.bin /dev/fd0 + + Place a Linux-8086 executable in the root directory. + +$ make monitor.out +$ mount -t minix /dev/fd0 /mnt +$ cp monitor.out /mnt/linux +$ umount /dev/fd0 + + Or in a tar file: + +$ make monitor.out +$ mount -t minix /dev/fd0 /mnt +$ tar cvf /mnt/linux monitor.out long list of other files +$ umount /dev/fd0 + + This works on my 3 1/4 floppy, and it _should_ work on any double sided + drive. Be sure to make the filesystem the full size of the floppy. + +To boot the floppy in DOSEMU +---------------------------- + +$ dos -A + + Press ^C to exit DOSEMU from inside monitor.c + +Rob. + diff --git a/bootblocks/bootlist.s b/bootblocks/bootlist.s new file mode 100644 index 0000000..889842a --- /dev/null +++ b/bootblocks/bootlist.s @@ -0,0 +1,256 @@ +! This bootsector is modified by the installer to have a list of sectors at +! offset 256. + +! Table format is a list of dwords. Each dword has a partition offest in +! the low 24 bits and a count in the high. +! +! Prob better to make it: HH DD MM LL rather than DD HH MM LL +! as this matches the BIOS better +! +! Note: +! Stack top is at abs location 64k. +! + +BOOTSEG = 0x07c0 +LOADSEG = 0x07e0 ! Just after boot sector. + +public linear +linear = 1 ! Is linear processing done ? + +public floppy +floppy = 0 *linear ! Allow for floppy drive ? +public reloc +reloc = 1 *linear ! Auto configure of bootpart. + +macro locn + if *-start>?1 + fail + endif + .blkb ?1 + start-* +mend + +use16 +entry start + +org $7b00 + +! temporary space + +n_cyl: .blkw 1 +n_secs: .blkw 1 +t_drive: .blkb 1 +t_sector: .blkb 1 +t_secs: .blkw 1 + +org $7c00 +start: + j code + +runit: + jmpi 0,0 ! This instruction is altered by the installer + +public execaddr ! Via this label. +execaddr = *-4 + +public bootpart +bootpart: + .data4 0x80000011 +code: + + if reloc + mov cx,[si+8] ! Fetch the linear address of part from DS:SI + mov dh,[si+10] ! DL is drive number + xchg dl,dh ! Into normal form. + endif + + xor ax,ax + mov ds,ax + mov ss,ax + mov sp,ax + + if reloc + mov [bootpart],cx + mov [bootpart+2],dx + endif + +! ASSUME ds=ss= 0 (cs should also be zero) + + mov ax,#LOADSEG + mov es,ax + + mov si,#table +load_addrs: + cld + + if linear + lodsw + mov cx,ax + add cx,[bootpart] + lodsw + mov dx,[bootpart+2] + adc dl,al + mov al,ah + else + lodsw + mov cx,ax + lodsw + mov dx,ax + lodsb + endif + + test al,al + jz runit + +loadem: + xor bx,bx + push ax + call cread + jc failed + pop ax + mov cl,#5 + sal ax,cl + mov bx,es + add ax,bx + mov es,ax + j load_addrs + +! Humm, something goes wrong, not much we can do ... +! Let`s squeak then try again +failed: + mov ax,#$0E45 + mov bx,#7 + int $10 + pop ax + + j loadem + +cread: + ! This function is like BIOS 1302 but it`s linear. + ! It's taken, almost, intact from LILO. + + ! DH is drive, DL:CX is linear address, AL is count. + ! ES:BX is load address, beware of DMA limitations + + ! All registers except AX and flags are preserved. + + mov t_secs,al ! save number of sectors +lnread: push cx ! keep linear address + push dx + xchg dl,dh + + if linear + if floppy + test dl,#0x80 ! Floppy is physical only. + jz lrd + endif + + push bx ! BX is used as scratch + push cx ! LSW + push dx ! MSW with drive + mov ah,#8 ! get drive geometry (do not clobber ES:DI) + push es + push di + int 0x13 + pop di + pop es + mov bl,dh ! BL <- #heads + pop dx ! get MSW + + jnc int_ok ! error -> quit + + pop cx ! discard stack contents + pop bx + pop dx + pop cx + ret ! (carry is already set) +int_ok: + mov t_drive,dl ! save drive + mov dl,dh ! linear address into DX:AX + xor dh,dh + mov bh,dh ! (clear BH too) + pop ax + push cx ! compute #cyls-1 + xchg ch,cl + rol ch,1 + rol ch,1 + and ch,#3 + mov n_cyl,cx ! save #cyls-1 + pop cx + and cx,#0x3f ! CX <- #secs + mov n_secs,cx + div cx ! AX <- track, DX <- sector + inc dl + mov t_sector,dl + xor dx,dx ! divide by #heads + inc bx + div bx ! AX <- cylinder, DX <- head + mov dh,dl ! set up DX (head:drive) + mov dl,t_drive + cmp ax,n_cyl ! valid cylinder number ? + ja linerr3 ! no -> error + xchg ah,al ! build cylinder number + ror al,1 + ror al,1 + or al,t_sector + mov cx,ax + pop bx ! restore BX + and ax,#0x3f ! read beyond end of track ? + add ax,t_secs + cmp ax,n_secs + jna intrk ! no -> go on + mov al,n_secs ! read to end of track + sub al,t_sector + inc al + jmp lrd ! read it +intrk: mov al,t_secs ! read all sectors + + endif + +lrd: push ax ! save AX and BX + push bx + + mov ah,#2 ! + int 0x13 ! read sectors + + pop bx ! restore AX and BX and the linear address + pop ax + pop dx + pop cx + + if linear + + jc linerr ! error -> quit + sub t_secs,al ! adjust sector count + jz lindone ! zero -> done + xor ah,ah ! increase linear address + add cx,ax + adc dh,#0 + xchg ah,al ! move BX + add ah,ah + add bx,ax + jc interr ! crossing segment boundaries -> error + br lnread ! process remaining sectors + +linerr3:pop bx ! pop BX and linear address + pop dx + pop cx +interr: xor ax,ax ! zero indicates internal error + + else + jnc lindone + endif + +linerr: stc ! error + ret +lindone:clc ! no error + ret ! done + + +!-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + +public table +table: +! .long 0x80000012 +! .byte 1 +! .long 0x07e00000 +! .byte 0 diff --git a/bootblocks/com_bcc.s b/bootblocks/com_bcc.s new file mode 100644 index 0000000..26daff3 --- /dev/null +++ b/bootblocks/com_bcc.s @@ -0,0 +1,65 @@ + +! This header assumes only that we're loaded at a 16 byte boundry + +ENDOFF=4 ! If you add code adjust this till it stops failing. + +org 0 +entry start +public start +start: + call chk ! This chunk allows this code to exist at _any_ click +chk: + pop ax + mov cl,#4 + shr ax,cl + mov bx,cs + add ax,bx + push ax + mov bx,#going + push bx + retf +going: + mov ds,ax + + add ax,#ENDOFF+2 ! New CS + mov bx,ax ! Saved + mov dx,[a_entry] ! Save the entry - zero + mov ax,[btype] + and ax,#$20 ! Split I/D ? + jz impure + mov cl,#4 + mov ax,[a_text] + shr ax,cl +impure: ! ax is now offset 'tween CS&DS + add ax,bx ! ax = DS + mov ss,ax + mov sp,[a_total] ! SS:SP is now ready for prog. + mov ds,ax + xor cx,cx ! argc, argv and envp = 0 + push cx + push cx + push cx + push bx ! CS + push dx ! Entry address + retf ! Gone. + +! Check for overlap +end_of_code: + if end_of_code>hitme + fail + endif + +.org ((ENDOFF)<<4)-1 +hitme: +.byte 0xFF ! Marker + +magic: .space 2 ! A.out header +btype: .space 2 +headerlen: .space 4 +a_text: .space 4 +a_data: .space 4 +a_bss: .space 4 +a_entry: .space 4 +a_total: .space 4 +a_syms: .space 4 +.org (ENDOFF+2)<<4 ! Code start. diff --git a/bootblocks/i86_funcs.c b/bootblocks/i86_funcs.c new file mode 100644 index 0000000..a17e7a4 --- /dev/null +++ b/bootblocks/i86_funcs.c @@ -0,0 +1,190 @@ + +#include <stdio.h> +#include <errno.h> +#include "i86_funcs.h" + +int x86 = 0; /* CPU major number */ +char *x86_name = ""; /* and it's name */ +int x86_emu = 0; /* Is this a PC emulator ? */ +int x86_a20_closed = 1; /* Is the A20 gate closed ? */ +int x86_test = 0; /* In test mode */ +int x86_fpu = 0; + +unsigned boot_mem_top = 0x4000; /* Default 64k, the minimum */ +long main_mem_top = 0; /* K of extended memory */ + +int a20_closed() +{ + register int v, rv = 0; + if (x86_test) + return 1; /* If not standalone don't try */ + + __set_es(0); + v = __peek_es(512); + __set_es(0xFFFF); + if (v == __peek_es(512+16)) + { + __set_es(0); + __poke_es(512, v+1); + __set_es(0xFFFF); + if (v+1 == __peek_es(512+16)) + rv = 1; + __set_es(0); + __poke_es(512, v); + } + return x86_a20_closed = rv; +} + +void open_a20() +{ +#asm + call empty_8042 + mov al,#0xD1 ! command write + out #0x64,al + call empty_8042 + mov al,#0xDF ! A20 on + out #0x60,al +empty_8042: + .word 0x00eb,0x00eb + in al,#0x64 ! 8042 status port + test al,#2 ! is input buffer full? + jnz empty_8042 ! yes - loop, with no timeout! +#endasm +} + +void cpu_check() +{ + static char *name_808x[] = + { + "8088", "8086", "80C88", "80C86", "NEC V20", "NEC V30", "808x Clone" + }; + + static char *name_8018x[] = + { + "80188", "80186", "8018x Clone" + }; + static char cpubuf[] = "80x86+"; + int c, major; + + c = cputype(0); + x86_fpu = (c < 0); + major = ((c >> 8) & 0x1F); + c &= 0xFF; + x86 = (major&0xF); + if (major == 0) + { + if (c > 6) c = 6; + x86_name = name_808x[c]; + } + else if (major == 1) + { + if (c > 3) c = 3; + x86_name = name_8018x[c]; + } + else + { + cpubuf[2] = (major&0xF)+'0'; + cpubuf[5] = (major > 15 ? '+' : '\0'); + x86_name = cpubuf; + if (c & 0x01) x86_emu = 1; /* Already in protected mode !!! */ + } +} + +void mem_check() +{ + if (x86_test) return; /* If not standalone don't try */ + { +#asm + int 0x12 ! Amount of boot memory + mov cl,#6 + sal ax,cl ! In segments + mov [_boot_mem_top],ax + + ! Next check for extended + mov al,[_x86] ! If we ain't got a 286+ we can't access it anyway + cmp al,#2 + jl is_xt + + mov ah,#0x88 ! + int 0x15 + jnc got_ext ! Error!? This should _not_ happen ... but ... +is_xt: + xor ax,ax +got_ext: + mov word ptr [_main_mem_top+2],#0 + mov [_main_mem_top],ax + +#endasm + } + + if( main_mem_top == 0xFFFFL ) + { + /* It say 64Mb-1k - Hmmmm I think it might be 128! */ + } +} + +#define RIGHTS (0x93000000L) + +static struct { + char gdt0[8]; + char gdt1[8]; + unsigned short src_len; + long src_seg; + unsigned int spad; + unsigned short dst_len; + long dst_seg; + unsigned int dpad; + char gdt5[8]; +} GDT = { + "","", + 0xFFFF, RIGHTS, 0, + 0xFFFF, RIGHTS, 0, + "" +}; + +ext_put(from, to, length) +unsigned int from, to, length; +{ + if(x86_test) return 3; + GDT.src_seg = RIGHTS + from + ((long)__get_ds()<<4); + GDT.dst_seg = RIGHTS + ((long)to<<8); + if( length == 0xFFFF ) length = 0x8000; + else length = ((length+1)>>1); + return asm_copy(length); +} + +ext_get(from, to, length) +unsigned int from, to, length; +{ + if(x86_test) return 3; + GDT.src_seg = RIGHTS + ((long)from<<8); + GDT.dst_seg = RIGHTS + to + ((long)__get_ds()<<4); + if( length == 0xFFFF ) length = 0x8000; + else length = ((length+1)>>1); + return asm_copy(length); +} + +static asm_copy(length) +{ +#asm +#if !__FIRST_ARG_IN_AX__ + mov bx,sp + mov ax,[bx+2] +#endif + push es + push si + mov cx,ax + mov ah,$87 + push ds + pop es + mov si,#_GDT + int $15 + jc err + xor ax,ax +err: + mov al,ah + xor ah,ah + push si + push es +#endasm +} diff --git a/bootblocks/makeboot.c b/bootblocks/makeboot.c new file mode 100644 index 0000000..5a6348d --- /dev/null +++ b/bootblocks/makeboot.c @@ -0,0 +1,187 @@ + +#include <stdio.h> + +#include "tarboot.v" +#include "sysboot.v" + +char tarblock[512]; + +char *bootblock = tarboot_data; + +struct tar_head { + char name[100]; + char mode[8]; + char uid[8]; + char gid[8]; + char size[12]; + char mtime[12]; + char chksum[8]; + char linkflag; + char linkname[100]; + char magic[8]; + char uname[32]; + char gname[32]; + char devmajor[8]; + char devminor[8]; + char padding[167]; +} ; + +#define head (*(struct tar_head*) tarblock) +#define boothead (*(struct tar_head*) bootblock) + +int force = 0; +int relocatable = 0; +int tableload = 0; +long loadaddress = 0x8000; +long execaddress = 0x8000; + +main(argc, argv) +int argc; +char ** argv; +{ + int ar; + int done=0; + + if( sizeof(head) != sizeof(tarblock) ) + { fprintf(stderr, "Program structure error\n"); exit(1); } + + for(ar=1; ar<argc; ar++) if(argv[ar][0]=='-') switch(argv[ar][1]) + { + case 'f': force++; break; + case 'r': relocatable++; break; + case 't': tableload++; break; + case 'l': sscanf(argv[ar]+2, "%li", &loadaddress); break; + case 'x': sscanf(argv[ar]+2, "%li", &execaddress); break; + + case '?': Usage(1); break; + default: Usage(0); break; + } + else + { + mktarboot(argv[ar]); + done++; + } +} + +Usage(flg) +int flg; +{ + fprintf(stderr, "Usage: makeboot [-f] device\n"); + exit(9); +} + +mktarboot(fname) +char * fname; +{ + FILE * fd; + + fd = fopen(fname, "r+"); + if( !fd ) { perror(fname); exit(1); } + + if( fread(tarblock, sizeof(tarblock), 1, fd) != 1 ) + { fprintf(stderr, "Cannot read boot block\n"); exit(1); } + + check_tar(1); + mangle_tarvol(); + + rewind(fd); + if( fwrite(tarblock, sizeof(tarblock), 1, fd) != 1 ) + { fprintf(stderr, "Cannot write boot block\n"); exit(1); } + + rewind(fd); + if( fread(tarblock, sizeof(tarblock), 1, fd) != 1 ) + { fprintf(stderr, "Cannot re-read boot block\n"); exit(1); } + + if( fread(tarblock, sizeof(tarblock), 1, fd) == 1 && head.linkflag == '0' ) + printf("Boot block installed to boot file %s\n", head.name); + + fclose(fd); + exit(0); +} + +unsigned int oct(s) +char *s; +{ + unsigned int val = 0; + int i; + for(i=0; i<8; i++) if( s[i] >= '0' && s[i] <= '7' ) + val = (val<<3) + s[i] - '0'; + return val; +} + +check_tar(fatal) +int fatal; +{ + char vbuf[100], *p; + unsigned int csum = 0; + long osum = -1; + + osum = oct(head.chksum); + memset(head.chksum, ' ', sizeof(head.chksum)); + + for(p=tarblock; p<tarblock+sizeof(tarblock); p++) + csum += (*p & 0xFF); + + if( csum != osum ) + { + fprintf(stderr, "TAR file checksum failed, this isn't a tar file.\n"); + if(fatal) exit(9); + return -1; + } + if( head.linkflag != 'V' ) + { + fprintf(stderr, "Tar file doesn't start with a volume label\n"); + if(fatal) exit(8); + return -1; + } + + strcpy(vbuf, boothead.name); strcat(vbuf, " Volume 1"); + if( !force && strcmp(boothead.name, head.name) != 0 + && strcmp(vbuf, head.name) != 0 ) + { + fprintf(stderr, "Volume is labeled as '%s' not '%s'\n", + head.name, boothead.name); + fprintf(stderr, "Use -f flag to force write\n"); + if(fatal) exit(1); + return -1; + } + return 0; +} + +mangle_tarvol() +{ + char lbuf[20]; + char * p; + unsigned int csum = 0; + int i; + + struct tar_head temp; + + temp = boothead; + + /* Copy preserved fields + */ + memcpy(temp.mtime, head.mtime, sizeof(temp.mtime)); + + memset(temp.name, 0x90, 16); + for(i=0; head.name[i] && head.name[i] != ' ' && i<14; i++) + { + int ch = head.name[i]; + if( islower(ch) ) ch = toupper(ch); + if( strchr("/?@ABCDEFGHIJKLMNO", ch) == 0 ) + ch = '?'; + temp.name[i] = ch; + } + temp.name[i++] = 0; + temp.name[i] = 0xC0; + + head = temp; + /* Calculate the checksum */ + memset(head.chksum, ' ', sizeof(head.chksum)); + + for(p=tarblock; p<tarblock+sizeof(tarblock); p++) + csum += (*p & 0xFF); + + sprintf(head.chksum, "%7o", csum); +} + diff --git a/bootblocks/minix.c b/bootblocks/minix.c new file mode 100644 index 0000000..f6ba7b4 --- /dev/null +++ b/bootblocks/minix.c @@ -0,0 +1,537 @@ +/* + * This bootblock loads the linux-8086 executable in the file 'linux' + * from the root directory of a minix filesystem. + * + * Copyright (C) 1990-1996 Robert de Bath, distributed under the GPL Version 2 + * Based on minix filesystem definitions. + */ + +#include <a.out.h> + +#undef DOTS /* define to have dots printed */ +#define zone_shift 0 /* for any < 32M (non-zero not supported yet) */ + +#define seg_at(k) ((k)*64) +#define seg_of(p) ((unsigned int)p >>4) +#define BOOTSEG (0x07c0) +#define LOADSEG (0x1000) + +#asm +BOOTSEG = 0x07c0 +BOOTADDR = 0x7c00 +LOADSEG = 0x1000 ! This must be sector aligned + +.text +! Apparently on startup the only things we can assume are that we start at +! `start` (ABS addr $07C00) ... + +! So first set CS=DS=ES=SS=0 +! The we move this to $0500 and put the stack at the top of the first 64k. +! The directory 'file' is loaded $1500 and scanned there. +! The final executable will be loaded in the 2nd 64k chunk. +! +org $0500 ! The lowest available address. +start: + include sysboot.s + org codestart + + xor ax,ax + mov ds,ax + mov es,ax + mov ss,ax + mov sp,ax + + mov ax,#$0204 ! Read 4 sectors, code + superblock. + mov bx,#start ! Where this _should_ be + mov cx,#$0001 ! From sector 1 + xor dx,dx ! Of the floppy drive head zero + int $13 + + jmpi code,#0 + +#endasm + +/****************************************************************************/ +/* Super block table. The root file system and every mounted file system + * has an entry here. The entry holds information about the sizes of the bit + * maps and inodes. The s_ninodes field gives the number of inodes available + * for files and directories, including the root directory. Inode 0 is + * on the disk, but not used. Thus s_ninodes = 4 means that 5 bits will be + * used in the bit map, bit 0, which is always 1 and not used, and bits 1-4 + * for files and directories. The disk layout is: + * + * Item # blocks + * boot block 1 + * super block 1 + * inode map s_imap_blocks + * zone map s_zmap_blocks + * inodes (s_ninodes + 1 + INODES_PER_BLOCK - 1)/INODES_PER_BLOCK + * unused whatever is needed to fill out the current zone + * data zones (s_nzones - s_firstdatazone) << s_log_zone_size + * + * A super_block slot is free if s_dev == NO_DEV. + */ + +#define BLOCK_SIZE 1024 /* # bytes in a disk block */ + +/* Flag bits for i_mode in the inode. */ +#define I_TYPE 0170000 /* this field gives inode type */ +#define I_REGULAR 0100000 /* regular file, not dir or special */ +#define I_BLOCK_SPECIAL 0060000 /* block special file */ +#define I_DIRECTORY 0040000 /* file is a directory */ +#define I_CHAR_SPECIAL 0020000 /* character special file */ +#define I_SET_UID_BIT 0004000 /* set effective uid on exec */ +#define I_SET_GID_BIT 0002000 /* set effective gid on exec */ +#define ALL_MODES 0006777 /* all bits for user, group and others */ +#define RWX_MODES 0000777 /* mode bits for RWX only */ +#define R_BIT 0000004 /* Rwx protection bit */ +#define W_BIT 0000002 /* rWx protection bit */ +#define X_BIT 0000001 /* rwX protection bit */ +#define I_NOT_ALLOC 0000000 /* this inode is free */ + +/* Type definitions */ +typedef unsigned short unshort; /* must be 16-bit unsigned */ +typedef unshort block_nr; /* block number */ +typedef unshort inode_nr; /* inode number */ +typedef unshort zone_nr; /* zone number */ +typedef unshort bit_nr; /* if inode_nr & zone_nr both unshort, + then also unshort, else long */ + +typedef unshort sect_nr; + +typedef long zone_type; /* zone size */ +typedef unshort mask_bits; /* mode bits */ +typedef unshort dev_nr; /* major | minor device number */ +typedef char links; /* number of links to an inode */ +typedef long real_time; /* real time in seconds since Jan 1, 1970 */ +typedef long file_pos; /* position in, or length of, a file */ +typedef short uid; /* user id */ +typedef char gid; /* group id */ + +/* Tables sizes */ +#define NR_ZONE_NUMS 9 /* # zone numbers in an inode */ +#define NAME_SIZE 14 /* # bytes in a directory component */ + +/* Miscellaneous constants */ +#define SUPER_MAGIC 0x137F /* magic number contained in super-block */ + +#define BOOT_BLOCK (block_nr)0 /* block number of boot block */ +#define SUPER_BLOCK (block_nr)1 /* block number of super block */ +#define ROOT_INODE (inode_nr)1 /* inode number for root directory */ + +/* Derived sizes */ +#define NR_DZONE_NUM (NR_ZONE_NUMS-2) /* # zones in inode */ +#define INODES_PER_BLOCK (BLOCK_SIZE/sizeof(d_inode)) /* # inodes/disk blk */ +#define NR_INDIRECTS (BLOCK_SIZE/sizeof(zone_nr)) /* # zones/indir blk */ +#define INTS_PER_BLOCK (BLOCK_SIZE/sizeof(int)) /* # integers/blk */ + +struct super_block { + inode_nr s_ninodes; /* # usable inodes on the minor device */ + zone_nr s_nzones; /* total device size, including bit maps etc */ + unshort s_imap_blocks; /* # of blocks used by inode bit map */ + unshort s_zmap_blocks; /* # of blocks used by zone bit map */ + zone_nr s_firstdatazone; /* number of first data zone */ + short s_log_zone_size; /* log2 of blocks/zone */ + file_pos s_max_size; /* maximum file size on this device */ + short s_magic; /* magic number to recognize super-blocks */ + +} ; + +/* Type definitions local to the File System. */ +typedef struct { /* directory entry */ + inode_nr d_inum; /* inode number */ + char d_name[NAME_SIZE]; /* character string */ +} dir_struct; + +/* Declaration of the disk inode used in rw_inode(). */ +typedef struct { /* disk inode. Memory inode is in "inotab.h" */ + mask_bits i_mode; /* file type, protection, etc. */ + uid i_uid; /* user id of the file's owner */ + file_pos i_size; /* current file size in bytes */ + real_time i_modtime; /* when was file data last changed */ + gid i_gid; /* group number */ + links i_nlinks; /* how many links to this file */ + zone_nr i_zone[NR_ZONE_NUMS]; /* block nums for direct, ind, and dbl ind */ +} d_inode; + +/****************************************************************************/ + +#ifdef zone_shift +#if zone_shift == 0 +#define load_zone load_block +#endif +#else +static short zone_shift; +#endif + +/* The name of the file and inode to start */ +extern char bootfile[]; +extern inode_nr inode; + +/* For multi-sector reads */ +extern sect_nr lastsect; +extern sect_nr firstsect; +extern unsigned loadaddr; +extern unsigned loadcount; + +/* Keep track of zones to load */ +extern zone_nr * next_zone; +extern zone_nr * end_zone; +extern zone_nr indirect; + +/* Where to load zones */ +extern unsigned ldaddr; + +/* Directory reading */ +extern dir_struct * dirptr; +extern unsigned flength; + +/* The 'shape' of the floppy - intuit from superblock */ +extern unsigned n_sectors; + +/* + * #define b_super (*(struct super_block *) 1024) + * #define b_inode ((d_inode *)2048) + * #define b_zone ((zone_nr *)3072) + */ + +extern struct super_block b_super; +extern d_inode b_inode[INODES_PER_BLOCK]; +extern zone_nr b_zone[NR_INDIRECTS]; +extern dir_struct directory[]; + +/****************************************************************************/ + +#asm +! A few variables we need to know the positions of for patching, so export +! them and as86_encaps will make some variables. +.text +export _inode ! Inode to search +_inode: .word 1 ! ROOT_INODE + +export _bootfile ! File to boot, make this whatever you like, +_bootfile: ! 'boot' is good too. + .ascii "linux" + .byte 0,0,0,0,0,0,0,0,0 + +_loadcount: .word 0 +_firstsect: .word 0 +_loadaddr: .word 0 +_lastsect: .word 0 + +code: + call _loadprog + call _runprog + br _nogood +#endasm + +static +load_block(address, blkno) +unsigned address, blkno; +{ + register sect_nr sectno; + if(blkno == 0) { zero_block(address); return; } +#ifdef DOTS + bios_putc('.'); +#endif + + sectno = (sect_nr)blkno * 2; + load_sect(address, sectno); + load_sect(address+32, sectno+1); +} + +static +load_sect(address, sectno) +unsigned address; +sect_nr sectno; +{ + register sect_nr nsect; + + nsect = sectno%n_sectors +1; + sectno /= n_sectors; + nsect |= (sectno<<8); + + if( loadcount ) + { + lastsect++; + if( ( address & 4095 ) && nsect == lastsect ) + { + loadcount++; + return; + } + get_now(); + } + + lastsect = firstsect = nsect; + loadaddr = address; + loadcount = 1; +} + +static +get_now() +{ +#asm + xor dx,dx + mov cx,[_firstsect] + shr ch,#1 + adc dh,#0 + mov es,[_loadaddr] + xor bx,bx + mov ax,[_loadcount] + test ax,ax + jz no_load + mov ah,#2 + int $13 + jc nogood +no_load: + xor ax,ax + mov [_loadcount],ax +#endasm +} + +#asm +nogood: + j _nogood +#endasm + +static +zero_block(address) +{ +#asm +#if __FIRST_ARG_IN_AX__ + mov es,ax +#else + mov bx,sp + mov es,[bx+2] +#endif + push di + mov cx,#512 + xor ax,ax + mov di,ax + rep + stosw + pop di +#endasm +} + +#ifndef load_zone +NOT_DEFINED_load_zone(address, zoneno) +{ +} +#endif + +#ifdef DOTS +static +bios_putc(c) +{ +#asm +#if !__FIRST_ARG_IN_AX__ + mov bx,sp + mov ax,[bx+2] +#endif + mov ah,#$0E + mov bx,#7 + int $10 +#endasm +} +#endif + +static +nogood() +{ +/* This didn't work, chain the boot sector of the HD */ +#asm + push cs + pop es +hcode: + mov ax,#$0201 ! Read 1 sector + mov bx,#BOOTADDR ! In the boot area + mov cx,#$0001 ! From sector 1 + mov dx,#$0080 ! Of the hard drive head zero + int $13 + jc hcode ! Keep trying forever! + jmpi BOOTADDR,0 +#endasm +} + +#asm +end_of_part1: + if *>start+0x200 + fail + endif + .blkb 0x200+start-* +#endasm + +static +loadprog() +{ +#ifdef DOTS + bios_putc('+'); +#endif + if( b_super.s_magic != SUPER_MAGIC ) nogood(); + n_sectors = b_super.s_nzones / 80; + if( n_sectors < 5 ) n_sectors = b_super.s_nzones / 40; + +try_again:; +#ifdef zone_shift + if( zone_shift != b_super.s_log_zone_size) nogood(); +#else + zone_shift = b_super.s_log_zone_size; +#endif + + inode--; + load_block(seg_of(b_inode), inode/INODES_PER_BLOCK + + b_super.s_imap_blocks + + b_super.s_zmap_blocks + + 2); + get_now(); + + ldaddr = LOADSEG; /* Load at 64k mark */ + + { + register d_inode * i_ptr; + i_ptr = b_inode + inode%INODES_PER_BLOCK; + next_zone = i_ptr->i_zone; + flength = i_ptr->i_size; + if( (i_ptr->i_mode & I_TYPE) == I_DIRECTORY ) + { + ldaddr = seg_of(directory); + inode = 0; /* Mark - we've no _file_ inode yet */ + } + } + + end_zone = next_zone+NR_DZONE_NUM; + load_zone(seg_of(b_zone), (indirect = next_zone[NR_DZONE_NUM])); + get_now(); + + for(;;) + { + if( next_zone >= end_zone ) + { + if( indirect != 0 ) + { + next_zone = b_zone; + end_zone = next_zone + NR_INDIRECTS; + indirect = 0; + continue; + } + break; + } + load_zone(ldaddr, *next_zone); + next_zone++; + ldaddr += (seg_at(1) << zone_shift); + } + get_now(); + +#ifdef DOTS + bios_putc('\r'); + bios_putc('\n'); +#endif + if(!inode) + { +#ifdef DOTS + bios_putc('+'); +#endif + dirptr = directory; + while(flength > 0) + { +register char * s = bootfile; +register char * p = dirptr->d_name; + + if( dirptr->d_inum ) + { + for(;;) + { + if( *s == '\0') + { + if(*p == '\0') + { + inode = dirptr->d_inum; + goto try_again; + } + break; + } + if( *s++ != *p++ ) break; + } + } + flength -= 16; + dirptr++; + } + nogood(); + } +} + +static +runprog() +{ +/* This did work, run the loaded executable */ +#asm + xor dx,dx ! DX=0 => floppy drive + push dx ! CX=0 => partition offset = 0 + mov si,[_n_sectors] ! Save for monitor.out + + mov bx,#LOADSEG + mov ds,bx ! DS = loadaddress + inc bx + inc bx ! bx = initial CS + xor di,di ! Zero + mov ax,[di] + cmp ax,#0x0301 ! Right magic ? + bne nogood ! Yuk ... + mov ax,[di+2] + and ax,#$20 ! Is it split I/D ? + jz impure ! No ... + mov cl,#4 + mov ax,[di+8] + shr ax,cl +impure: + pop cx + add ax,bx + mov ss,ax + mov sp,[di+24] ! Chmem value + mov ds,ax + + push bx + push di ! jmpi 0,#LOADSEG+2 + retf +#endasm +} + +#asm +! These functions are pulled from the C library. +libstuff: +imodu: + xor dx,dx + div bx + mov ax,dx ! instruction queue full so xchg slower + ret +idiv_u: + xor dx,dx + div bx + ret +libend: + +vars: +_n_sectors: .word 0 +_next_zone: .word 0 +_end_zone: .word 0 +_indirect: .word 0 +_ldaddr: .word 0 +_dirptr: .word 0 +_flength: .word 0 +varend: + +end_of_prog: + if *>start+0x400 + fail + endif + + .blkb 0x3FF+start-* + .byte 0xFF + +_b_super: .blkb 1024 +_b_inode: .blkb 1024 +_b_zone: .blkb 1024 +_directory: .blkb 32768 + +#endasm diff --git a/bootblocks/monitor.c b/bootblocks/monitor.c new file mode 100644 index 0000000..6c1d9eb --- /dev/null +++ b/bootblocks/monitor.c @@ -0,0 +1,353 @@ + +#define VERSION "0.0.0-ALPHA" +#define NOT_ANSICOLOUR +#define VT52COLOUR + +#include <stdio.h> +#include <errno.h> +#include <ctype.h> +#include <i86_funcs.h> +#include <dos.h> + +char command_buf[256]; + +typedef int (*proc)(); + +int cmd_quit(), cmd_dump(), cmd_seg(), cmd_rel(); +void init_prog(); + +extern struct t_cmd_list { + char * command; + proc func; +} cmd_list[]; + +static unsigned int current_address; +static int number_base = 16; + +#ifdef __STANDALONE__ +main() +#else +main(argc, argv) +int argc; +char ** argv; +#endif +{ +static char minibuf[2] = " "; + int ch, i; + char *cmd, *args, *ptr; + struct t_cmd_list * cptr; + + printf("\n\n"); +#ifdef ANSICOLOUR + printf("\033[H\033[0;44;37m\033[2J"); +#endif +#ifdef VT52COLOUR + printf("\033E\033Rg\033Sa\033J"); +#endif + printf("Linux x86 boot monitor Version %s\n", VERSION); + +#ifndef __STANDALONE__ + if( argc > 1 && strcmp(argv[1], "-t") == 0 ) x86_test=0; else x86_test=1; +#endif + + init_prog(); +#ifdef __STANDALONE__ + { + extern union REGS __argr; + printf("REGS: AX=%04x BX=%04x CX=%04x DX=%04x SI=%04x DI=%04x\n", + __argr.x.ax, __argr.x.bx, __argr.x.cx, __argr.x.dx, + __argr.x.si, __argr.x.di); + } +#endif +#ifdef VT52COLOUR + printf("Colours: "); + printf("\033S \033R_UNL "); + printf("\033S \033R*BLK "); + printf("\033S \033R+BLD "); + printf("\033S \033R!REV"); + printf("\033Sa\033Rg "); + printf("\033R@@\033Raa\033Rbb\033Rcc\033Rdd\033Ree\033Rff\033Rgg"); + printf("\033Rhh\033Rii\033Rjj\033Rkk\033Rll\033Rmm\033Rnn\033Roo"); + printf("\033Sa\033Rg\n"); +#endif + + printf("Type ^C to exit\n"); + + for (;;) + { +#ifdef ANSICOLOUR + printf("\033[36m"); +#endif +#ifdef VT52COLOUR + printf("\033S \033R+\033Sa\033Rc"); +#endif + printf(">"); + fflush(stdout); + ch = read(0, command_buf, sizeof(command_buf)-1) ; + if( ch <= 0 ) break; + command_buf[ch] = '\0'; + if( ch == 1 && command_buf[0] != '\n' ) + { + sprintf(command_buf, "func 0x%02x\n", command_buf[0]&0xFF); + printf("%s", command_buf); + } + if( command_buf[ch-1] == '\n' ) command_buf[ch-1] = 0; + + for(ptr=command_buf; *ptr; ptr++) + { + if(*ptr=='"') do { ptr++; } while(*ptr && *ptr != '"'); + if( isupper(*ptr) ) *ptr = tolower(*ptr); + } + + cmd = command_buf; + while(*cmd == ' ') cmd++; + if( !isalpha(cmd[0]) || !isalpha(cmd[1]) ) + { + minibuf[0] = cmd[0]; + args = cmd+1; + cmd = minibuf; + } + else + { + args = strchr(cmd, ' '); + if( args ) *args++ = 0; + else args = cmd + strlen(cmd); + } + + if( *cmd == 0 ) continue; + + for(cptr = cmd_list; cptr->command; cptr++) + { + if( strcmp(cptr->command, cmd) == 0 ) + break; + } +#ifdef ANSICOLOUR + printf("\033[37m"); +#endif +#ifdef VT52COLOUR + printf("\033S \033Sa\033Rg"); +#endif + if( cptr->command ) + (void) (*cptr->func)(args); + else + printf("Command not found.\n"); + } +} + +/****************************************************************************/ + +void init_prog() +{ + cpu_check(); + mem_check(); + + printf("Processor: %s", x86_name); + if(x86_fpu) printf(" with FPU"); + if(x86_emu) printf(" in protected mode"); + if(!x86_test && x86 > 1) + { + printf(", A20 gate "); + if( a20_closed() ) + { + open_a20(); + if( a20_closed() ) + printf("won't open!!"); + else + printf("is now open"); + } + else printf("is already open."); + } + printf("\n"); + + printf("There is %dk of boot memory", boot_mem_top/64); + if( main_mem_top ) + { + printf(" %ld.%ldM of main memory", + main_mem_top/1024, + (10*main_mem_top)/1024%10 + ); + } + printf("\n"); + + if( main_mem_top >= 0xFC00L ) + printf("There may be more main memory available but the BIOS don't say\n"); +} + +/****************************************************************************/ + +int +getnum(numptr, valptr) +char ** numptr; +unsigned int * valptr; +{ + char * ptr = *numptr; + unsigned int val = 0; + int base = number_base; + int flg = 0; + + while( *ptr && *ptr <= ' ' ) ptr++; + switch(*ptr) + { + case '$': case '&': case 'X': + base=16; ptr++; break; + case '#': + base=10; ptr++; break; + case '%': + base=2; ptr++; break; + case '0': + if( ptr[1] == 'X' ) { base=16; ptr+=2; } + break; + case '-': + *numptr = ptr+1; + return 0; + } + + while(*ptr) + { + int d = -1, ch; + ch = *ptr; + if( ch >= '0' && ch <= '9' ) d = ch - '0'; + if( ch >= 'a' && ch <= 'z' ) d = ch - 'a' + 10; + if( ch >= 'A' && ch <= 'Z' ) d = ch - 'A' + 10; + + if( d>=0 && d<base ) + { + val = val * base + d; + ptr++; + flg=1; + } + else + break; + } + if( flg ) + { + *numptr = ptr; + if(valptr) *valptr = val; + else return val; + } + return flg; +} + +/****************************************************************************/ + +int cmd_quit(args) +char * args; +{ + printf("Bye\n"); + exit(0); +} + +cmd_memdump(ptr) +char * ptr; +{ + int count = 128; + int i,j; + int es = __get_es(); + +#define rmem(x) __peek_es( (x)+current_address ) + + getnum(&ptr, ¤t_address); + getnum(&ptr, &count); + + for(i=0; i<count; i+=16) + { + printf("%04x:%04x:", es, current_address); + for(j=0; j<16; j++) + printf(" %02x", rmem(j)); + printf(" "); + for(j=0; j<16; j++) + if( rmem(j) >= ' ' && rmem(j) <= '~' ) + putchar(rmem(j)); + else + putchar('.'); + putchar('\n'); + current_address += 16; + current_address &= 0xFFFF; + } + +#undef rmem +} + +int cmd_nop(ptr) +char * ptr; +{ +} + +int cmd_seg(ptr) +char * ptr; +{ + int es = __get_es(); + + if( getnum(&ptr, &es) ) + { + __set_es(es); + current_address = 0; + } + else + printf("Current segment 0x%04x\n", es); + return 0; +} + +int cmd_set_base(ptr) +{ + int obase = number_base; + int nbase; + number_base = 10; + + if( getnum(&ptr, &nbase) ) + { + if( nbase < 2 || nbase > 36 ) + printf("Can't use that base\n"); + else + obase = nbase; + } + else printf("Current base is %d\n", obase); + + number_base = obase; + return 0; +} + +int cmd_rel(ptr) +char * ptr; +{ + int nseg = 0xFFFF; + + getnum(&ptr, &nseg); + + printf("Monitor code seg from 0x%04x ", __get_cs()); + fflush(stdout); + relocator(nseg); + printf("to 0x%04x\n", __get_cs()); +} + +/****************************************************************************/ + +struct t_cmd_list cmd_list[] = +{ + {"exit", cmd_quit}, {"quit", cmd_quit}, {"q", cmd_quit}, + {"memdump",cmd_memdump}, {"m", cmd_memdump}, + /* Display bytes */ + {"seg", cmd_seg}, /* Set default segment */ + {"rel", cmd_rel}, /* Relocate self */ + {"base", cmd_set_base}, + {"n", cmd_set_base}, + {"#", cmd_nop}, +/* + {"edit", cmd_edit}, Alter memory + {"move", cmd_move}, Move memory contents + + {"dir", cmd_dir}, Display dir of inode + {"load", cmd_load}, Load file of inode + {"stat", cmd_stat}, Stat info of inode + + {"zimage", cmd_zimage}, Load and run 386 zimage from inode or tar file + {"bimage", cmd_bimage}, Load and run 386 bzimage from inode or tar file + {"image", cmd_image}, Load and run 8086 image from inode or tar file + + {"read", cmd_read}, Read sector + {"write", cmd_write}, Write sector + + {"call", cmd_call}, load and run a bcc linux-8086 program. +*/ + {0,0} +}; diff --git a/bootblocks/relocate.c b/bootblocks/relocate.c new file mode 100644 index 0000000..121699e --- /dev/null +++ b/bootblocks/relocate.c @@ -0,0 +1,77 @@ + +#include <i86_funcs.h> + +static unsigned memseg = 0, memlen = 0; + +char buf[1]; + +void +relocator(newseg) +unsigned newseg; +{ + unsigned moved, codelen; + unsigned es = __get_es(); + + if( x86_test ) return; /* I don't think so! */ + + /* Where do we start */ + if(memseg == 0) + { + memseg = __get_cs(); + codelen = __get_ds()-memseg; + __set_es(memseg-2); + memlen = __deek_es( 24 ); + memlen >>=4; + if( memlen == 0 ) memlen = 0x1000; + memlen += codelen; + __set_es(es); + } + + if( newseg < 0x50 ) return; + + if( newseg == 0xFFFF ) + { + newseg = boot_mem_top; + if( newseg > 0x90000 ) newseg = 0x90000; + newseg -= memlen; + } + + /* If the old area overlaps the new then fail */ + if( newseg >= memseg && newseg < memseg+memlen ) return; + if( memseg >= newseg && memseg < newseg+memlen ) return; + + /* Copy segments, done in 32k chunks */ + for(moved=0; moved < memlen; ) + { + unsigned int lump; + if( memlen <= 0x800 ) lump = memlen; else lump = 0x800; + + __movedata(memseg+moved, 0, newseg+moved, 0, (lump<<4)); + moved += lump; + } + + /* re-link int 0x80 + __set_es(0); + __doke_es(0x80*4+2, newseg); + __set_es(es); + */ + + /* The actual jump ... */ + memseg = newseg; +#asm + mov ax,ds + mov bx,cs + sub ax,bx + mov bx,[_memseg] + add ax,bx + push bx + call L_x + mov ds,ax + mov ss,ax + mov [_memseg],bx +#endasm +} +#asm +L_x: + retf +#endasm diff --git a/bootblocks/standalone.c b/bootblocks/standalone.c new file mode 100644 index 0000000..57634d4 --- /dev/null +++ b/bootblocks/standalone.c @@ -0,0 +1,309 @@ + +#include <errno.h> +#asm +entry _int_80 ! Tell ld86 we really do need this file. + ! then call the init stuff before main. + + loc 1 ! Make sure the pointer is in the correct segment +auto_func: ! Label for bcc -M to work. + .word _pre_main ! Pointer to the autorun function + .word no_op ! Space filler cause segs are padded to 4 bytes. + .text ! So the function after is also in the correct seg. +#endasm + +void int_80(); + +static void pre_main() +{ + /* Set the int 0x80 pointer to here */ + __set_es(0); + __doke_es(0x80*4+0, int_80); + __doke_es(0x80*4+2, __get_cs()); + bios_coninit(); +} + +void int_80() +{ +#asm +SYS_EXIT=1 +SYS_FORK=2 +SYS_READ=3 +SYS_WRITE=4 +SYS_OPEN=5 +SYS_CLOSE=6 +SYS_CHDIR=12 +SYS_LSEEK=19 +ENOSYS=38 + + push es + push si + push di + push dx + push cx + push bx + cmp ax,#SYS_READ + jne L1 + call _func_read + jmp L0 +L1: + cmp ax,#SYS_WRITE + jne L2 + call _func_write + jmp L0 +L2: + cmp ax,#SYS_LSEEK + jne L3 + call _func_lseek + jmp L0 +L3: + cmp ax,#SYS_EXIT + jne L4 + call _func_exit + jmp L0 +L4: + mov ax,#-ENOSYS +L0: + pop bx + pop cx + pop dx + pop di + pop si + pop es + iret +#endasm +} + +func_lseek() { return -38; } + +func_write(bx,cx,dx,di,si,es) +int bx,dx; +char * cx; +{ + register int v, c; + if(bx == 1 || bx == 2) + { + for(v=dx; v>0; v--) + { + c= *cx++; + if( c == '\n') bios_putc('\r'); + bios_putc(c); + } + return dx; + } + return -EBADF; +} + +func_read(bx,cx,dx,di,si,es) +int bx,dx; +char * cx; +{ + if(bx == 0) return read_line(cx, dx); + return -EBADF; +} + +read_line(buf, len) +char * buf; +int len; +{ + int ch; + int pos=0; + + if( len == 1 ) + { + buf[0]=((ch=bios_getc())&0xFF?ch&0xFF:((ch>>8)&0xFF|0x80)); + return 1; + } + + for(ch=0;;) + { + if(ch != '\003') + { + ch = bios_getc(); + if( pos == 0 && (ch&0xFF) == 0 ) + { + buf[0] = ((ch>>8)|0x80); + return 1; + } + ch &= 0x7F; + } + if( ch == '\r' ) + { + bios_putc('\r'); bios_putc('\n'); + buf[pos++] = '\n'; + return pos; + } + if( ch >= ' ' && ch != 0x7F && pos < len-1) + bios_putc(buf[pos++] = ch); + else if( (ch == '\003' || ch == '\b') && pos > 0 ) + { + bios_putc('\b'); bios_putc(' '); bios_putc('\b'); + pos--; + } + else if( ch == '\003' ) + return 0; + else + bios_putc('\007'); + } +} + +#define CTRL(x) ((x)&0x1F) +static int last_attr = 0x07; +static int con_mode; +static int con_size = 0x184F; +static int con_colour = 0; + +bios_coninit() +{ +#asm + mov ax,#$0F00 + int $10 + mov _con_mode,ax +#endasm + if( (con_mode &0xFF) > 39 ) con_size = (con_size&0xFF00) + (con_mode&0xFF); + if( (con_mode&0xFF00) != 0x700) + con_colour = 1; +} + +bios_putc(c) +int c; +{ +static char tbuf[3]; +static int tcnt=0; + if(tcnt) + { + tbuf[tcnt++] = c; + if( tcnt < 3 && (tbuf[0] != CTRL(']') || tbuf[1] < '`' || tbuf[1] > 'p')) + return; + if( tbuf[0] == CTRL('P') ) + { + if( tbuf[1] >= 32 && tbuf[1] <= 56 + && tbuf[2] >= 32 && tbuf[2] <= 111 ) + asm_cpos((tbuf[1]-32), (tbuf[2]-32)); + } + else + { + if( tbuf[1] >= '`' ) + last_attr = ( (tbuf[1]&0xF) | (last_attr&0xF0)); + else + last_attr = ( (tbuf[2]&0xF) | ((tbuf[1]&0xF)<<4)); + + if( !con_colour ) + last_attr = (last_attr&0x88) + ((last_attr&7)?0x07:0x70); + } + tcnt=0; + return; + } + if( c & 0xE0 ) { asm_colour(last_attr) ; asm_putc(c); } + else switch(c) + { + case CTRL('L'): + asm_cpos(0,0); + asm_cls(); + break; + case CTRL('P'): + case CTRL(']'): + tbuf[tcnt++] = c; + break; + default: + asm_putc(c); + break; + } + return; +} + +static asm_putc(c) +{ +#asm +#if !__FIRST_ARG_IN_AX__ + mov bx,sp + mov ax,[bx+2] +#endif + mov ah,#$0E + mov bx,#7 + int $10 +#endasm +} + +static asm_colour(c) +{ +#asm +#if __FIRST_ARG_IN_AX__ + mov bx,ax +#else + mov bx,sp + mov bx,[bx+2] +#endif + mov ah,#$08 + int $10 + mov ah,#$09 + mov cx,#1 + int $10 +#endasm +} + +static asm_cls() +{ +#asm + push bp ! Bug in some old BIOS's + !mov ax,#$0500 + !int $10 + mov ax,#$0600 + mov bh,_last_attr + mov cx,#$0000 + mov dx,_con_size + int $10 + pop bp +#endasm +} + +static asm_cpos(r,c) +{ +#asm +#if __FIRST_ARG_IN_AX__ + mov bx,sp + mov dh,al + mov ax,[bx+2] + mov dl,al +#else + mov bx,sp + mov ax,[bx+2] + mov dh,al + mov ax,[bx+4] + mov dl,al +#endif + mov ah,#$02 + mov bx,#7 + int $10 +#endasm +} + +bios_getc() +{ +#asm + xor ax,ax + int $16 +#endasm +} + +static void be_safe() +{ +#asm + iret +#endasm +} + +func_exit(bx,cx,dx,di,si,es) /* AKA reboot! */ +{ + __set_es(0); + __doke_es(0xE6*4+2,__get_cs()); + __doke_es(0xE6*4+0,be_safe); +#asm + mov ax,#$FFFF + int $E6 ! Try to exit DOSEMU + mov ax,#$0040 ! If we get here we're not in dosemu. + mov es,ax + seg es + mov [$72],#$1234 ! Warm reboot. + jmpi $0000,$FFFF +#endasm +} diff --git a/bootblocks/sysboot.s b/bootblocks/sysboot.s new file mode 100644 index 0000000..496b7a5 --- /dev/null +++ b/bootblocks/sysboot.s @@ -0,0 +1,77 @@ + +! The master boot sector will have setup a stack, +! this is normally at 0:7c00 down. +! DS, SS, CS and ES will all have value 0 so the execution address is 0:7c00 +! On entry the register SI will be pointer to the partition entry that +! this sector was loaded from, DL is the drive. + +! Also if it's a standard Master boot DH will be the head, CX will be the +! sector and cylinder, BX=7C00, AX=1, DI=7DFE, BP=SI. There's a reasonable +! chance that this isn't true though. + +! The Master boot itself will have been loaded and run at $07c00 +! The BIOS must have setup a stack because interrupts are enabled +! Little else can be assumed because DOS doesn`t assume anything either + +sysboot_start: +j codestart + +.blkb sysboot_start+3-* +public dosfs_stat +dosfs_stat: +.blkb 8 ! System ID +.word 0 ! Sector size +.byte 0 ! Cluster size +.word 0 ! Res-sector +.byte 0 ! FAT count +.word 0 ! Root dir entries +.word 0 ! Sector count (=0 if large FS) +.byte 0 ! Media code +.word 0 ! FAT length +.word 0 ! Sect/Track +.word 0 ! Heads +.long 0 ! Hidden sectors +! Here down is DOS 4+ +.long 0 ! Large FS sector count +.byte 0 ! Phys drive +.byte 0 ! Reserved +.byte 0 ! DOS 4 +.long 0 ! Serial number +.blkb 11 ! Disk Label (DOS 4+) +.blkb 8 ! FAT type + +.blkb sysboot_start+0x3E-* +public codestart +codestart: + hlt + +! Partition table +public partition_1 +public partition_2 +public partition_3 +public partition_4 + +.blkb sysboot_start+0x1BE-* +partition_1: +.byte 0,0,0,0,0,0,0,0 ! IN,SH,SS,ST,OS,EH,ES,ET +.long 0 ! Linear position (0 based) +.long 0 ! Linear length +.blkb sysboot_start+0x1CE-* +partition_2: +.byte 0,0,0,0,0,0,0,0 ! IN,SH,SS,ST,OS,EH,ES,ET +.long 0 ! Linear position (0 based) +.long 0 ! Linear length +.blkb sysboot_start+0x1DE-* +partition_3: +.byte 0,0,0,0,0,0,0,0 ! IN,SH,SS,ST,OS,EH,ES,ET +.long 0 ! Linear position (0 based) +.long 0 ! Linear length +.blkb sysboot_start+0x1EE-* +partition_4: +.byte 0,0,0,0,0,0,0,0 ! IN,SH,SS,ST,OS,EH,ES,ET +.long 0 ! Linear position (0 based) +.long 0 ! Linear length + +.blkb sysboot_start+0x1FE-* +.word 0xAA55 + diff --git a/bootblocks/tarboot.s b/bootblocks/tarboot.s new file mode 100644 index 0000000..ffa8db6 --- /dev/null +++ b/bootblocks/tarboot.s @@ -0,0 +1,509 @@ +! +! This is floppy bootblock to load the first item from a tar file. +! +! The tar file is constructed with a GNU TAR label at the start +! which is replaced with this by the makeboot.c program. +! +! The first item must be a Linux-8086 executable compiled with the -Ms option +! +! Copyright (C) 1996 Robert de Bath, distributed under the GPL Version 2. +! + +BOOTADDR= 0x7C00 ! The address that the boot seg is loaded. + +RELADDR = 0x0600 ! This is floppy, so we can relocate to 'super' address + ! It appears the 0500 is also ok as that's DOS memory + ! But then where can we get 200 bytes of stack! + +STACK = 0x0600 ! Inital stack, 0 makes bad_magic + +LOADSEG = 0x0080 ! Segment for program load, this must be 512b aligned + ! The first 32 bytes are the a.out header. +DEBUG=1 ! Print dots ... + +!-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + +macro locn + if *-start>?1 + fail + endif + .blkb ?1 + start-* +mend + +! On startup from a floppy boot it`s probably best if we assume _nothing_ +! that we don`t have to ... +! +! So, `start` is, erm, right here :-) +! The boot block is re-loaded from the floppy for relocation. +!-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + use16 + org RELADDR + +start: + ! Don't even _think_ of changing this unless you're 110% sure! + .byte 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90 + .byte 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90 + + block start + .asciz "ENIAC" + .byte $C0 + endb + + ! All right, I'll help, you can use any of these chars: + ! "/?@ABCDEFGHIJKLMNO" + ! Others are likely to cause ... problems. + +!-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + +! Beware; the assumption is this code is relocatable. + + xor ax,ax + mov ds,ax + mov es,ax + mov ss,ax + if STACK = 0 + mov sp,ax + else + mov sp,#STACK ! Stack location + endif + cld + +! ASSUME ds=ss=es=cs=0 +keep_trying1: +! Get the tar block after this program, and relocate this code. + mov ax,#$0202 ! Read 2 sectors + mov bx,#start ! Where this _should_ be + mov cx,#$0001 ! From sector 1 + xor dx,dx ! Of the floppy drive head zero + int $13 + jc keep_trying1 + jmpi going,#0 +going: + +! OK. Code will now be run at correct address. + +if DEBUG + call pboot +endif + + mov al,tar_link + cmp al,#'0 + jnz nogood ! Make sure next item is file. + + call probe_floppy + + call get_size ! Get number of clicks in di + cmp di,#0 + jz nogood ! If it`s zero .. Hmm + + if STACK = 0 + mov sp,#bad_magic ! Real bad magic :-) + endif + + call load_sectors + +! This requires that we have been relocated, so we can't call it too soon. +nogood: + push cs + pop es + +hcode: + mov ax,#$0201 ! Read 1 sector + mov bx,#BOOTADDR ! into the boot area + mov cx,#1 ! sector 1 + mov dx,#$0080 ! hard drive head zero + int $13 + jc hcode ! Keep trying forever! + jmpi BOOTADDR,#0 + +!-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +! +! These are the number of sectors per track that will be scanned for. +! For 3.5 inch floppies 36 is 2.88 Mb, 18 is 1.44Mb, 21 is 1.68Mb on +! a 1.44Mb floppy drive. 15 and 9 are for 5.25 inch floppies. + +disksizes: .byte 36,21,18,15,9 + +! End of part 1 +!-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +! This is important bits of the TAR Block. +! The chksum field will need to be changed if any mods are done to this +! file so that the bare header is a TAR file. If it's installed using +! makeboot that program will correct the sum as it also changes the time. + + locn(100) +blk_mode: .asciz " 4111" +blk_uid: .blkb 8 +blk_gid: .blkb 8 +blk_size: .blkb 12 +blk_mtime: .asciz "6141567743 " +blk_chksum: .asciz " 131141" +blk_link: .byte 'V + +! Sneaks here, overlay zero init vars on tar data. + + block blk_mode +public sectors +sectors: .blkw 1 ! POSITION OF THIS FIELD IS MAGIC! + ! other programs know it's at pos 100 + +bios_disk: .blkb 12 ! BPB for FD0 +head: .word 0 ! current head +track: .word 0 ! current track + + endb + +!-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +! +! This code taken from the Linux bootsector and adjusted to suit +! +! Many BIOS's default disk parameter tables will not +! recognize multi-sector reads beyond the maximum sector number +! specified in the default diskette parameter tables - this may +! mean 7 sectors in some cases. +! +! Since single sector reads are slow and out of the question, +! we must take care of this by creating new parameter tables +! (for the first disk) in RAM. We will set the maximum sector +! count to 36 - the most we will encounter on an ED 2.88. +! +! High doesn't hurt. Low does. +! +! Segments are as follows: ds=es=ss=cs=0 +! + +probe_floppy: + mov di,#bios_disk + + mov bx,#0x78 +! 0:bx is parameter table address + push ds + lds si,[bx] + +! ds:si is source + + mov cl,#6 +! copy 12 bytes + cld + push di + + rep + movsw + + pop di + pop ds + movb 4[di],*36 ! patch sector count + + mov [bx],di + mov 2[bx],es + +! It seems that there is no BIOS call to get the number of sectors. Guess +! 36 sectors if sector 36 can be read, 18 sectors if sector 18 can be read, +! 15 if sector 15 can be read. Otherwise guess 9. + + mov si,#disksizes ! table of sizes to try + +probe_loop: + lodsb + cbw ! extend to word + mov sectors, ax + cmp al,#9 + je got_sectors ! if all else fails, try 9 + xchg ax, cx ! cx = track and sector + xor dx, dx ! drive 0, head 0 + mov bx,#probe_buf ! address after setup (es = cs) + mov ax,#0x0201 ! service 2, 1 sector + int 0x13 + jc probe_loop ! try next value +got_sectors: + + ret + +!-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +! +! This function reads the size of the first file in the TAR image. It's +! stored in octal in the tar header that was loaded just after this block. + +get_size: + mov di,#tar_size + xor dx,dx + xor bx,bx + xor cx,cx + +next_dig: + mov al,[di] + and al,#$F8 + cmp al,#'0 + jne no_dig + + mov al,[di] + and al,#$07 + + mov cl,#3 +mul_loop: + sal bx,#1 ! Double prec * 8 + rcl dx,#1 + loop mul_loop + or bl,al + +no_dig: + inc di + cmp di,#tar_mtime + jne next_dig + + add bx,#15 ! How many clicks ? + adc dx,cx ! AKA zero + mov cl,#4 +div_loop: + shr dx,#1 + rcr bx,#1 + loop div_loop + + mov di,bx +bad_magic: + ret + +!-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +! +! This is good so far, is it an 8086 a.out file ? +! If so start it. + +go_go_go: + xor dx,dx ! DX=0 => floppy drive + push dx ! CX=0 => partition offset = 0 + mov si,[sectors] ! Save for monitor.out + + mov bx,#LOADSEG + mov ds,bx ! DS = loadaddress + inc bx + inc bx ! bx = initial CS + xor di,di ! Zero + mov ax,[di] + cmp ax,#0x0301 ! Right magic ? + jnz bad_magic ! Yuk ... + mov ax,[di+2] + and ax,#$20 ! Is it split I/D ? + jz impure ! No ... + mov cl,#4 + mov ax,[di+8] + shr ax,cl +impure: + pop cx ! Partition offset. + add ax,bx + mov ss,ax + mov sp,[di+24] ! Chmem value + mov ds,ax + + push bx ! jmpi 0,#LOADSEG+2 + push di + + ! AX=ds, BX=cs, CX=X, DX=X, SI=X, DI=0, BP=X, ES=X, DS=*, SS=*, CS=* + retf + +!-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +! This isn't in a normal volume lable, no problem it leaves more space. +! +! locn(257) +! blk_magic: .ascii "ustar " +! .blkb 1 +! blk_uname: .ascii "TarBoot/Copyright" +! blk_uname_end: +! .blkb 32+blk_uname-blk_uname_end +! blk_gname: .ascii "R de Bath" +! blk_gname_end: +! .blkb 32+blk_gname-blk_gname_end +! blk_devmaj: .blkb 8 +! blk_devmin: .blkb 8 +! +!-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + +if DEBUG +dot: mov al,#'. +putc: + push bx + mov bx,#7 + mov ah,#$E + int $10 + pop bx + ret + +endif + +!-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +! +! This code taken from the Linux bootsector and adjusted to suit +! +! This routine loads the system at address LOADSEG, making sure +! no 64kB boundaries are crossed. We try to load it as fast as +! possible, loading whole tracks whenever we can. +! +! LOADSEG must be sector aligned and sectors will be loaded upto +! the next 64k boundry past the segment specified by DI. + +load_sectors: + if LOADSEG & $F000 = 0 + xor ax,ax + else + mov ax,#LOADSEG & $F000 ! segment to load to + endif + mov es,ax + +! dx=sectors read of current track +! bx=offset in memory of block +! si=sectors read to block +! al=number to read + +read_it: + mov dx,#2 ! Volume lable + tar header + if LOADSEG & $0FFF = 0 + xor si,si + else + mov si,#(LOADSEG & $FFF)>>5 + endif + add di,#LOADSEG +rp_read: +if DEBUG + call dot +endif + mov ax,es + cmp ax,di ! have we loaded all yet? + jbe ok1_read + jmp go_go_go ! Loaded, run it. +ok1_read: + mov ax,sectors ! nr of sectors/track + + sub ax,dx ! remaining of track + + mov cx,ax ! cx= remaining + + add cx,si ! boundary check + cmp cl,#128 + jbe ok2_read ! + ! to much-> fill block + mov ax,#128 ! ax=0 + sub ax,si ! so much may be read + +ok2_read: + mov bx,si + mov cx,#9 + shl bx,cl + call read_track ! do it + mov cx,ax ! cl=read blocks + + add ax,dx ! ax=new sectors + + cmp ax,sectors ! track done? + jne ok3_read + mov ax,#1 ! yes + sub ax,head + jne ok4_read ! next head + inc track ! next track +ok4_read: + mov head,ax + xor ax,ax +ok3_read: + mov dx,ax + + add si,cx + cmp si,#128 + jne rp_read + + mov ax,es + add ah,#0x10 + mov es,ax + + xor si,si + jmp rp_read + +read_track: + push dx + push ax + push bx + + mov cx,dx + mov dx,track + inc cx + mov ch,dl + mov dx,head + mov dh,dl + and dx,#0x0100 + mov ah,#2 + + int 0x13 +! ah=02h al=nr sectors to read +! ch=cylinder +! cl=sector +! dh=head +! dl=drive +! es:bx=buffer + + jc bad_rt + pop bx + pop ax + pop dx + ret + +bad_rt: xor ah,ah + xor dl,dl + int 0x13 + + pop bx + pop ax + pop dx + jmp read_track + +!-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +! +! This is the GNU-TAR 'isextended' field. It must be zero or gtar goes apeshit. + locn(482) + .byte 0 +!-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + +if DEBUG +pboot: + mov si,#mesg +nextc: + lodsb + call putc + cmp al,#0 + jnz nextc + ret + +locn(512-16) +mesg: +.ascii "Tarboot loading " +endif + +!-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + +if DEBUG = 0 + locn(510) +! This isn't a hard disk boot sector so don't give it an HD magic +! .word 0xAA55 + .word 0 +endif + +! From here down is where we load stuff. + +blk_load: ! Address of block load +tar_name: .blkb 100 +tar_mode: .blkb 8 +tar_uid: .blkb 8 +tar_gid: .blkb 8 +tar_size: .blkb 12 +tar_mtime: .blkb 12 +tar_chksum: .blkb 8 +tar_link: .blkb 1 ! "0" +tar_linkname: .blkb 100 +tar_magic: .blkb 8 ! "ustar " +tar_uname: .blkb 32 +tar_gname: .blkb 32 +tar_devmaj: .blkb 8 +tar_devmin: .blkb 8 +tar_padd: + + + locn(1024) +probe_buf: .blkb 512 + + diff --git a/bootblocks/tich.s b/bootblocks/tich.s new file mode 100644 index 0000000..830f742 --- /dev/null +++ b/bootblocks/tich.s @@ -0,0 +1,38 @@ +! + +org 0 + call chk !This chunk allows this code to exist at _any_ click +chk: + pop ax + mov cl,#4 + shr ax,cl + mov bx,cs + add ax,bx + push ax + mov bx,#going + push bx + retf +going: + mov ds,ax + mov es,ax + +! Print 'mesg' + mov ah,#0x03 ! read cursor pos + xor bh,bh + int 0x10 + + mov cx,#(emesg-mesg) + mov bp,#mesg + mov bx,#$7 ! page 0, attribute 7 (normal) + mov ax,#$1301 ! write string, move cursor + int $10 + +nogood: + j nogood + +mesg: +.ascii "Hello world" +emesg: + +org 510 + .word 0xAA55 diff --git a/bootblocks/tiny.s b/bootblocks/tiny.s new file mode 100644 index 0000000..6090cd3 --- /dev/null +++ b/bootblocks/tiny.s @@ -0,0 +1,55 @@ +! +! This floppy bootblock bypasses the floppy boot ... +! + +BOOTSEG = 0x07c0 +BOOTDISK = 0x80 + +! Apparently on startup the only things we can assume are that we start at +! `start` (ABS addr $07C00) and we`ll have a few bytes of stack storage... + +! So first set DS=ES= 0x07c0 + include sysboot.s + .blkb codestart-* + +start: + mov ax,#BOOTSEG + mov ds,ax + mov es,ax + +! Print 'mesg' + mov ah,#0x03 ! read cursor pos + xor bh,bh + int 0x10 + + mov cx,#(emesg-mesg) + mov bp,#mesg + mov bx,#$7 ! page 0, attribute 7 (normal) + mov ax,#$1301 ! write string, move cursor + int $10 + +nogood: + xor si,si + mov di,#$0200 + mov cx,#$0100 + rep + movw + jmpi hcode,#BOOTSEG+$20 + +hcode: + mov ax,#$0201 ! Read 1 sector + xor bx,bx ! In the boot area + mov cx,#$0001 ! From sector 1 + mov dx,#BOOTDISK ! Of the hard drive head zero + int $13 + jc hcode ! Keep trying forever! + jmpi $7c00,0 + + +mesg: + if BOOTDISK = 0x80 +.ascii "Bypassing floppy boot\r\n" + else +.ascii "Booting drive two\r\n" + endif +emesg: |