diff --git a/boot/boot32.asm b/boot/boot32.asm new file mode 100644 index 0000000..8c4b249 --- /dev/null +++ b/boot/boot32.asm @@ -0,0 +1,362 @@ +; +--------+ +; | | +; | | +; |--------| 4000:0000 +; | | +; | FAT | +; | | +; |--------| 2000:0000 +; |BOOT SEC| +; |RELOCATE| +; |--------| 1FE0:0000 +; | | +; | | +; | | +; | | +; |--------| +; |BOOT SEC| +; |ORIGIN | 07C0:0000 +; |--------| +; | | +; | | +; | | +; |--------| +; |KERNEL | +; |LOADED | +; |--------| 0060:0000 +; | | +; +--------+ + +;%define MULTI_SEC_READ 1 + + +segment .text + +%define BASE 0x7c00 + + org BASE + +Entry: jmp short real_start + nop + +; bp is initialized to 7c00h +%define bsOemName bp+0x03 ; OEM label +%define bsBytesPerSec bp+0x0b ; bytes/sector +%define bsSecPerClust bp+0x0d ; sectors/allocation unit +%define bsResSectors bp+0x0e ; # reserved sectors +%define bsFATs bp+0x10 ; # of fats +%define bsRootDirEnts bp+0x11 ; # of root dir entries +%define bsSectors bp+0x13 ; # sectors total in image +%define bsMedia bp+0x15 ; media descrip: fd=2side9sec, etc... +%define sectPerFat bp+0x16 ; # sectors in a fat +%define sectPerTrack bp+0x18 ; # sectors/track +%define nHeads bp+0x1a ; # heads +%define nHidden bp+0x1c ; # hidden sectors +%define nSectorHuge bp+0x20 ; # sectors if > 65536 +%define xsectPerFat bp+0x24 ; Sectors/Fat +%define xrootClst bp+0x2c ; Starting cluster of root directory +%define drive bp+0x40 ; Drive number + +%define LOADSEG 0x0060 + +%define FATSEG 0x2000 + +%define fat_sector bp+0x48 ; last accessed sector of the FAT + dd 0 + + times 0x5a-$+$$ db 0 +%define fat_start bp+0x5a ; first FAT sector + dd 0 +%define data_start bp+0x5e ; first data sector + dd 0 +%define fat_secmask bp+0x62 ; number of clusters in a FAT sector - 1 + dw 0 +%define fat_secshift bp+0x64 ; fat_secmask+1 = 2^fat_secshift + dw 0 + +;----------------------------------------------------------------------- +; ENTRY +;----------------------------------------------------------------------- + +real_start: cld + sub ax, ax + mov ds, ax + mov bp, 0x7c00 + mov ss, ax ; initialize stack + lea sp, [bp-0x20] + int 0x13 ; reset drive + + mov ax, 0x1FE0 + mov es, ax + mov si, bp + mov di, bp + mov cx, 0x0100 + rep movsw ; move boot code to the 0x1FE0:0x0000 + push es + mov bx, cont + push bx + retf + +cont: mov ds, ax + mov ss, ax + mov [drive], dl ; BIOS passes drive number in DL + + call print + db "Loading FreeDOS...",13,10,0 + +; FINDFILE: Searches for the file in the root directory. +; +; Returns: +; DX:AX = first cluster of file + + mov word [fat_sector], cx ; CX is 0 after movsw + mov word [fat_sector + 2], cx + + mov ax, word [xrootClst] + mov dx, word [xrootClst + 2] +ff_next_cluster: + push dx ; save cluster + push ax + call convert_cluster + jc boot_error ; EOC encountered + +ff_next_sector: + push bx ; save sector count + + mov bx, LOADSEG + mov es, bx + sub bx, bx + call readDisk + push dx ; save sector + push ax + + mov ax, [bsBytesPerSec] + + ; Search for KERNEL.SYS file name, and find start cluster. +ff_next_entry: mov cx, 11 + mov si, filename + mov di, ax + sub di, 0x20 + repe cmpsb + jz ff_done + + sub ax, 0x20 + jnz ff_next_entry + pop ax ; restore sector + pop dx + pop bx ; restore sector count + dec bx + jnz ff_next_sector +ff_find_next_cluster: + pop ax ; restore current cluster + pop dx + call next_cluster + jmp ff_next_cluster +ff_done: + + mov ax, [es:di+0x1A-11] ; get cluster number + mov dx, [es:di+0x14-11] +c4: + sub bx, bx ; ES points to LOADSEG +c5: push dx + push ax + push bx + call convert_cluster + jc boot_success + mov di, bx + pop bx +c6: + call readDisk + dec di + jnz c6 + pop ax + pop dx + call next_cluster + jmp c5 + + +boot_error: call print + db 13,10,"BOOT error!",13,10,0 + + xor ah,ah + int 0x16 ; wait for a key + int 0x19 ; reboot the machine + +; input: +; DX:AX - cluster +; output: +; DX:AX - next cluster +; CX = 0 +; modify: +; DI +next_cluster: + push es + mov di, ax + and di, [fat_secmask] + + mov cx, [fat_secshift] +cn_loop: + shr dx,1 + rcr ax,1 + dec cx + jnz cn_loop ; DX:AX fat sector where our + ; cluster resides + ; DI - cluster index in this + ; sector + + shl di,1 ; DI - offset in the sector + shl di,1 + add ax, [fat_start] + adc dx, [fat_start+2] ; DX:AX absolute fat sector + + push bx + mov bx, FATSEG + mov es, bx + sub bx, bx + + cmp ax, [fat_sector] + jne cn1 ; if the last fat sector we + ; read was this, than skip + cmp dx,[fat_sector+2] + je cn_exit +cn1: + mov [fat_sector],ax ; save the fat sector number, + mov [fat_sector+2],dx ; we are going to read + call readDisk +cn_exit: + pop bx + mov ax, [es:di] ; DX:AX - next cluster + mov dx, [es:di + 2] ; + pop es + ret + + +boot_success: + mov bl, [drive] + jmp word LOADSEG:0 + +; Convert cluster to the absolute sector +;input: +; DX:AX - target cluster +;output: +; DX:AX - absoulute sector +; BX - [bsSectPerClust] +;modify: +; CX +convert_cluster: + cmp dx,0x0fff + jne c3 + cmp ax,0xfff8 + jb c3 ; if cluster is EOC (carry is set), do ret + stc + ret +c3: + mov cx, dx ; sector = (cluster - 2)*clussize + + ; + data_start + sub ax, 2 + sbb cx, byte 0 ; CX:AX == cluster - 2 + mov bl, [bsSecPerClust] + sub bh, bh + xchg cx, ax ; AX:CX == cluster - 2 + mul bx ; first handle high word + ; DX must be 0 here + xchg ax, cx ; then low word + mul bx + add dx, cx ; DX:AX target sector + add ax, [data_start] + adc dx, [data_start + 2] + ret + +; prints text after call to this function. + +print: pop si ; this is the first character + xor bx, bx ; video page 0 + mov ah, 0x0E ; else print it +print1: lodsb ; get token + cmp al, bl ; end of string? (al == bl == 0) + je print2 ; if so, exit + int 0x10 ; via TTY mode + jmp short print1 ; until done +print2: push si ; stack up return address + ret ; and jump to it + + +;input: +; DX:AX - 32-bit DOS sector number +; ES:BX - destination buffer +;output: +; ES:BX points one byte after the last byte read. +; DX:AX - next sector +;modify: +; ES if DI * bsBytesPerSec >= 65536, CX + +readDisk: +read_next: push dx + push ax + ; + ; translate sector number to BIOS parameters + ; + + ; + ; abs = sector offset in track + ; + head * sectPerTrack offset in cylinder + ; + track * sectPerTrack * nHeads offset in platter + ; + ; t1 = abs / sectPerTrack (ax has t1) + ; sector = abs mod sectPerTrack (cx has sector) + ; + div word [sectPerTrack] + mov cx, dx + + ; + ; t1 = head + track * nHeads + ; + ; track = t1 / nHeads (ax has track) + ; head = t1 mod nHeads (dl has head) + ; + xor dx, dx + div word [nHeads] + + ; the following manipulations are necessary in order to + ; properly place parameters into registers. + ; ch = cylinder number low 8 bits + ; cl = 7-6: cylinder high two bits + ; 5-0: sector + mov dh, dl ; save head into dh for bios + ror ah, 1 ; move track high bits into + ror ah, 1 ; bits 7-6 (assumes top = 0) + xchg al, ah ; swap for later + mov dl, byte [sectPerTrack] + sub dl, cl + inc cl ; sector offset from 1 + or cx, ax ; merge cylinder into sector + + mov ax, 0x0201 + mov dl, [drive] + int 0x13 + + pop ax + pop dx + jnc read_ok ; jump if no error + xor ah, ah ; else, reset floppy + int 0x13 + jmp read_next +read_ok: + add bx, word [bsBytesPerSec] + + jnc no_incr_es ; if overflow... + + mov cx, es + add ch, 0x10 ; ...add 1000h to ES + mov es, cx + +no_incr_es: + add ax,byte 1 + adc dx,byte 0 + ret + +filename db "KERNEL SYS" + + times 0x01fe-$+$$ db 0 + +sign dw 0xAA55 diff --git a/docs/lfnapi.txt b/docs/lfnapi.txt new file mode 100644 index 0000000..8270b52 --- /dev/null +++ b/docs/lfnapi.txt @@ -0,0 +1,24 @@ + FreeDOS LFN aid API. + + +struct lfn_inode +{ + UNICODE name[255]; + + struct dirent l_dir; /* this file's dir entry image */ + + ULONG l_diroff; /* offset of the dir entry */ + CLUSTER l_dirstart; /* the starting cluster of dir */ + /* when dir is not root */ +}; + +typedef struct lfn_inode FAR * lfn_inode_ptr; + +COUNT lfn_allocate_inode(); +COUNT lfn_free_inode(COUNT handle); + +COUNT lfn_create_entries(COUNT handle, lfn_inode_ptr lip); +COUNT lfn_remove_entries(COUNT handle, lfn_inode_ptr lip); + +COUNT lfn_dir_read(COUNT handle, lfn_inode_ptr lip); +COUNT lfn_dir_write(COUNT handle, lfn_inode_ptr lip); diff --git a/hdr/xstructs.h b/hdr/xstructs.h new file mode 100644 index 0000000..4b0d631 --- /dev/null +++ b/hdr/xstructs.h @@ -0,0 +1,84 @@ +/****************************************************************/ +/* */ +/* xstructs.h */ +/* */ +/* Extended DOS 7.0+ structures */ +/* */ +/****************************************************************/ + +#ifdef MAIN +#ifdef VERSION_STRINGS +static BYTE *XStructs_hRcsId = "$Id$"; +#endif +#endif + +struct xdpbdata +{ + UWORD xdd_dpbsize; + struct dpb xdd_dpb; +}; + +struct xfreespace +{ + UWORD xfs_datasize; /* size of this structure */ + union { + UWORD requested; /* requested structure version */ + UWORD actual; /* actual structure version */ + } xfs_version; + ULONG xfs_clussize; /* number of sectors per cluster */ + ULONG xfs_secsize; /* number of bytes per sector */ + ULONG xfs_freeclusters; /* number of available clusters */ + ULONG xfs_totalclusters; /* total number of clusters on the drive */ + ULONG xfs_freesectors; /* number of physical sectors available */ + ULONG xfs_totalsectors; /* total number of physical sectors */ + ULONG xfs_freeunits; /* number of available allocation units */ + ULONG xfs_totalunits; /* total allocation units */ + UBYTE xfs_reserved[8]; +}; + +struct xdpbforformat +{ + UWORD xdff_datasize; /* size of this structure */ + union { + UWORD requested; /* requested structure version */ + UWORD actual; /* actual structure version */ + } xdff_version; + UDWORD xdff_function; /* function number: + 00h invalidate DPB counts + 01h rebuild DPB from BPB + 02h force media change + 03h get/set active FAT number and mirroring + 04h get/set root directory cluster number + */ + union { + struct { + DWORD nfreeclst; /* # free clusters + (-1 - unknown, 0 - don't change) */ + DWORD cluster; /* cluster # of first free + (-1 - unknown, 0 - don't change) */ + UDWORD reserved[2]; + } setdpbcounts; + + struct { + UDWORD unknown; + bpb FAR *bpbp; + UDWORD reserved[2]; + } rebuilddpb; + + struct { + DWORD newmirroring; /* new active FAT/mirroring state, or -1 to get + bits 3-0: the 0-based FAT number of the active FAT + bits 6-4: reserved (0) + bit 7: do not mirror active FAT to inactive FATs + */ + DWORD oldmirroring; /* previous active FAT/mirroring state (as above) */ + UDWORD reserved[2]; + } setmirroring; + + struct { + DWORD newrootclst; /* set new root directory cluster, -1 - get current */ + DWORD oldrootclst; /* get previous root directory cluster */ + UDWORD reserved[2]; + } setroot; + } xdff_f; +}; diff --git a/kernel/dosfns.c b/kernel/dosfns.c index ab068e8..5de3873 100644 --- a/kernel/dosfns.c +++ b/kernel/dosfns.c @@ -37,6 +37,9 @@ static BYTE *dosfnsRcsId = "$Id$"; * /// Added SHARE support. 2000/09/04 Ron Cemer * * $Log$ + * Revision 1.27 2001/09/24 02:21:14 bartoldeman + * SYS and printer fixes + * * Revision 1.26 2001/09/23 20:39:44 bartoldeman * FAT32 support, misc fixes, INT2F/AH=12 support, drive B: handling * @@ -551,16 +554,15 @@ UCOUNT DosWrite(COUNT hndl, UCOUNT n, BYTE FAR * bp, COUNT FAR * err) } else { - REG WORD /*c,*/ - cnt = n, - xfer = 0; + REG WORD xfer; - while(cnt-- != 0 && *bp != CTL_Z){ + for(xfer = 0; xfer < n && *bp != CTL_Z; bp++, xfer++) + { if (s->sft_flags & SFT_FCONOUT) { cso(*bp); } - else + else FOREVER { rq.r_length = sizeof(request); rq.r_command = C_OUTPUT; @@ -568,11 +570,24 @@ UCOUNT DosWrite(COUNT hndl, UCOUNT n, BYTE FAR * bp, COUNT FAR * err) rq.r_trans = bp; rq.r_status = 0; execrh((request FAR *) & rq, s->sft_dev); - if (rq.r_status & S_ERROR) - char_error(&rq, s->sft_dev); + if (!(rq.r_status & S_ERROR)) + break; + charloop: + switch(char_error(&rq, s->sft_dev)) + { + case ABORT: + case FAIL: + *err = DE_INVLDACC; + return xfer; + case CONTINUE: + break; + case RETRY: + continue; + default: + goto charloop; + } + break; } - ++bp; - ++xfer; if (control_break()) { handle_break(); diff --git a/kernel/init-dat.h b/kernel/init-dat.h new file mode 100644 index 0000000..ea6e79d --- /dev/null +++ b/kernel/init-dat.h @@ -0,0 +1,31 @@ +/* Included by initialisation functions */ + +#if _MSC_VER != 0 + extern __segment DosDataSeg;/* serves for all references to the DOS DATA segment + necessary for MSC+our funny linking model + */ + + extern __segment DosTextSeg; + + #define DOSFAR __based(DosDataSeg) + #define DOSTEXTFAR __based(DosTextSeg) + +#elif defined(__TURBOC__) + + #define DOSFAR FAR + #define DOSTEXTFAR FAR + +#elif defined(__WATCOMC__) + + #define DOSFAR FAR + #define DOSTEXTFAR FAR + +#else + #pragma error("unknown compiler - please adjust") + this should simply not compile !! +#endif + + + +extern BYTE DOSFAR version_flags; /* minor version number */ + diff --git a/kernel/lfnapi.c b/kernel/lfnapi.c new file mode 100644 index 0000000..71211ee --- /dev/null +++ b/kernel/lfnapi.c @@ -0,0 +1,147 @@ +/****************************************************************/ +/* */ +/* lfnapi.c */ +/* */ +/* Directory access functions for LFN aid API */ +/* Module is under construction! */ +/****************************************************************/ + +#include "portab.h" +#include "globals.h" + +#ifdef VERSION_STRINGS +static BYTE *lfnaidRcsId = "$Id$"; +#endif + +#if 0 +#define E_INVLDHNDL -1 +#define E_NOFREEHNDL -2 +#define E_IOERROR -3 +#define E_INVLDDRV -4 + +COUNT lfn_allocate_inode() +{ + f_node_ptr fnp = get_f_node(); + struct cds FAR *cdsp; + if (fnp == 0) return E_NOFREEHNDL; + + cdsp = &CDSp->cds_table[default_drive]; + + if (cdsp->cdsDpb == 0) + { + release_f_node(fnp); + return E_INVLDDRV; + } + + fnp->f_dpb = cdsp->cdsDpb; + + if (media_check(fnp->f_dpb) < 0) + { + release_f_node(fnp); + return E_INVLDDRV; + } + + fnp->f_dsize = DIRENT_SIZE * fnp->f_dpb->dpb_dirents; + + return xlt_fnp(fnp); +} + +COUNT lfn_free_inode(COUNT handle) +{ + f_node_ptr fnp = xlt_fd(handle); + if (fnp == 0 || fnp->f_count <= 0) return E_INVLHNDL; + + release_f_node(fnp); +} + +COUNT lfn_to_unicode_chunk(UNICODE FAR **nptr, UNICODE FAR **uptr, + UCOUNT *index, COUNT count) +{ + COUNT j; + + for (j = 0; j < count; j++, *uptr++, *index++, *nptr++) + { + **nptr = **uptr; + if (**uptr == 0) return 0; + } + + return 1; +} + +COUNT lfn_to_unicode(UNICODE FAR *name, UBYTE FAR *lfn_entry, UCOUNT *index) +{ + COUNT j; + UNICODE FAR *uptr; + UNICODE FAR *nptr = name; + + uptr = (UNICODE FAR *)&lfn_entry[1]; + if (!lfn_to_unicode_chunk(&nptr, &uptr, index, 5)) return 0; + uptr = (UNICODE FAR *)&lfn_entry[0xe]; + if (!lfn_to_unicode_chunk(&nptr, &uptr, index, 6)) return 0; + uptr = (UNICODE FAR *)&lfn_entry[0x1c]; + if (!lfn_to_unicode_chunk(&nptr, &uptr, index, 2)) return 0; + + return 1; +} + +COUNT lfn_dir_read(COUNT handle, lfn_inode_ptr lip) +{ + COUNT index = 0; /* index of the first non-filled char in the long file + name string */ + ULONG original_diroff; + f_node_ptr fnp = xlt_fd(handle); + if (fnp == 0 || fnp->f_count <= 0) return E_INVLHNDL; + + if (lfnp->l_dirstart == 0) + { + } + + original_diroff = fnp->f_diroff; + + lip->name[0] = 0; + + while (TRUE) + { + if (dir_read(fnp) != DIRENT_SIZE) return E_IOERROR; + if (fnp->f_dir.dir_name[0] != DELETED && fnp->f_dir.dir_name[0] != 0 + && fnp->f_dir.dir_attrib != D_LFN) + { + fmemcpy(lip->l_dir, fnp->f_dir, sizeof(struct dirent)); + lip->l_diroff = fnp->f_diroff; + lip->l_dirstart = fnp->f_dirstart; + break; + } + } + fnp->f_diroff = original_diroff - DIRENT_SIZE; + + while (TRUE) + { + if (fnp->f_diroff == 0) break; + fnp->f_diroff -= 2*DIRENT_SIZE; + if (dir_read(fnp) != DIRENT_SIZE) return E_IOERROR; + if (fnp->f_dir.dir_name[0] == '\0' + || fnp->f_dir.dir_name[0] == DELETED) break; + if (!lfn_to_unicode(lip->name, + (UBYTE FAR *)fnp->f_dir, index)) break; + } + + if (lip->name[0] == 0) + { + ConvertName83ToNameSZ(lip->name, lip->l_dir.dir_name); + } + + return SUCCESS; +} + +/* Calculate checksum for the 8.3 name */ +UBYTE lfn_checksum(char *name) +{ + UBYTE sum; + COUNT i; + + for (sum = 0, i = 11; --i >= 0; sum += *name++) + sum = (sum << 7) | (sum >> 1); + + return sum; +} +#endif diff --git a/kernel/printer.asm b/kernel/printer.asm index ee855ec..cbcf898 100644 --- a/kernel/printer.asm +++ b/kernel/printer.asm @@ -28,6 +28,9 @@ ; $Header$ ; ; $Log$ +; Revision 1.5 2001/09/24 02:21:14 bartoldeman +; SYS and printer fixes +; ; Revision 1.4 2001/09/23 20:39:44 bartoldeman ; FAT32 support, misc fixes, INT2F/AH=12 support, drive B: handling ; @@ -106,19 +109,29 @@ uPrtQuantum dw 50h PrtWrite: jcxz PrtWr3 ; Exit if nothing to write -PrtWr1: - mov bx,2 ; number of retries -PrtWr2: - call PrintSingleCharacter +PrtCharLoop: ; next character loop + + mov bx, 2 ; number of retries +PrtRetryTwice: + mov ah, PRT_GETSTATUS ; get status, ah=2 + call PrtIOCall ; + jnz PrtWr4 - jnz PrtWr4 ; Exit if done - loop PrtWr1 ; otherwise loop + mov al,[es:di] + + mov ah, PRT_WRITECHAR ; print character, ah=0 + call PrtIOCall ; (0800) + + jnz PrtWr4 ; NZ = error, retry + + inc di + loop PrtCharLoop ; next character PrtWr3: jmp _IOExit -PrtWr4: +PrtWr4: ; repeat dec bx - jnz PrtWr2 + jnz PrtRetryTwice PrtWr5: jmp _IOErrCnt @@ -141,18 +154,27 @@ GetPrtStat: PrtIOCall: call GetUnitNum - int 17h ; print char al, get status ah - test ah, PRT_TIMEOUT|PRT_IOERROR - jnz PrtIOCal2 - mov al, E_PAPER - test ah, PRT_OUTOFPAPER - jnz PrtIOCal1 - inc al ; al<-E_WRITE -PrtIOCal1: - retn -PrtIOCal2: + int 17h ; print char al, get status ah + + mov al, ah ; if (stat & 0x30) == 0x30 return 10; + and al, PRT_SELECTED|PRT_OUTOFPAPER + cmp al, PRT_SELECTED|PRT_OUTOFPAPER + mov al, E_WRITE + je ret_error_code + + test ah, PRT_OUTOFPAPER|PRT_IOERROR|PRT_TIMEOUT ; 29h mov al, E_NOTRDY - test ah, PRT_TIMEOUT + jz ret_error_code + + test ah, PRT_OUTOFPAPER ; 20h + mov al, E_WRITE + jz ret_error_code ; not out of paper -> E_WRITE + +ret_error_code_9: + mov al, E_PAPER + +ret_error_code: + cmp al, E_NOTRDY ; 2 = no error retn @@ -222,8 +244,11 @@ PrtGnIoctl3: ; -; original implementation didn't work at all. -; this one's not much better either, +; some comments to last changes (TE, 23/09/01) +; +; original implementation didn't print at all - on my machine,LPT2 +; +; maybe this one's not much better either, ; but should print a little bit ; ; the status bits = AH @@ -242,42 +267,7 @@ PrtGnIoctl3: ; 10 - printer with power, but not initialized ; 90 - this one is fine ; - - ; you must not simply print without asking for status ; as the BIOS has a LARGE timeout before aborting ; -PrintSingleCharacter: - - mov ah, PRT_GETSTATUS ; get status, ah=2 - call GetUnitNum - int 17h ; print char al, get status ah - - test ah, PRT_OUTOFPAPER|PRT_IOERROR - jnz decode_error - - test ah, PRT_NOTBUSY - jz decode_error - - - mov al,[es:di] - mov ah,PRT_WRITECHAR ; print character, ah=0 - call GetUnitNum - int 17h ; print char al, get status ah - - test ah, PRT_OUTOFPAPER|PRT_IOERROR|PRT_TIMEOUT - jnz decode_error - inc di - xor al,al ; set zero flag + clear al - ret - - -decode_error: - mov al, E_PAPER - test ah, PRT_OUTOFPAPER ;out_of_paper, 20h - jnz out_of_paper - mov al, E_WRITE -out_of_paper: - or al,al ; reset zero flag - ret