📄 boot.c
字号:
#if 1
#define PMODE_LOAD_ADR 0x00100000L /* 1 meg (for stand-alone loader) */
#else
#define PMODE_LOAD_ADR 0x00110000L /* 1 meg+64K (for DOS loader) */
#endif
/*****************************************************************************
DEFS.H
- in file_t, allocate 'name' dynamically, with malloc()
- in fsinfo_t, allocate 'info' dynamically, with malloc()
FAT.C
- in fat_find_root(), get root dir size (may not be possible)
EXT2.C
- finish ext2_find_file()
- finish ext2_read()
- finish ext2_mount()
VFS.C
- in open(), either convert path from relative to absolute
or handle relative pathnames
- in open(), maybe figure out mount point based on absolute path
so you don't need global variable _mount
- in open(), fix it so open() doesn't modify the path argument
- in open(), maybe remove superfluous components of path
various
- support LBA
- support partition type 0x0E (FAT16 with LBA)
*****************************************************************************/
#include <stdio.h>
/*////////////////////////////////////////////////////////////////////////////
DEFS.H - DEFINES
////////////////////////////////////////////////////////////////////////////*/
/* no debug messages */
#if 1
#define DEBUG(X) /* nothing */
#define DEBUG1(X) /* nothing */
/* some debug messages */
#elif 1
#define DEBUG(X) X
#define DEBUG1(X) /* nothing */
#else
/* many debug messages */
#define DEBUG(X) X
#define DEBUG1(X) X
#endif
#define HUGE huge
/* these assume sizeof(short)==2 and sizeof(long)==4 */
#define read_le16(X) *(unsigned short *)(X)
#define read_le32(X) *(unsigned long *)(X)
/* some functions return -1 when I don't know what else to return */
#define EINVAL 2 /* invalid function argument */
#define EIO 3 /* disk/device read/write error */
#define ERR_FILE_NAME 4 /* filename not supported by filesystem */
#define ERR_EOF 5 /* end of file */
#define ERR_FILE_SYSTEM 6 /* filesystem is invalid/corrupt */
#define ENOIMP 7 /* function not (yet) implemented */
#define EMFILE 8 /* too many open files */
#define EBADF 9 /* bad file handle */
#define ENOMEM 10 /* not enough memory */
#define ERR_FILE_FORMAT 11 /* invalid file format */
/* bytes per sector for disks */
#define BPS 512
#define SEEK_SET 0
#define SEEK_CUR 1
#define SEEK_END 2
#define O_RDONLY 0x0001
#define O_WRONLY 0x0002
#define O_RDWR 0x0004
/* "An inode is an [unique] integer associated with a file on the filesystem."
For FAT, we use the first cluster of the file as the inode */
typedef unsigned long inode_t;
typedef unsigned long sector_t;
typedef unsigned long pos_t;
typedef struct
{
unsigned char int13_dev;
unsigned short sects, heads, bytes_per_sector;
} dev_t;
typedef struct
{
pos_t pos;
struct _mount *mount;
inode_t inode;
unsigned long file_size;
unsigned is_dir : 1;
unsigned is_open : 1;
char name[16]; /* xxx - 16 is arbitrary...maybe use malloc()? */
} file_t;
#define DIR file_t
typedef struct
{
int (*read)(file_t *file, unsigned char HUGE *buf, unsigned len);
int (*find_root)(struct _mount *mount, file_t *dir);
int (*find_file)(file_t *file, char *name);
/* void *info; */
unsigned char info[64]; /* xxx - use malloc()? */
} fsinfo_t;
typedef struct _mount
{
dev_t *dev;
fsinfo_t fsinfo;
sector_t partition_start;
inode_t curr_dir;
} mount_t;
#define MAX_SECT 4
typedef struct
{
unsigned load : 1; /* section flags: load from disk? */
unsigned zero : 1; /* BSS? */
unsigned read : 1; /* readable? */
unsigned write : 1; /* writable? */
unsigned exec : 1; /* executable? */
unsigned long off, size, adr; /* file offset, size, virtual adr */
char name[12]; /* section name (e.g. ".bss") */
} sect_t;
typedef struct
{
unsigned long entry_pt; /* initial EIP or CS:IP */
unsigned short num_sections; /* sections (.text, .data, .bss) */
sect_t section[MAX_SECT];
const char *format_name; /* name of file format */
unsigned pmode : 1; /* 32-bit kernel? */
unsigned rdsk : 1; /* RDSK file? */
} exec_t;
/*////////////////////////////////////////////////////////////////////////////
CONSOLE.C - CONSOLE ROUTINES
EXPORTS:
void gotoxy(unsigned char x, unsigned char y);
void textattr(int a);
void cprintf(const char *fmt, ...);
void erase_screen(unsigned char x, unsigned char y,
unsigned char wd, unsigned char ht);
int getch(void);
////////////////////////////////////////////////////////////////////////////*/
#include <stdarg.h> /* va_list, va_start(), va_end() */
#include <string.h> /* strlen() */
#include <stdio.h> /* vsprintf() */
#include <dos.h> /* struct REGPACK, intr() */
static unsigned char _attrib = 0x07; /* white on black */
/*****************************************************************************
*****************************************************************************/
void gotoxy(unsigned char x, unsigned char y)
{
struct REGPACK regs;
regs.r_dx = y;
regs.r_dx <<= 8;
regs.r_dx |= x;
regs.r_bx = 0; /* BH=video page 0 */
regs.r_ax = 0x0200; /* AH=subfunction 2 (move csr) */
intr(0x10, ®s);
}
/*****************************************************************************
*****************************************************************************/
void textattr(int a)
{
_attrib = a;
}
/*****************************************************************************
*****************************************************************************/
void cprintf(const char *fmt, ...)
{
struct REGPACK regs;
char buf[200];
va_list args;
va_start(args, fmt);
vsprintf(buf, fmt, args);
va_end(args);
regs.r_bx = 0; /* BH=video page 0 */
regs.r_ax = 0x0300; /* AH=subfunction 3: get cursor pos to DH,DL */
intr(0x10, ®s);
regs.r_es = _DS;
regs.r_bp = (unsigned)buf;
regs.r_cx = strlen(buf);
regs.r_bx = _attrib; /* BH=video page 0, BL=attribute */
regs.r_ax = 0x1301; /* AH=subfunction 13h, AL=write mode 1 */
intr(0x10, ®s);
}
/*****************************************************************************
*****************************************************************************/
void erase_screen(unsigned char x, unsigned char y,
unsigned char wd, unsigned char ht)
{
struct REGPACK regs;
regs.r_ax = 0x0600; /* AH=subfunction 6 (scroll), AH=0 (erase) */
regs.r_bx = _attrib;
regs.r_bx <<= 8; /* BH=attribute */
regs.r_cx = y;
regs.r_cx <<= 8; /* CH=row */
regs.r_cx |= x; /* CL=col */
regs.r_dx = (y + ht - 1);
regs.r_dx <<= 8; /* DH=height */
regs.r_dx |= (x + wd - 1);/* DL=width */
intr(0x10, ®s);
}
/*****************************************************************************
*****************************************************************************/
int getch(void)
{
static short prev = -1;
struct REGPACK regs;
int ret_val;
if(prev != -1)
{
ret_val = prev;
prev = -1;
}
else
{
regs.r_ax = 0; /* AH=subfunction 0 (get key) */
intr(0x16, ®s);
ret_val = regs.r_ax & 0xFF;
if(ret_val == 0)
{
regs.r_ax >>= 8;
prev = regs.r_ax;
}
}
return ret_val;
}
/*////////////////////////////////////////////////////////////////////////////
CACHE.C - SIMPLE READ-ONLY DISK CACHE
EXPORTS:
int read_sector(dev_t *dev, sector_t sector, unsigned char **blk);
////////////////////////////////////////////////////////////////////////////*/
#include <bios.h> /* biosdisk() */
/*#include "defs.h"*/
#define MAX_CACHE 32 /* 32 sectors == 16K */
/*****************************************************************************
*****************************************************************************/
int read_sector(dev_t *dev, sector_t sector, unsigned char **blk)
{
/* this bug was hard to find...
static unsigned char cached_blk[BPS][MAX_CACHE]; */
static unsigned char cached_blk[MAX_CACHE][BPS];
static sector_t cached_sector[MAX_CACHE];
static unsigned char init, evict;
/**/
unsigned short c, h, s, temp;
unsigned char tries;
if(!init)
{
init = 1;
for(temp = 0; temp < MAX_CACHE; temp++)
cached_sector[temp] = -1uL;
}
/* see if this sector is cached */
for(temp = 0; temp < MAX_CACHE; temp++)
{
if(cached_sector[temp] == sector)
{
(*blk) = cached_blk[temp];
return 0;
}
}
/* not cached, find a free buffer for it */
for(temp = 0; temp < MAX_CACHE; temp++)
{
if(cached_sector[temp] == -1uL)
break;
}
/* no free buffer, kick out someone else */
if(temp >= MAX_CACHE)
{
temp = evict;
evict++;
if(evict >= MAX_CACHE)
evict = 0;
}
/* load it */
cached_sector[temp] = sector;
(*blk) = cached_blk[temp];
/* we can load sector 0 of the disk even if we don't
know the disk geometry. This is good, because we can:
- get floppy geometry from FAT bootsector (in sector 0 of floppy)
- get hard disk geometry from partition table (in sector 0 of hard disk) */
if(sector == 0)
{
s = 1;
h = 0;
c = 0;
}
else
{
s = sector % dev->sects + 1;
h = (sector / dev->sects) % dev->heads;
c = (sector / dev->sects) / dev->heads;
}
/* make 3 attempts */
for(tries = 3; tries != 0; tries--)
{
temp = biosdisk(/* _DISK_READ */2, dev->int13_dev,
h, c, s, 1, *blk);
/* biosdisk() does not return what the Turbo C online help says.
It returns the AH value from INT 13h, not AX
temp >>= 8; */
if(temp == 0 || temp == 0x11)
return 0;
/* reset FDC if error */
(void)biosdisk(/* _DISK_RESET */0, dev->int13_dev,
0, 0, 0, 0, 0);
}
cprintf("\n\rread_sector: INT 13h disk error 0x%02X, CHS=%u:%u:%u, "
"dev=0x%02X, *blk=%p\n\r", temp, c, h, s,
dev->int13_dev, *blk);
return -EIO;
}
/*///////////////////////////////////////////////////////////////////////////
FAT.C - FAT12/16 FILESYSTEM
EXPORTS:
int fat_mount(mount_t *mount, dev_t *dev, unsigned char part);
////////////////////////////////////////////////////////////////////////////*/
/* NULL, memset, memcmp, memcpy, _fmemcpy */
#include <string.h> /* strchr, strlen, strcpy, strupr, strchr */
#include <dos.h> /* MK_FP() */
/*#include "defs.h"*/
#define min(a,b) (((a) < (b)) ? (a) : (b))
/* bytes per FAT directory entry */
#define FAT_DIRENT_LEN 32
/* FAT entries 0 and 1 are reserved: */
#define MAGIC_FAT_CLUSTER 0
#define MAGIC_ROOT_CLUSTER 1
typedef enum
{
FAT12, FAT16, FAT32
} fat_type_t;
typedef struct
{
unsigned short max_cluster;
unsigned char sectors_per_cluster;
sector_t fat_start, root_start, data_start;
fat_type_t fat_type;
} fat_t;
/* IMPORTS:
from VFS.C */
int read(unsigned handle, void HUGE *buf, unsigned len);
extern file_t _files[];
/* from CACHE.C */
int read_sector(dev_t *dev, sector_t sector, unsigned char **blk);
/*****************************************************************************
extend name to 8 characters, extend extension to 3 characters
(both padded on the right with spaces), and capitalize them
e.g. "foo.i" -> "FOO I "
'dst' must be >=12 bytes
*****************************************************************************/
static int fat_convert_name_to_fat(char *dst, char *src)
{
unsigned len;
char *dot;
/* put dst in FAT format */
memset(dst, ' ', 11);
dot = strchr(src, '.');
/* there is an extension */
if(dot != NULL)
{
/* long filenames not supported */
len = dot - src;
if(len > 8)
return -ERR_FILE_NAME;
/* copy filename */
memcpy(dst, src, len);
/* long extension not supported */
len = strlen(dot) - 1;
if(len > 3)
return -ERR_FILE_NAME;
/* copy extension */
memcpy(dst + 8, dot + 1, len);
}
/* no extension */
else
{
/* long filenames not supported */
len = strlen(src);
if(len > 8)
return -ERR_FILE_NAME;
/* copy filename */
memcpy(dst, src, len);
}
/* make it upper case */
dst[11] = '\0';
strupr(dst);
DEBUG(cprintf("fat_convert_name_to_fat: `%s' -> `%s'\n\r",
src, dst);)
return 0;
}
/*****************************************************************************
e.g. "README TXT" -> "readme.txt"
'dst' must be >=12 bytes
*****************************************************************************/
static void fat_convert_name_from_fat(char *dst, char *src)
{
unsigned char i;
char *d = dst;
for(i = 0; i < 8; i++)
{
if(src[i] == ' ')
break;
*d = src[i];
d++;
}
if(src[8] != ' ')
{
*d = '.';
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -