From 726b3f5af1585389326481dec3515e7cccca6636 Mon Sep 17 00:00:00 2001 From: Kenneth J Davis Date: Sat, 28 May 2005 12:10:29 +0000 Subject: [PATCH] set backup boot sector on FAT32, add update option, fix oemboot to work with msdos 7+ git-svn-id: https://svn.code.sf.net/p/freedos/svn/kernel/branches/UNSTABLE@1125 6ac86273-5f31-0410-b378-82cca8765d1b --- boot/oemboot.asm | 128 +++++++++++++++++++++++++++++++++-------------- docs/sys.htm | 12 ++++- docs/sys.txt | 3 +- sys/sys.c | 100 +++++++++++++++++++++++++++--------- 4 files changed, 181 insertions(+), 62 deletions(-) diff --git a/boot/oemboot.asm b/boot/oemboot.asm index 16edb53..a57bdbc 100644 --- a/boot/oemboot.asm +++ b/boot/oemboot.asm @@ -5,17 +5,20 @@ ; Copyright (c) 200?, ; Description: ; OEM boot sector for FreeDOS compatible with IBM's (R) PC-DOS, -; and Microsoft's (R) PC-DOS. It may work with OpenDOS/DR-DOS, -; although the standard FreeDOS boot sector works with later +; and Microsoft's (R) MS-DOS. It may work with older OpenDOS/DR-DOS, +; although the standard FreeDOS boot sector is needed with ver 7+ ; releases. May work with other versions of DOS that use ; IBMBIO.COM/IBMDOS.COM pair. This boot sector loads only up ; to 58 sectors (29KB) of the kernel (IBMBIO.COM) to 0x70:0 then -; jumps to it. As best I can tell, PC-DOS (and assuming MS-DOS -; behaves similar) expects on entry for: +; jumps to it. As best I can tell, PC-DOS (and MS-DOS up to version +; 6.xx behaves similar) expects on entry for: ; ch = media id byte in the boot sector ; dl = BIOS drive booted from (0x00=A:, 0x80=C:, ...) -; ax:bx = the LBA sector of 1st data sector 0x0000:0021 for FAT12 -; ?or? 1st sector of IBMBIO.COM (which is normally 1st data sector) +; ax:bx = the starting (LBA) sector of cluster 2 (ie the 1st +; data sector, which is 0x0000:0021 for FAT12) +; ?note? IBMBIO.COM/IO.SYS may use ax:bx and cluster # stored +; elsewhere (perhaps dir entry still at 0x50:0) to determine +; starting sector for full loading of kernel file. ; it also expects the boot sector (in particular the BPB) ; to still be at 0x0:7C00, the directory entry for IBMBIO.COM ; (generally first entry of first sector of the root directory) @@ -24,6 +27,26 @@ ; may fail for any systems where the changes (???) are needed. ; If the above conditions are not met, then IBMBIO.COM will ; print the not a bootable disk error message. +; +; For MS-DOS >= 7 (ie Win9x DOS) the following conditions +; must be met: +; bp = 0x7C00, ie offset boot sector loaded at +; [bp-4] = the starting (LBA) sector of cluster 2 (ie the 1st +; data sector [this is the same as ax:bx for earlier versions +; and dx:ax in Win9x boot sector] +; The starting cluster of the kernel file is stored in +; di for FAT 12/16 (where si is a don't care) and si:di +; for FAT 32. +; The values for ax,bx,cx,dx,ds and the stack do not +; seem to be important (used by IO.SYS) and so may be any value +; (though dx:ax=[data_start], cx=0, bx=0x0f00 on FAT12 or +; 0x0700 on FAT32, ds=0, ss:sp=0:7b??) + +; the boot time stack may store the original int1E floppy +; parameter table, otherwise nothing else important seems +; stored there and I am unsure if even this value is used +; beyond boot sector code. + ; ; This boot sector only supports FAT12/FAT16 as PC-DOS ; does not support FAT32 and newer FAT32 capable DOSes @@ -78,29 +101,39 @@ ; |BOOT SEC| contains BPB ; |ORIGIN | ; |--------| 0000:7C00 (0:BP) +; |VARS | only known is 1st data sector (start of cluster 2) +; |--------| 0000:7BFC (DS:[BP-4]) ; |STACK | minimal 256 bytes (1/2 sector) ; |- - - - | ; |KERNEL | kernel loaded here (max 58 sectors, 29KB) ; |LOADED | also used as FAT buffer ; |--------| 0070:0000 (0:0700) ; |DOS DA/ | DOS Data Area, -; |ROOT DIR| during boot the 1st sector of root directory +; |ROOT DIR| during boot contains directory entries ; |--------| 0000:0500 ; |BDA | BIOS Data Area ; +--------+ 0000:0400 ; |IVT | Interrupt Vector Table ; +--------+ 0000:0000 +CPU 8086 ; enable assembler warnings to limit instruction set ;%define ISFAT12 1 ; only 1 of these should be set, ;%define ISFAT16 1 ; defines which FAT is supported %define TRYLBAREAD 1 ; undefine to use only CHS int 13h -;%define LOOPONERR 1 ; if defined on error simply loop forever -;%define SETROOTDIR 1 ; if defined dir entry copied to 0:500 +%define SETROOTDIR 1 ; if defined dir entry copied to 0:500 +%define LOOPONERR 1 ; if defined on error simply loop forever ;%define RETRYALWAYS 1 ; if defined retries read forever +;%define WINBOOT 1 ; use win9x kernel calling conventions (name & jmp addr) ;%define MSCOMPAT 1 ; sets default filename to MSDOS IO.SYS +%ifdef WINBOOT ; if set also change from PC-DOS to +%ifndef MSCOMPAT ; kernel name to MS-DOS kernel name +%define MSCOMPAT +%endif +%endif + segment .text %define BASE 0x7c00 ; boot sector originally at 0x0:BASE @@ -133,7 +166,8 @@ segment .text ;%define RootDirSecs PARAMS+0x0 ; # of sectors root dir uses %define fat_start PARAMS+0x2 ; first FAT sector ;%define root_dir_start PARAMS+0x6 ; first root directory sector -%define data_start PARAMS+0x0a ; first data sector +%define first_cluster PARAMS+0x0a ; starting cluster of kernel file +%define data_start bp-4 ; first data sector (win9x expects here) ;----------------------------------------------------------------------- @@ -203,20 +237,33 @@ real_start: mov es, ax mov ss, ax mov bp, BASE - lea sp, [bp-2] - - ; a reset should not be needed here -; int 0x13 ; reset drive + lea sp, [bp-4] ; for DOS <7 this may be [bp] ; For compatibility, diskette parameter vector updated. -; lea di [bp+0x3E] ; just use bp for DR-DOS? +; lea di [bp+0x3E] ; use 7c3e([bp+3e]) for PC-DOS, +; ;lea di [bp] ; but 7c00([bp]) for DR-DOS 7 bug ; mov bx, 4 * 1eh ; stored at int 1E's vector ; lds si, [bx] ; fetch current int 1eh pointer +; push ds ; store original 1eh pointer at stack top +; push si ; so can restore later if needed +; +; Copy table to new location ; mov cl, 11 ; the parameter table is 11 bytes ; rep movsb ; and copy the parameter block ; mov ds, ax ; restore DS +; +; Note: make desired changes to table here +; +; Update int1E to new location +; mov [bx+2], 0 ; set to 0:bp or 0:bp+3e as appropriate +; mov word [bx], 0x7c3e ; (use 0x7c00 for DR-DOS) sti ; enable interrupts + +; If updated floppy parameter table then must notify BIOS +; Otherwise a reset should not be needed here. +; int 0x13 ; reset drive (AX=0) + ; ; Note: some BIOS implementations may not correctly pass drive number ; in DL, however we work around this in SYS.COM by NOP'ing out the use of DL @@ -290,22 +337,21 @@ next_entry: mov cx, 11 je ffDone add si, byte 0x20 ; go to next directory entry - jc near boot_error ; fail if not found and si wraps + jc boot_error ; fail if not found and si wraps cmp byte [si], 0 ; if the first byte of the name is 0, jnz next_entry ; there are no more files in the directory ffDone: - push ax ; store first cluster number + mov [first_cluster], ax ; store first cluster number %ifdef SETROOTDIR ; copy over this portion of root dir to 0x0:500 for PC-DOS ; (this may allow IBMBIO.COM to start in any directory entry) lea di, [ROOTDIR] ; es:di = 0:0500 - mov cx, 0x100 + mov cx, 32 ; limit to this 1 entry (rest don't matter) rep movsw %endif - ; GETFATCHAIN: ; ; Reads the FAT chain and stores it in a temporary buffer in the first @@ -334,7 +380,7 @@ ffDone: mov ax, LOADSEG mov ds, ax ; ds:0 = 0x70:0 = 0:FATBUF - pop ax ; restore first cluster number + mov ax, [first_cluster] ; restore first cluster number push ds ; store LOADSEG next_clust: stosw ; store cluster number @@ -403,7 +449,30 @@ cluster_next: lodsw ; AX = next cluster to read mov ch, [bsMedia] ; ch set to media id mov ax, [data_start+2] ; ax:bx set to 1st data sector mov bx, [data_start] ; + mov di, [first_cluster] ; set di (si:di on FAT32) to starting cluster # +%ifdef WINBOOT + jmp LOADSEG:0x0200 ; yes, pass control to kernel +%else jmp LOADSEG:0000 ; yes, pass control to kernel +%endif + + +; failed to boot +boot_error: +call show +; db "Error! Hit a key to reboot." + db "):." +%ifdef LOOPONERR +jmp $ +%else + + ; Note: should restore floppy paramater table address at int 0x1E + xor ah,ah + int 0x13 ; reset floppy + int 0x16 ; wait for a key + int 0x19 ; reboot the machine +%endif + load_next: dec ax ; cluster numbers start with 2 dec ax @@ -428,22 +497,6 @@ show: pop si jne show ; until done ret -; failed to boot - -boot_error: -%ifdef LOOPONERR -jmp boot_error -%else -call show -; db "Error! Hit a key to reboot." - db "Err." - - xor ah,ah - int 0x13 ; reset floppy - int 0x16 ; wait for a key - int 0x19 ; reboot the machine -%endif - ; readDisk: Reads a number of sectors into memory. ; @@ -564,7 +617,8 @@ read_next_chained: read_ok: mov ax, word [bsBytesPerSec] - shr ax, 4 ; adjust segment pointer by increasing + mov cl, 4 ; adjust segment pointer by increasing + shr ax, cl add word [LBA_SEG], ax ; by paragraphs read in (per sector) add LBA_SECTOR_0, byte 1 diff --git a/docs/sys.htm b/docs/sys.htm index 0b50839..949db0b 100644 --- a/docs/sys.htm +++ b/docs/sys.htm @@ -1,5 +1,5 @@ -sys +sys - FreeDOS system file installer

sys

Copy system files and make a floppy disk or hard disk bootable. @@ -32,6 +32,16 @@ Switches (FreeDOS specific): but the kernel and command.com will not be copied to the destination. + /UPDATE + This option is for updating (or changing) your kernel while + leaving your shell alone. Updates the boot sector and copies + the kernel file(s) to the destination. [Allows installing + latest kernel and boot sector without making a copy of your + current COMMAND.COM or other shell first.] Note: for FreeDOS + kernel, an upgrade can also be performed by simply copying + KERNEL.SYS over an existing bootable one (though making a + backup of your current kernel is encouraged). + /K filename Gives the filename of the kernel file to be copied. This option is only required when the kernel is not called "kernel.sys" diff --git a/docs/sys.txt b/docs/sys.txt index 7292869..f5f13f4 100644 --- a/docs/sys.txt +++ b/docs/sys.txt @@ -1,4 +1,4 @@ -FreeDOS SYS 3.5 +FreeDOS SYS 3.6 documentation by: Jeremy Davis Bart Oldeman @@ -22,6 +22,7 @@ SYS [source] dest: [bootsect] [{option}] {option} is one or more of the following: /BOTH : write to *both* the real boot sector and the image file /BOOTONLY: do *not* copy kernel / shell, only update boot sector or image + /UPDATE : copy kernel and update boot sector (do *not* copy shell) /OEM : indicates boot sector, filenames, and load segment to use /OEM:FD use FreeDOS compatible settings /OEM:DR use DR DOS 7+ compatible settings (same as /OEM) diff --git a/sys/sys.c b/sys/sys.c index fa1b928..042d7f2 100644 --- a/sys/sys.c +++ b/sys/sys.c @@ -32,7 +32,7 @@ #define FDCONFIG /* include support to configure FD kernel */ /* #define DRSYS */ /* SYS for Enhanced DR-DOS (OpenDOS enhancement Project) */ -#define SYS_VERSION "v3.5b" +#define SYS_VERSION "v3.6" #define SYS_NAME "FreeDOS System Installer " @@ -293,25 +293,26 @@ int FDKrnConfigMain(int argc, char **argv); typedef struct DOSBootFiles { const char * kernel; /* filename boot sector loads and chains to */ const char * dos; /* optional secondary file for OS */ - WORD loadseg; /* segment kernel file expects to start at */ + WORD loadaddr; /* segment kernel file expects to start at for stdbs */ + /* or offset to jump into kernel for oem compat bs */ BOOL stdbs; /* use FD boot sector (T) or oem compat one (F) */ LONG minsize; /* smallest dos file can be and be valid, 0=existance optional */ } DOSBootFiles; -#define FREEDOS_FILES { "KERNEL.SYS", NULL, 0x60, 1, 0 }, +#define FREEDOS_FILES { "KERNEL.SYS", NULL, 0x60/*:0*/, 1, 0 }, DOSBootFiles bootFiles[] = { /* Note: This order is the order OEM:AUTO uses to determine DOS flavor. */ #ifndef DRSYS /* FreeDOS */ FREEDOS_FILES #endif - /* DR-DOS */ { "DRBIO.SYS", "DRDOS.SYS", 0x70, 1, 1 }, - /* DR-DOS */ { "IBMBIO.COM", "IBMDOS.COM", 0x70, 1, 1 }, + /* DR-DOS */ { "DRBIO.SYS", "DRDOS.SYS", 0x70/*:0*/, 1, 1 }, + /* DR-DOS */ { "IBMBIO.COM", "IBMDOS.COM", 0x70/*:0*/, 1, 1 }, #ifdef DRSYS /* FreeDOS */ FREEDOS_FILES #endif #ifdef WITHOEMCOMPATBS - /* PC-DOS */ { "IBMBIO.COM", "IBMDOS.COM", 0x70, 0, 6138 }, /* pre v7 DR ??? */ - /* MS-DOS */ { "IO.SYS", "MSDOS.SYS", 0x70, 0, 10240 }, - /* W9x-DOS */ { "IO.SYS", "MSDOS.SYS", 0x70, 0, 0}, + /* PC-DOS */ { "IBMBIO.COM", "IBMDOS.COM", /*0x70:*/0x0, 0, 6138 }, /* pre v7 DR ??? */ + /* MS-DOS */ { "IO.SYS", "MSDOS.SYS", /*0x70:*/0x0, 0, 10240 }, + /* W9x-DOS */ { "IO.SYS", "MSDOS.SYS", /*0x70:*/0x0200, 0, 0 }, #endif }; #define DOSFLAVORS (sizeof(bootFiles) / sizeof(*bootFiles)) @@ -356,7 +357,8 @@ typedef struct SYSOptions { DOSBootFiles kernel; /* file name(s) and relevant data for kernel */ BYTE defBootDrive; /* value stored in boot sector for drive, eg 0x0=A, 0x80=C */ BOOL ignoreBIOS; /* true to NOP out boot sector code to get drive# from BIOS */ - BOOL copyFiles; /* true to copy kernel files and command interpreter */ + BOOL copyKernel; /* true to copy kernel files */ + BOOL copyShell; /* true to copy command interpreter */ BOOL writeBS; /* true to write boot sector to drive/partition LBA 0 */ BYTE *bsFile; /* file name & path to save bs to when saving to file */ BYTE *bsFileOrig; /* file name & path to save original bs when backing up */ @@ -382,6 +384,7 @@ void showHelpAndExit(void) " {option} is one or more of the following:\n" " /BOTH : write to *both* the real boot sector and the image file\n" " /BOOTONLY: do *not* copy kernel / shell, only update boot sector or image\n" + " /UPDATE : copy kernel and update boot sector (do *not* copy shell)\n" " /OEM : indicates boot sector, filenames, and load segment to use\n" " /OEM:FD use FreeDOS compatible settings\n" " /OEM:EDR use Enhanced DR DOS 7+ compatible settings\n" @@ -400,7 +403,7 @@ void showHelpAndExit(void) "%s CONFIG /help\n" #endif /*SYS, KERNEL.SYS/DRBIO.SYS 0x60/0x70*/ - , pgm, bootFiles[0].kernel, bootFiles[0].loadseg + , pgm, bootFiles[0].kernel, bootFiles[0].loadaddr #ifdef FDCONFIG , pgm #endif @@ -422,7 +425,8 @@ void initOptions(int argc, char *argv[], SYSOptions *opts) memset(opts, 0, sizeof(SYSOptions)); /* set srcDrive and dstDrive after processing args */ opts->flavor = OEM_AUTO; /* attempt to detect DOS user wants to boot */ - opts->copyFiles = 1; /* actually copy the kernel and cmd interpreter to dstDrive */ + opts->copyKernel = 1; /* actually copy the kernel and cmd interpreter to dstDrive */ + opts->copyShell = 1; /* cycle through processing cmd line arguments */ for(argno = 1; argno < argc; argno++) @@ -446,7 +450,14 @@ void initOptions(int argc, char *argv[], SYSOptions *opts) /* do *not* copy kernel / shell, only update boot sector or image */ else if (memicmp(argp, "BOOTONLY", 8) == 0) { - opts->copyFiles = 0; + opts->copyKernel = 0; + opts->copyShell = 0; + } + /* copy kernel and update boot sector (do *not* copy shell) */ + else if (memicmp(argp, "UPDATE", 8) == 0) + { + opts->copyKernel = 1; + opts->copyShell = 0; } /* indicates compatibility mode, fs, filenames, and load segment to use */ else if (memicmp(argp, "OEM", 3) == 0) @@ -499,7 +510,7 @@ void initOptions(int argc, char *argv[], SYSOptions *opts) } else if (toupper(*argp) == 'L') /* set Load segment */ { - opts->kernel.loadseg = (WORD)strtol(argv[argno], NULL, 16); + opts->kernel.loadaddr = (WORD)strtol(argv[argno], NULL, 16); } else if (memicmp(argp, "B", 2) == 0) /* set boot drive # */ { @@ -673,7 +684,7 @@ void initOptions(int argc, char *argv[], SYSOptions *opts) /* set compatibility settings not explicitly set */ if (!opts->kernel.kernel) opts->kernel.kernel = bootFiles[opts->flavor].kernel; if (!opts->kernel.dos) opts->kernel.dos = bootFiles[opts->flavor].dos; - if (!opts->kernel.loadseg) opts->kernel.loadseg = bootFiles[opts->flavor].loadseg; + if (!opts->kernel.loadaddr) opts->kernel.loadaddr = bootFiles[opts->flavor].loadaddr; opts->kernel.stdbs = bootFiles[opts->flavor].stdbs; opts->kernel.minsize = bootFiles[opts->flavor].minsize; @@ -688,7 +699,7 @@ void initOptions(int argc, char *argv[], SYSOptions *opts) /* unless we are only setting boot sector, verify kernel file exists */ - if (opts->copyFiles) + if (opts->copyKernel) { /* check kernel (primary file) 1st */ sprintf(srcFile, "%s%s", opts->srcDrive, (opts->fnKernel)?opts->fnKernel:opts->kernel.kernel); @@ -720,7 +731,11 @@ void initOptions(int argc, char *argv[], SYSOptions *opts) exit(1); } } + } + /* if updating or only setting bootsector then skip this check */ + if (opts->copyShell) + { /* lastly check for command interpreter */ sprintf(srcFile, "%s%s", opts->srcDrive, (opts->fnCmd)?opts->fnCmd:"COMMAND.COM"); if (stat(srcFile, &fstatbuf)) /* if !exists() */ @@ -754,7 +769,7 @@ int main(int argc, char **argv) printf("Processing boot sector...\n"); put_boot(&opts); - if (opts.copyFiles) + if (opts.copyKernel) { printf("Now copying system files...\n"); @@ -774,7 +789,12 @@ int main(int argc, char **argv) exit(1); } /* copy secondary file (DOS) */ } + } + if (opts.copyShell) + { + printf("Copying shell (command interpreter)...\n"); + /* copy command.com, 1st try source path, then try %COMSPEC% */ sprintf(srcFile, "%s%s", opts.srcDrive, (opts.fnCmd)?opts.fnCmd:"COMMAND.COM"); if (!copy(srcFile, opts.dstDrive, "COMMAND.COM")) @@ -1337,6 +1357,7 @@ void put_boot(SYSOptions *opts) if (fs == FAT32) { bs32 = (struct bootsectortype32 *)&newboot; + if (!bs32->bsBackupBoot) bs32->bsBackupBoot = 0x6; /* ensure set, 6 is MS defined bs size */ bs32->bsDriveNumber = opts->defBootDrive; /* the location of the "0060" segment portion of the far pointer @@ -1350,7 +1371,7 @@ void put_boot(SYSOptions *opts) */ if (opts->kernel.stdbs) { - ((int *)newboot)[0x78/sizeof(int)] = opts->kernel.loadseg; + ((int *)newboot)[0x78/sizeof(int)] = opts->kernel.loadaddr; bsBiosMovOff = 0x82; } else /* compatible bs */ @@ -1374,23 +1395,34 @@ void put_boot(SYSOptions *opts) /* the location of the "0060" segment portion of the far pointer in the boot sector is just before cont: in boot*.asm. This happens to be offset 0x78 for FAT32 and offset 0x5c for FAT16 + The oem boot sectors do not have/need this value for patching. + + the location of the jmp address (patching from + EA00007000 [jmp 0x0070:0000] to EA00207000 [jmp 0x0070:0200]) + 0x11b: for fat12 oem boot sector + 0x118: for fat16 oem boot sector + The standard boot sectors do not have/need this value patched. force use of value stored in bs by NOPping out mov [drive], dl 0x66: 88h,56h,24h for fat16 and fat12 boot sectors 0x4F: 88h,56h,24h for oem compatible fat16 and fat12 boot sectors - + i.e. BE CAREFUL WHEN YOU CHANGE THE BOOT SECTORS !!! */ if (opts->kernel.stdbs) { - ((int *)newboot)[0x5c/sizeof(int)] = opts->kernel.loadseg; + /* this sets the segment we load the kernel to, default is 0x60:0 */ + ((int *)newboot)[0x5c/sizeof(int)] = opts->kernel.loadaddr; bsBiosMovOff = 0x66; } else { - /* load segment hard coded to 0x70 in oem compatible boot sector */ - if (opts->kernel.loadseg != 0x70) - printf("%s: Warning! ignoring load segment, compat bs always uses 0x70!\n", pgm); + /* load segment hard coded to 0x70 in oem compatible boot sector, */ + /* this however changes the offset jumped to default 0x70:0 */ + if (fs == FAT12) + ((int *)newboot)[0x11c/sizeof(int)] = opts->kernel.loadaddr; + else + ((int *)newboot)[0x119/sizeof(int)] = opts->kernel.loadaddr; bsBiosMovOff = 0x4F; } } @@ -1443,7 +1475,10 @@ void put_boot(SYSOptions *opts) #ifdef DEBUG /* there's a zero past the kernel name in all boot sectors */ printf("Boot sector kernel name set to %s\n", &newboot[0x1f1]); - printf("Boot sector load segment set to %Xh\n", opts->kernel.loadseg); + if (opts->kernel.stdbs) + printf("Boot sector kernel load segment set to %X:0h\n", opts->kernel.loadaddr); + else + printf("Boot sector kernel jmp address set to 70:%Xh\n", opts->kernel.loadaddr); #endif #ifdef DDEBUG @@ -1463,6 +1498,25 @@ void put_boot(SYSOptions *opts) printf("Can't write new boot sector to drive %c:\n", opts->dstDrive + 'A'); exit(1); } + + /* for FAT32, we need to update the backup copy as well */ + /* Note: assuming sectors 1-5 & 7-11 (FSINFO+additional boot code) + are properly setup by prior format and need no modification + [technically freespace, etc. should be updated] + */ + if (fs == FAT32) + { + bs32 = (struct bootsectortype32 *)&newboot; +#ifdef DEBUG + printf("writing backup bootsector to sector %d\n", bs32->bsBackupBoot); +#endif + if (MyAbsReadWrite(opts->dstDrive, 1, bs32->bsBackupBoot, newboot, 1) != 0) + { + printf("Can't write backup boot sector to drive %c:\n", opts->dstDrive + 'A'); + exit(1); + } + } + } /* if write boot sector to boot record*/ if (opts->bsFile != NULL)