Initial (manual) import

This commit is contained in:
minexew committed 2017-01-22 20:26:44 +01:00
1 parent f39611c506
commit 895fe109de
661 files changed
+245862

No files matched your search

+611
View File
@@ -0,0 +1,611 @@
U0 ATABlkSel(CBlkDev *bd,I64 blk,I64 cnt)
{
if (bd->type!=BDT_ATAPI && bd->base1)
OutU8(bd->base1+ATAR1_CTRL,0x8);
if (bd->flags & BDF_EXT_SIZE) { //48 Bit LBA?
OutU8(bd->base0+ATAR0_NSECT,cnt.u8[1]);
OutU8(bd->base0+ATAR0_SECT,blk.u8[3]);
OutU8(bd->base0+ATAR0_LCYL,blk.u8[4]);
OutU8(bd->base0+ATAR0_HCYL,blk.u8[5]);
OutU8(bd->base0+ATAR0_NSECT,cnt);
OutU8(bd->base0+ATAR0_SECT,blk);
OutU8(bd->base0+ATAR0_LCYL,blk.u8[1]);
OutU8(bd->base0+ATAR0_HCYL,blk.u8[2]);
OutU8(bd->base0+ATAR0_SEL,0xEF|bd->unit<<4);
} else { //28 Bit LBA
OutU8(bd->base0+ATAR0_NSECT,cnt);
OutU8(bd->base0+ATAR0_SECT,blk);
OutU8(bd->base0+ATAR0_LCYL,blk.u8[1]);
OutU8(bd->base0+ATAR0_HCYL,blk.u8[2]);
OutU8(bd->base0+ATAR0_SEL,0xE0|bd->unit<<4|blk.u8[3]);
}
}
Bool ATAWaitNotBUSY(CBlkDev *bd,F64 timeout)
{
I64 i;
do {
for (i=0;i<3;i++)
if (!(InU8(bd->base0+ATAR0_STAT)&ATAS_BSY))
return TRUE;
Yield;
} while (!(0<timeout<tS));
return FALSE;
}
Bool ATAWaitDRQ(CBlkDev *bd,F64 timeout)
{
I64 i;
do {
for (i=0;i<3;i++)
if (InU8(bd->base0+ATAR0_STAT)&ATAS_DRQ)
return TRUE;
Yield;
} while (!(0<timeout<tS));
return FALSE;
}
Bool ATANop(CBlkDev *bd,F64 timeout)
{
if (bd->flags & BDF_EXT_SIZE)
OutU8(bd->base0+ATAR0_SEL,0xEF|bd->unit<<4);
else
OutU8(bd->base0+ATAR0_SEL,0xE0|bd->unit<<4);
OutU8(bd->base0+ATAR0_FEAT,0);
OutU8(bd->base0+ATAR0_CMD,ATA_NOP);
return ATAWaitNotBUSY(bd,timeout);
}
U0 ATACmd(CBlkDev *bd,U8 cmd)
{
OutU8(bd->base0+ATAR0_FEAT,0);
OutU8(bd->base0+ATAR0_CMD,cmd);
bd->last_time=tS;
PortNop;
}
Bool ATAGetRes(CBlkDev *bd,F64 timeout,U8 *buf,I64 cnt,
I64 _avail,Bool one_read)
{
I64 avail,overflow;
bd->flags&=~BDF_LAST_WAS_WRITE;
MemSet(buf,0,cnt);
while (cnt>0) {
if (!ATAWaitDRQ(bd,timeout))
return FALSE;
if (_avail)
avail=_avail;
else
avail=InU8(bd->base0+ATAR0_HCYL)<<8+InU8(bd->base0+ATAR0_LCYL);
if (avail) {
if (avail>cnt) {
overflow=avail-cnt;
avail=cnt;
} else
overflow=0;
if (avail&2)
RepInU16(buf,avail>>1,bd->base0+ATAR0_DATA);
else
RepInU32(buf,avail>>2,bd->base0+ATAR0_DATA);
cnt-=avail;
buf+=avail;
while (overflow>0) {
InU16(bd->base0+ATAR0_DATA);
overflow-=2;
if (0<timeout<tS)
return FALSE;
}
if (one_read)
break;
} else
Yield;
}
return ATAWaitNotBUSY(bd,timeout);
}
Bool ATAPIWritePktWord(CBlkDev *bd,F64 timeout,...)
{
I64 i;
for (i=0;i<argc;i++) {
if (!ATAWaitDRQ(bd,timeout))
return FALSE;
OutU16(bd->base0+ATAR0_DATA,EndianU16(argv[i]));
bd->last_time=tS;
}
return TRUE;
}
Bool ATAPISetMaxSpeed(CBlkDev *bd)
{
if (bd->flags & BDF_EXT_SIZE)
OutU8(bd->base0+ATAR0_SEL,0xEF|bd->unit<<4);
else
OutU8(bd->base0+ATAR0_SEL,0xE0|bd->unit<<4);
OutU8(bd->base0+ATAR0_LCYL,0);
OutU8(bd->base0+ATAR0_HCYL,0);
ATACmd(bd,ATA_PACKET);
ATAPIWritePktWord(bd,0,0xBB00,0xFFFF,0xFFFF,0,0,0);
return ATAWaitNotBUSY(bd,0);
}
Bool ATAPISeek(CBlkDev *bd,I64 native_blk)
{
if (bd->flags & BDF_EXT_SIZE)
OutU8(bd->base0+ATAR0_SEL,0xEF|bd->unit<<4);
else
OutU8(bd->base0+ATAR0_SEL,0xE0|bd->unit<<4);
OutU8(bd->base0+ATAR0_LCYL,0);
OutU8(bd->base0+ATAR0_HCYL,0);
ATACmd(bd,ATA_PACKET);
ATAPIWritePktWord(bd,0,0x2B00,native_blk>>16,native_blk,0,0,0);
return ATAWaitNotBUSY(bd,0);
}
Bool ATAPIStartStop(CBlkDev *bd,F64 timeout,Bool start)
{
I64 i;
if (start)
i=0x100;
else
i=0;
if (bd->flags & BDF_EXT_SIZE)
OutU8(bd->base0+ATAR0_SEL,0xEF|bd->unit<<4);
else
OutU8(bd->base0+ATAR0_SEL,0xE0|bd->unit<<4);
ATACmd(bd,ATA_PACKET);
//Start/Stop
if (ATAPIWritePktWord(bd,timeout,0x1B00,0,i,0,0,0))
return ATAWaitNotBUSY(bd,timeout);
else
return FALSE;
}
I64 ATAGetDevId(CBlkDev *bd,F64 timeout,Bool keep_id_record)
{
I64 res=BDT_NULL;
U16 *id_record=NULL;
if (bd->type!=BDT_ATAPI && bd->base1)
OutU8(bd->base1+ATAR1_CTRL,0x8);
if (bd->flags & BDF_EXT_SIZE)
OutU8(bd->base0+ATAR0_SEL,0xEF|bd->unit<<4);
else
OutU8(bd->base0+ATAR0_SEL,0xE0|bd->unit<<4);
ATACmd(bd,ATA_ID_DEV);
if (ATAWaitNotBUSY(bd,timeout)) {
if (InU8(bd->base0+ATAR0_STAT)&ATAS_ERR)
res=BDT_ATAPI;
else {
id_record=ACAlloc(512);
if (ATAGetRes(bd,timeout,id_record,512,512,FALSE))
res=BDT_ATA;
else {
Free(id_record);
id_record=NULL;
}
}
}
if (keep_id_record) {
Free(bd->dev_id_record);
bd->dev_id_record=id_record;
}
return res;
}
I64 ATAReadNativeMax(CBlkDev *bd,F64 timeout)
{//Returns zero on err
I64 res=0;
Bool okay=TRUE;
if (bd->type==BDT_ATAPI) {
if (bd->flags & BDF_EXT_SIZE)
OutU8(bd->base0+ATAR0_SEL,0xEF|bd->unit<<4);
else
OutU8(bd->base0+ATAR0_SEL,0xE0|bd->unit<<4);
ATACmd(bd,ATA_DEV_RST);
if (!ATAWaitNotBUSY(bd,0))
okay=FALSE;
} else {
while (InU8(bd->base0+ATAR0_STAT) & ATAS_BSY) {
if (bd->flags&BDF_LAST_WAS_WRITE)
OutU16(bd->base0+ATAR0_DATA,0);
else
InU16(bd->base0+ATAR0_DATA);
Yield;
if (0<timeout<tS)
return FALSE;
}
if (ATAGetDevId(bd,timeout,TRUE)==BDT_NULL)
okay=FALSE;
else
BEqu(&bd->flags,BDf_EXT_SIZE,Bt(&bd->dev_id_record[86],10));
}
if (okay) {
if (bd->flags & BDF_EXT_SIZE && bd->base1) {
OutU8(bd->base1+ATAR1_CTRL,0x8);
OutU8(bd->base0+ATAR0_SEL,0xEF|bd->unit<<4);
ATACmd(bd,ATA_READ_NATIVE_MAX_EXT);
if (ATAWaitNotBUSY(bd,timeout)) {
res.u8[0]=InU8(bd->base0+ATAR0_SECT);
res.u8[1]=InU8(bd->base0+ATAR0_LCYL);
res.u8[2]=InU8(bd->base0+ATAR0_HCYL);
OutU8(bd->base1+ATAR1_CTRL,0x80);
res.u8[3]=InU8(bd->base0+ATAR0_SECT);
res.u8[4]=InU8(bd->base0+ATAR0_LCYL);
res.u8[5]=InU8(bd->base0+ATAR0_HCYL);
if (res>>24==res&0xFFFFFF) {//Kludge to make QEMU work
bd->flags&=~BDF_EXT_SIZE;
res&=0xFFFFFF;
}
}
} else {
if (bd->type!=BDT_ATAPI && bd->base1)
OutU8(bd->base1+ATAR1_CTRL,0x8);
OutU8(bd->base0+ATAR0_SEL,0xE0|bd->unit<<4);
ATACmd(bd,ATA_READ_NATIVE_MAX);
if (ATAWaitNotBUSY(bd,timeout)) {
res.u8[0]=InU8(bd->base0+ATAR0_SECT);
res.u8[1]=InU8(bd->base0+ATAR0_LCYL);
res.u8[2]=InU8(bd->base0+ATAR0_HCYL);
res.u8[3]=InU8(bd->base0+ATAR0_SEL) & 0xF;
}
}
}
return bd->max_blk=res;
}
I64 ATAPIReadCapacity(CBlkDev *bd,I64 *_blk_size=NULL)
{//Supposedly this can return a res +/- 75 sects.
//Error might just be for music.
Bool unlock=BlkDevLock(bd);
U32 buf[2];
if (ATAWaitNotBUSY(bd,0)) {
if (bd->flags & BDF_EXT_SIZE)
OutU8(bd->base0+ATAR0_SEL,0xEF|bd->unit<<4);
else
OutU8(bd->base0+ATAR0_SEL,0xE0|bd->unit<<4);
OutU8(bd->base0+ATAR0_LCYL,8);
OutU8(bd->base0+ATAR0_HCYL,0);
ATACmd(bd,ATA_PACKET);
ATAPIWritePktWord(bd,0,0x2500,0,0,0,0,0);
if (!ATAGetRes(bd,0,buf,8,0,TRUE))
buf[0]=buf[1]=0;
} else
buf[0]=buf[1]=0;
if (unlock) BlkDevUnlock(bd);
if (_blk_size) *_blk_size=EndianU32(buf[1]);
return EndianU32(buf[0]);
}
CATAPITrack *ATAPIReadTrackInfo(CBlkDev *bd,I64 blk)
{
CATAPITrack *res=CAlloc(sizeof(CATAPITrack));
Bool unlock=BlkDevLock(bd);
if (ATAWaitNotBUSY(bd,0)) {
if (bd->flags & BDF_EXT_SIZE)
OutU8(bd->base0+ATAR0_SEL,0xEF|bd->unit<<4);
else
OutU8(bd->base0+ATAR0_SEL,0xE0|bd->unit<<4);
OutU8(bd->base0+ATAR0_LCYL,sizeof(CATAPITrack)&0xFF);
OutU8(bd->base0+ATAR0_HCYL,sizeof(CATAPITrack)>>8);
ATACmd(bd,ATA_PACKET);
ATAPIWritePktWord(bd,0,0x5200,blk.u16[1],blk.u16[0],
(sizeof(CATAPITrack)&0xFF00)>>8,(sizeof(CATAPITrack)&0x00FF)<<8,0);
if (!ATAGetRes(bd,0,res,sizeof(CATAPITrack),0,TRUE)) {
Free(res);
res=NULL;
}
} else {
Free(res);
res=NULL;
}
if (unlock) BlkDevUnlock(bd);
return res;
}
Bool ATAInit(CBlkDev *bd)
{
Bool unlock=BlkDevLock(bd),okay=FALSE;
if (bd->type==BDT_ATAPI)
bd->flags&=~BDF_EXT_SIZE;
else
bd->flags|=BDF_EXT_SIZE;
if (ATAReadNativeMax(bd,tS+0.1)) {
ATABlkSel(bd,bd->max_blk,0);
if (bd->flags&BDF_EXT_SIZE)
ATACmd(bd,ATA_SET_MAX_EXT);
else
ATACmd(bd,ATA_SET_MAX);
if (ATAWaitNotBUSY(bd,0)) {
okay=TRUE;
if (bd->type==BDT_ATAPI) {
if (ATAPIStartStop(bd,0,TRUE)) {
if(!ATAPISetMaxSpeed(bd))
okay=FALSE;
} else
okay=FALSE;
}
}
}
if (unlock) BlkDevUnlock(bd);
return okay;
}
Bool ATAPIWaitReady(CBlkDev *bd,F64 timeout)
{
do {
if (!ATAWaitNotBUSY(bd,timeout) ||
!ATANop(bd,timeout) ||
!ATAPIStartStop(bd,timeout,TRUE))
return FALSE;
if (InU8(bd->base0+ATAR0_STAT) & ATAS_DRDY &&
!InU8(bd->base0+ATAR0_FEAT));
return TRUE;
ATAInit(bd);
Yield;
} while (!(0<timeout<tS));
return FALSE;
}
U0 ATAReadBlks(CBlkDev *bd,U8 *buf, I64 blk, I64 cnt)
{
I64 retries=3;
Bool unlock=BlkDevLock(bd);
retry:
ATABlkSel(bd,blk,cnt);
if (bd->flags & BDF_EXT_SIZE)
ATACmd(bd,ATA_READ_MULTI_EXT);
else
ATACmd(bd,ATA_READ_MULTI);
if (!ATAGetRes(bd,tS+1.0,buf,cnt*bd->blk_size,BLK_SIZE,FALSE)) {
if (retries--) {
ATAWaitNotBUSY(bd,0);
goto retry;
} else
throw('BlkDev');
}
blkdev.read_cnt+=(cnt*bd->blk_size)>>BLK_SIZE_BITS;
if (unlock) BlkDevUnlock(bd);
}
I64 ATAProbe(I64 base0,I64 base1,I64 unit)
{
CBlkDev bd;
MemSet(&bd,0,sizeof(CBlkDev));
bd.type=BDT_ATAPI;
bd.base0=base0;
bd.base1=base1;
bd.unit=unit;
bd.blk_size=DVD_BLK_SIZE;
return ATAGetDevId(&bd,tS+0.1,FALSE);
}
Bool ATAPIReadBlks2(CBlkDev *bd,F64 timeout,U8 *buf,
I64 native_blk, I64 cnt,Bool lock)
{
Bool res=FALSE,unlock;
if (cnt<=0)
return FALSE;
if (lock)
unlock=BlkDevLock(bd);
if (ATAPIWaitReady(bd,timeout)) {
if (bd->flags & BDF_EXT_SIZE)
OutU8(bd->base0+ATAR0_SEL,0xEF|bd->unit<<4);
else
OutU8(bd->base0+ATAR0_SEL,0xE0|bd->unit<<4);
OutU8(bd->base0+ATAR0_LCYL,bd->blk_size);
OutU8(bd->base0+ATAR0_HCYL,bd->blk_size.u8[1]);
ATACmd(bd,ATA_PACKET);
if (ATAPIWritePktWord(bd,timeout,0xA800,
native_blk.u16[1],native_blk,cnt.u16[1],cnt,0) &&
ATAGetRes(bd,timeout,buf,cnt*bd->blk_size,0,FALSE)) {
blkdev.read_cnt+=(cnt*bd->blk_size)>>BLK_SIZE_BITS;
res=TRUE;
}
}
// ATAPIStartStop(bd,0,FALSE);
if (lock && unlock) BlkDevUnlock(bd);
return res;
}
U0 ATAPIReadBlks(CBlkDev *bd,U8 *buf, I64 blk, I64 cnt)
{
CDrv *dv=Let2Drv(bd->first_drv_let);
I64 retry,spc=bd->blk_size>>BLK_SIZE_BITS,n,blk2,
l2=bd->max_reads<<1+spc<<1;
U8 *dvd_buf=MAlloc(l2<<BLK_SIZE_BITS);
if (cnt>0) {
if (blk<=bd->max_reads)
blk2=0;
else
blk2=FloorU64(blk-bd->max_reads,spc);
if (blk2+l2>dv->size+dv->drv_offset)
l2=dv->size+dv->drv_offset-blk2;
n=(l2+spc-1)/spc;
retry=4;
while (--retry)
if (ATAPIReadBlks2(bd,tS+7.0+0.004*n,dvd_buf,blk2/spc,n,TRUE))
//n is 0x800 if max_reads. Up to 8 additional seconds
break;
if (!retry)
ATAPIReadBlks2(bd,0,dvd_buf,blk2/spc,n,TRUE);
if (bd->flags & BDF_READ_CACHE)
DskCacheAdd(dv,dvd_buf,blk2,n*spc);
MemCpy(buf,dvd_buf+(blk-blk2)<<BLK_SIZE_BITS,cnt<<BLK_SIZE_BITS);
}
Free(dvd_buf);
}
Bool ATARBlks(CDrv *dv,U8 *buf, I64 blk, I64 cnt)
{
I64 n;
CBlkDev *bd=dv->bd;
while (cnt>0) {
n=cnt;
if (n>bd->max_reads)
n=bd->max_reads;
if (bd->type==BDT_ATAPI)
ATAPIReadBlks(bd,buf,blk,n);
else
ATAReadBlks(bd,buf,blk,n);
buf+=n<<BLK_SIZE_BITS;
blk+=n;
cnt-=n;
}
return TRUE;
}
U0 ATAWriteBlks(CBlkDev *bd,U8 *buf, I64 blk, I64 cnt)
{//For low level disk access.
//Use WBlks() instead.
I64 i,U32s_avail,sects_avail,retries=3;
F64 timeout;
Bool unlock=BlkDevLock(bd);
retry:
ATABlkSel(bd,blk,cnt);
if (bd->flags&BDF_EXT_SIZE)
ATACmd(bd,ATA_WRITE_MULTI_EXT);
else
ATACmd(bd,ATA_WRITE_MULTI);
bd->flags|=BDF_LAST_WAS_WRITE;
while (cnt>0) {
timeout=tS+1.0;
while (TRUE) {
i=InU8(bd->base0+ATAR0_STAT);
if (!(i & ATAS_DRDY)||!(i & ATAS_DRQ)) {
Yield;
} else
break;
if (/* i&ATAS_ERR||*/ tS>timeout) {
if (retries--) {
ATAWaitNotBUSY(bd,0);
goto retry;
} else
throw('BlkDev');
}
}
sects_avail=1;
U32s_avail=sects_avail<<BLK_SIZE_BITS>>2;
RepOutU32(buf,U32s_avail,bd->base0+ATAR0_DATA);
buf+=U32s_avail<<2;
cnt-=sects_avail;
retries=3;
}
ATAWaitNotBUSY(bd,0);
if (unlock) BlkDevUnlock(bd);
}
Bool ATAPISync(CBlkDev *bd)
{
Bool okay=TRUE;
if (!ATAWaitNotBUSY(bd,0))
okay=FALSE;
else {
if (bd->flags & BDF_EXT_SIZE)
OutU8(bd->base0+ATAR0_SEL,0xEF|bd->unit<<4);
else
OutU8(bd->base0+ATAR0_SEL,0xE0|bd->unit<<4);
OutU8(bd->base0+ATAR0_LCYL,0);
OutU8(bd->base0+ATAR0_HCYL,0);
ATACmd(bd,ATA_PACKET);
ATAPIWritePktWord(bd,0,0x3500,0,0,0,0,0);
if (!ATAWaitNotBUSY(bd,0))
okay=FALSE;
}
return okay;
}
U0 ATAPIClose(CBlkDev *bd,I64 close_field=0x200,I64 track=0)
{//0x200 CD/DVD part 1
// 0x300 DVD part 2
if (bd->flags & BDF_EXT_SIZE)
OutU8(bd->base0+ATAR0_SEL,0xEF|bd->unit<<4);
else
OutU8(bd->base0+ATAR0_SEL,0xE0|bd->unit<<4);
OutU8(bd->base0+ATAR0_LCYL,0);
OutU8(bd->base0+ATAR0_HCYL,0);
ATACmd(bd,ATA_PACKET);
ATAPIWritePktWord(bd,0,0x5B00,close_field,track,0,0,0);
ATAWaitNotBUSY(bd,0);
}
U0 ATAPIWriteBlks(CBlkDev *bd,U8 *buf, I64 native_blk, I64 cnt)
{
I64 U32s_avail;
U8 *buf2;
ATAWaitNotBUSY(bd,0);
ATAPISeek(bd,native_blk);
OutU8(bd->base0+ATAR0_FEAT,0);
OutU8(bd->base0+ATAR0_LCYL,bd->blk_size);
OutU8(bd->base0+ATAR0_HCYL,bd->blk_size.u8[1]);
if (bd->flags & BDF_EXT_SIZE)
OutU8(bd->base0+ATAR0_SEL,0xEF|bd->unit<<4);
else
OutU8(bd->base0+ATAR0_SEL,0xE0|bd->unit<<4);
OutU8(bd->base0+ATAR0_CMD,ATA_PACKET);
ATAPIWritePktWord(bd,0,0x0400,native_blk.u16[1],native_blk,cnt.u16[1],cnt,0);
bd->flags|=BDF_LAST_WAS_WRITE;
ATAWaitNotBUSY(bd,0);
ATAPISeek(bd,native_blk);
if (bd->flags & BDF_EXT_SIZE)
OutU8(bd->base0+ATAR0_SEL,0xEF|bd->unit<<4);
else
OutU8(bd->base0+ATAR0_SEL,0xE0|bd->unit<<4);
OutU8(bd->base0+ATAR0_LCYL,bd->blk_size);
OutU8(bd->base0+ATAR0_HCYL,bd->blk_size.u8[1]);
ATACmd(bd,ATA_PACKET);
ATAPIWritePktWord(bd,0,0xAA00,native_blk.u16[1],native_blk,cnt.u16[1],cnt,0);
buf2=buf+bd->blk_size*cnt;
while (buf<buf2) {
ATAWaitDRQ(bd,0);
U32s_avail=(InU8(bd->base0+ATAR0_HCYL)<<8+InU8(bd->base0+ATAR0_LCYL))>>2;
if (buf+U32s_avail<<2>buf2)
U32s_avail=(buf2-buf)>>2;
if (U32s_avail) {
RepOutU32(buf,U32s_avail,bd->base0+ATAR0_DATA);
buf+=U32s_avail<<2;
blkdev.write_cnt+=U32s_avail>>(BLK_SIZE_BITS-2);
}
}
ATAWaitNotBUSY(bd,0);
}
Bool ATAWBlks(CDrv *dv,U8 *buf, I64 blk, I64 cnt)
{
I64 n,spc;
CBlkDev *bd=dv->bd;
Bool unlock;
spc=bd->blk_size>>BLK_SIZE_BITS;
if (bd->type==BDT_ATAPI) {
unlock=BlkDevLock(bd);
ATAPIWaitReady(bd,0);
}
while (cnt>0) {
n=cnt;
if (n>bd->max_writes)
n=bd->max_writes;
if (bd->type==BDT_ATAPI)
ATAPIWriteBlks(bd,buf,blk/spc,(n+spc-1)/spc);
else
ATAWriteBlks(bd,buf,blk,n);
buf+=n<<BLK_SIZE_BITS;
blk+=n;
cnt-=n;
blkdev.write_cnt+=n;
}
if (bd->type==BDT_ATAPI) {
ATAPISync(bd);
// ATAPIStartStop(bd,0,FALSE);
if (unlock) BlkDevUnlock(bd);
}
return TRUE;
}
+293
View File
@@ -0,0 +1,293 @@
Bool BootDVDProbe(CBlkDev *bd)
{
U8 *img=CAlloc(DVD_BLK_SIZE);
I64 i;
Bool res=FALSE;
"Port: %04X,%04X Unit: %02X ",bd->base0,bd->base1,bd->unit;
if (ATAProbe(bd->base0,bd->base1,bd->unit)==BDT_ATAPI) {
" ATAPI";
if (ATAPIStartStop(bd,tS+5.0,TRUE)) {
" Started";
for (i=0;i<2;i++) {//Retry
if (ATAPIReadBlks2(bd,tS+7.0,img,sys_boot_blk,1,FALSE)) {
if ((img+sys_boot_src.u16[1]<<BLK_SIZE_BITS)(CKernel *)
->compile_time==sys_compile_time) {
" Found\n";
return TRUE;
} else
" Read";
} else
" NoRead";
}
}
}
" Nope\n";
Free(img);
return res;
}
Bool BootDVDProbeAll(CBlkDev *bd)
{
I64 d1,d2,i,j,k;
bd->base1=0;
for (k=0;k<256;k++) {
i=-1;
while (TRUE) {
j=PCIClassFind(0x010100+k,++i);
if (j<0)
break;
"Subcode:0x%X Bus:0x%X Dev:0x%X Fun:0x%X\n",k,j.u8[2],j.u8[1],j.u8[0];
d1=PCIReadU32(j.u8[2],j.u8[1],j.u8[0],0x10);
d2=PCIReadU32(j.u8[2],j.u8[1],j.u8[0],0x14);
if (d1&1 && d2&1) {
if (bd->base0=d1&~7) {
bd->unit=0;
if (BootDVDProbe(bd))
return TRUE;
bd->unit=1;
if (BootDVDProbe(bd))
return TRUE;
}
}
d1=PCIReadU32(j.u8[2],j.u8[1],j.u8[0],0x18);
d2=PCIReadU32(j.u8[2],j.u8[1],j.u8[0],0x1C);
if (d1&1 && d2&1) {
if (bd->base0=d1&~7) {
bd->unit=0;
if (BootDVDProbe(bd))
return TRUE;
bd->unit=1;
if (BootDVDProbe(bd))
return TRUE;
}
}
}
}
d1=0x1F0;
d2=0x3F6;
if (bd->base0=d1&~7) {
bd->unit=0;
if (BootDVDProbe(bd))
return TRUE;
bd->unit=1;
if (BootDVDProbe(bd))
return TRUE;
}
d1=0x170;
d2=0x376;
if (bd->base0=d1&~7) {
bd->unit=0;
if (BootDVDProbe(bd))
return TRUE;
bd->unit=1;
if (BootDVDProbe(bd))
return TRUE;
}
}
U0 ATARepEntry(I64 base0,I64 base1,I64 unit,U8 *msg,
CATARep **_head,I64 *num_hints)
{
I64 type;
base0&=-8;
base1&=-4;
CATARep *tmpha;
if (type=ATAProbe(base0,base1,unit)) {
*num_hints+=1;
"\n$$PURPLE$$ $$BT+X,\"%d\",LM=\"%d\\n\"$$$$FG$$$$LM,4$$",*num_hints,*num_hints;
if (type==BDT_ATA)
"$$RED$$Hard Drive $$LTBLUE$$ATA ";
else
"$$RED$$CD/DVD Drive $$LTBLUE$$ATAPI ";
"%s$$FG$$\n",msg;
if (base0==blkdev.ins_base0 && unit==blkdev.ins_unit)
"$$PURPLE$$(Drive originally installed from.)$$FG$$\n";
"Base0:0x%04X Base1:0x%04X Unit:%d$$LM,0$$\n",
base0,base1,unit;
if (_head) {
tmpha=CAlloc(sizeof(CATARep));
tmpha->next=*_head;
*_head=tmpha;
tmpha->num=*num_hints;
tmpha->type=type;
tmpha->base0=base0;
tmpha->base1=base1;
tmpha->unit=unit;
}
}
}
Bool ATARepExitAllApplications()
{
"\nWe're going to probe hardware.\n"
"$$RED$$Exit all other applications.$$FG$$\n"
"Press '$$PURPLE$$p$$FG$$' to probe or '$$PURPLE$$s$$FG$$' to skip.\n";
if (ToUpper(GetChar(,FALSE))=='S')
return TRUE;
else
return FALSE;
}
public I64 ATARep(Bool pmt=TRUE,Bool just_ide=FALSE,CATARep **_head=NULL)
{//Report possible ATA devices by probing. Hard disks and CD/DVDs.
I64 d1,d2,i,j,k,cnt=0,unlock_flags=0,num_hints=0;
#assert BLKDEVS_NUM<=64
if (_head) *_head=NULL;
if (pmt && ATARepExitAllApplications)
return 0;
for (i=0;i<BLKDEVS_NUM;i++)
if (blkdev.blkdevs[i].bd_signature==BD_SIGNATURE_VAL)
BEqu(&unlock_flags,i,
BlkDevLock(&blkdev.blkdevs[i]));
if (!just_ide)
for (k=0;k<256;k++) {
i=-1;
while (TRUE) {
j=PCIClassFind(0x010100+k,++i);
if (j<0)
break;
"\nSubcode:0x%X Bus:0x%X Dev:0x%X Fun:0x%X\n",k,j.u8[2],j.u8[1],j.u8[0];
cnt++;
d1=PCIReadU32(j.u8[2],j.u8[1],j.u8[0],0x10);
d2=PCIReadU32(j.u8[2],j.u8[1],j.u8[0],0x14);
if (d1&1 && d2&1) {
ATARepEntry(d1,d2,0,"Primary IDE",_head,&num_hints);
ATARepEntry(d1,d2,1,"Primary IDE",_head,&num_hints);
} else {
d1=0x1F0; d2=0x3F6;
ATARepEntry(d1,d2,0,"Primary IDE",_head,&num_hints);
ATARepEntry(d1,d2,1,"Primary IDE",_head,&num_hints);
}
d1=PCIReadU32(j.u8[2],j.u8[1],j.u8[0],0x18);
d2=PCIReadU32(j.u8[2],j.u8[1],j.u8[0],0x1C);
if (d1&1 && d2&1) {
ATARepEntry(d1,d2,0,"Secondary IDE",_head,&num_hints);
ATARepEntry(d1,d2,1,"Secondary IDE",_head,&num_hints);
} else {
d1=0x170; d2=0x376;
ATARepEntry(d1,d2,0,"Secondary IDE",_head,&num_hints);
ATARepEntry(d1,d2,1,"Secondary IDE",_head,&num_hints);
}
}
}
if (!cnt) {
d1=0x1F0; d2=0x3F6;
ATARepEntry(d1,d2,0,"Primary IDE",_head,&num_hints);
ATARepEntry(d1,d2,1,"Primary IDE",_head,&num_hints);
d1=0x170; d2=0x376;
ATARepEntry(d1,d2,0,"Secondary IDE",_head,&num_hints);
ATARepEntry(d1,d2,1,"Secondary IDE",_head,&num_hints);
}
'\n\n';
for (i=0;i<BLKDEVS_NUM;i++)
if (Bt(&unlock_flags,i))
BlkDevUnlock(&blkdev.blkdevs[i]);
return num_hints;
}
CATARep *ATARepFind(CATARep *haystack_head,I64 needle_num)
{
while (haystack_head) {
if (haystack_head->num==needle_num)
return haystack_head;
haystack_head=haystack_head->next;
}
return NULL;
}
CATARep *ATAIDDrvs(CATARep *head,CATARep **_ata_drv,CATARep **_atapi_drv)
{//This is for when trying to sort-out main hard drives and CD/DVD drives.
CATARep *res=NULL,*tmpha=head,*ata_drv=NULL,*atapi_drv=NULL;
CBlkDev *bd;
Bool was_silent=Silent,ins_found=FALSE;
bd=Let2BlkDev(':',FALSE);
Silent(was_silent);
while (tmpha) {
if (!res && bd && bd->type==tmpha->type) {
if (bd->type==BDT_ATAPI &&
bd->base0==tmpha->base0 && bd->unit==tmpha->unit)
res=atapi_drv=tmpha;
else if (bd->type==BDT_ATA && bd->base0==tmpha->base0 &&
bd->base1==tmpha->base1 && bd->unit==tmpha->unit)
res=ata_drv=tmpha;
}
if (!res || res->type!=tmpha->type) {
if (tmpha->type==BDT_ATA) {
if (!ata_drv || tmpha->unit<ata_drv->unit ||
tmpha->unit==ata_drv->unit && tmpha->num<ata_drv->num)
ata_drv=tmpha;
} else if (tmpha->type==BDT_ATAPI) {
if (!atapi_drv || !ins_found && (tmpha->unit<atapi_drv->unit ||
tmpha->unit==atapi_drv->unit && tmpha->num<atapi_drv->num))
atapi_drv=tmpha;
}
}
if (tmpha->type==BDT_ATAPI && bd && bd->type==BDT_ATA &&
tmpha->base0==blkdev.ins_base0 && tmpha->unit==blkdev.ins_unit) {
if (!ins_found) {
atapi_drv=tmpha;
ins_found=TRUE;
}
}
tmpha=tmpha->next;
}
if (_ata_drv) *_ata_drv =ata_drv;
if (_atapi_drv) *_atapi_drv=atapi_drv;
return res;
}
CBlkDev *ATAMount(U8 first_drv_let,I64 type,I64 base0,I64 base1,I64 unit)
{
CBlkDev *res;
if (0<=first_drv_let-'A'<DRVS_NUM && (type==BDT_ATA || type==BDT_ATAPI) &&
0<=unit<=1) {
res=BlkDevNextFreeSlot(first_drv_let,type);
res->unit=unit;
res->base0=base0;
res->base1=base1;
if (BlkDevAdd(res,,FALSE,FALSE))
return res;
}
return NULL;
}
I64 AutoMountIDE()
{//Try to mount hard drive and CD/DVD, automatically. (Kernel.Cfg option).
//It uses 'C' and 'T' as first drive letters or whatever you set
//in config when compiling Kernel.BIN.
I64 res=0;
CATARep *head=NULL,*ata_drv=NULL,*atapi_drv=NULL,*tmpha;
ATARep(FALSE,TRUE,&head);
ATAIDDrvs(head,&ata_drv,&atapi_drv);
if (ata_drv && ATAMount(blkdev.first_hd_drv_let,BDT_ATA,
ata_drv->base0,ata_drv->base1,ata_drv->unit))
res++;
if (atapi_drv && ATAMount(blkdev.first_dvd_drv_let,BDT_ATAPI,
atapi_drv->base0,atapi_drv->base1,atapi_drv->unit))
res++;
tmpha=head;
while (tmpha) {
if (tmpha!=ata_drv && tmpha!=atapi_drv) {
if (tmpha->type==BDT_ATA && ATAMount(blkdev.first_hd_drv_let,BDT_ATA,
tmpha->base0,tmpha->base1,tmpha->unit))
res++;
else if (tmpha->type==BDT_ATAPI &&
ATAMount(blkdev.first_dvd_drv_let,BDT_ATAPI,
tmpha->base0,tmpha->base1,tmpha->unit))
res++;
}
tmpha=tmpha->next;
}
LinkedLstDel(head);
blkdev.auto_mount_ide_cnt=res;
return res;
}
+240
View File
@@ -0,0 +1,240 @@
U0 BlkDevLockFwdingSet(CBlkDev *bd)
{ //If two blkdevs on same controller, use just one lock
CBlkDev *bd1;
I64 i;
switch (bd->type) {
case BDT_RAM:
break;
case BDT_ISO_FILE_READ:
case BDT_ISO_FILE_WRITE:
bd->lock_fwding=Let2BlkDev(*bd->file_dsk_name);
break;
case BDT_ATA:
case BDT_ATAPI:
for (i=0;i<BLKDEVS_NUM;i++) {
bd1=&blkdev.blkdevs[i];
if (bd1->bd_signature==BD_SIGNATURE_VAL && bd!=bd1 &&
(bd1->type==BDT_ATAPI || bd1->type==BDT_ATA) &&
bd1->base0==bd->base0) {
bd->lock_fwding=bd1;
break;
}
}
break;
}
}
I64 BlkDevAdd(CBlkDev *bd,I64 prt_num=I64_MIN,
Bool whole_drv,Bool make_free)
{//It will mount just one partition of prt_num>=0.
//When repartitioing whole drive, whole_drv=TRUE.
I64 i,j,ext_base,offset,res=0,num=0;
CDrv *dv;
CRedSeaBoot br;
CMasterBoot mbr;
bd->bd_signature=BD_SIGNATURE_VAL;
if (make_free)
dv=DrvMakeFreeSlot(bd->first_drv_let);
else
dv=DrvMakeFreeSlot(DrvNextFreeLet(bd->first_drv_let));
dv->bd=bd;
dv->drv_offset=bd->drv_offset;
dv->size=bd->max_blk+1-bd->drv_offset;
switch (bd->type) {
case BDT_RAM:
case BDT_ISO_FILE_READ:
case BDT_ISO_FILE_WRITE:
dv->dv_signature=DRV_SIGNATURE_VAL;
dv->prt_num=num;
dv->fs_type=FSt_REDSEA;
//This is to force creation of a RAM
//drive during boot, so it is probably
//MAlloced to the same addr and can
//be assumed to be already formatted.
//If this line is removed, RAM Drives
//will be alloced on a just-in-time
//basis.
if (BlkDevInit(bd))
res++;
else
dv->dv_signature=0;
break;
case BDT_ATA:
dv->dv_signature=DRV_SIGNATURE_VAL; //Temporarily validate
if (!BlkDevInit(bd))
dv->dv_signature=0; //Revoke validation
else {
dv->dv_signature=0; //Revoke validation
if (whole_drv) {
dv->dv_signature=DRV_SIGNATURE_VAL;
dv->prt_num=num;
res++;
dv->fs_type=FSt_REDSEA;
dv->size=bd->max_blk+1-bd->drv_offset;
//The following read is a test read.
//if it hangs, the drive is not supported.
ATAReadBlks(bd,&mbr,0,1);
break;
}
offset=0;
ext_base=INVALID_CLUSTER;
while (prt_num<0 || num<=prt_num) {
ATAReadBlks(bd,&mbr,offset,1);
if (mbr.signature!=0xAA55)
break;
j=-1;
for (i=0;i<4 && (prt_num<0 || num<=prt_num);i++) {
if (mbr.p[i].type) {
if (make_free)
dv=DrvMakeFreeSlot(bd->first_drv_let+res);
else
dv=DrvMakeFreeSlot(DrvNextFreeLet(bd->first_drv_let+res));
dv->bd=bd;
dv->drv_offset=mbr.p[i].offset+offset;
dv->size =mbr.p[i].size;
switch (mbr.p[i].type) {
case MBR_PT_REDSEA:
dv->dv_signature=DRV_SIGNATURE_VAL;
dv->prt_num=num;
res++;
dv->fs_type=FSt_REDSEA;
RedSeaInit(dv);
break;
case MBR_PT_FAT32a:
case MBR_PT_FAT32b:
case MBR_PT_FAT32c:
case MBR_PT_FAT32d:
case MBR_PT_FAT32e:
case MBR_PT_FAT32f:
ATAReadBlks(bd,&br,dv->drv_offset,1);
dv->dv_signature=DRV_SIGNATURE_VAL;
dv->prt_num=num;
res++;
if (br.signature==MBR_PT_REDSEA) {
dv->fs_type=FSt_REDSEA;
RedSeaInit(dv);
} else {
dv->fs_type=FSt_FAT32;
FAT32Init(dv);
}
break;
case MBR_PT_NTFS:
dv->dv_signature=DRV_SIGNATURE_VAL;
dv->prt_num=num;
res++;
dv->fs_type=FSt_NTFS;
break;
case 5:
case 15:
j=i;
break;
default:
dv->dv_signature=DRV_SIGNATURE_VAL;
dv->prt_num=num;
res++;
dv->fs_type=FSt_UNKNOWN;
}
num++;
}
}
if (Let2BlkDevType(bd->first_drv_let+res)!=bd->type)
break;
if (j<0)
break;
if (!mbr.p[j].offset)
break;
if (ext_base==INVALID_CLUSTER) {
offset=mbr.p[j].offset;
ext_base=offset;
} else
offset=mbr.p[j].offset+ext_base;
}
}
break;
case BDT_ATAPI:
dv->dv_signature=DRV_SIGNATURE_VAL;
dv->prt_num=num;
res++;
dv->fs_type=FSt_ISO9660; //Start with this
dv->size=0;
break;
}
if (res)
BlkDevLockFwdingSet(bd);
else
BlkDevDel(bd);
return res;
}
Bool DrvEnable(U8 drv_let,Bool val)
{//Can unmount or remount, but not mount the first time.
CDrv *dv;
if (dv=Let2Drv(drv_let,FALSE))
return !LBEqu(&dv->fs_type,FStf_DISABLE,!val);
else
return FALSE;
}
I64 SysGetI64()
{
U8 st[STR_LEN];
GetS(st,STR_LEN,FALSE);
return Str2I64(st,16);
}
Bool GetBaseUnit(CBlkDev *bd)
{
I64 ch;
Bool probe;
#exe {
if (kernel_cfg->opts[CFG_DONT_PROBE])
StreamPrint("probe=FALSE;");
else
StreamPrint("probe=TRUE;");
};
if (!probe || !BootDVDProbeAll(bd)) {
"\nDon't worry. This is not a product\n"
"registration. TempleOS just needs the\n"
"I/O port numbers for the CD/DVD.\n"
"\nRetry the ports above or check Windows\n"
"system information under I/O ports for\n"
"'IDE', 'ATA' or 'SATA'.\n"
"In Linux, use 'lspci -v' for ports.\n"
"\n\nEnter 4-digit hex I/O Port number.\n"
"CD/DVD I/O Port Base0: 0x";
bd->base0=SysGetI64;
bd->base1=0;
bd->unit =0;
if (bd->base0) {
"\nUnit (0 or 1): ";
do ch=GetChar(,FALSE);
while (!('0'<=ch<='1'));
'' ch;
bd->unit=ch-'0';
blkdev.dvd_boot_is_good=BootDVDProbe(bd);
return TRUE;
} else {
blkdev.dvd_boot_is_good=FALSE;
return FALSE;
}
}
return FALSE;
}
U0 BlkDevsInitAll()
{
CBlkDev *bd;
I64 i;
blkdev.blkdevs=CAlloc(sizeof(CBlkDev)*BLKDEVS_NUM);
blkdev.drvs=CAlloc(sizeof(CDrv)*DRVS_NUM);
for (i=0;i<DRVS_NUM;i++)
blkdev.let_to_drv[i]=&blkdev.drvs[i];
#exe {
if (kernel_cfg->opts[CFG_AUTO_MOUNT_IDE])
StreamPrint("AutoMountIDE;");
StreamPrint("#exe {Option(OPTf_WARN_PAREN,OFF);}");
StreamDoc(kernel_cfg->add_dev);
StreamPrint("#exe {Option(OPTf_WARN_PAREN,ON);}");
};
}
+109
View File
@@ -0,0 +1,109 @@
#define ZERO_BUF_SIZE 2048
U0 WZeroBlks(CDrv *dv,I64 blk,I64 cnt)
{//Fill blk cnt with zeros in Drv.
I64 n;
U8 *z=CAlloc(ZERO_BUF_SIZE<<BLK_SIZE_BITS);
Bool show_progress;
if (cnt>ZERO_BUF_SIZE && dv->bd->type!=BDT_RAM) {
progress1=0; progress1_max=cnt;
StrCpy(progress1_desc,"Zeroing");
show_progress=TRUE;
} else
show_progress=FALSE;
while (cnt>0) {
n=cnt;
if (n>ZERO_BUF_SIZE)
n=ZERO_BUF_SIZE;
WBlks(dv,z,blk,n);
blk+=n;
cnt-=n;
if (show_progress)
progress1+=n;
Yield; //Prevent locking
}
Free(z);
if (show_progress) {
*progress1_desc=0;
progress1=progress1_max=0;
}
}
Bool RBlks(CDrv *dv,U8 *buf, I64 blk, I64 cnt)
{//Read blk cnt from Drv to buf.
Bool res=TRUE,unlock;
CBlkDev *bd=dv->bd;
if (cnt<=0) return TRUE;
DrvChk(dv);
try {
unlock=DrvLock(dv);
BlkDevInit(bd);
if (dv->drv_offset && blk<dv->drv_offset ||
blk+cnt>dv->drv_offset+dv->size)
throw('Drv');
if (bd->flags & BDF_READ_CACHE)
RCache(dv,&buf,&blk,&cnt);
if (cnt>0) {
switch (bd->type) {
case BDT_RAM:
MemCpy(buf,bd->RAM_dsk+blk<<BLK_SIZE_BITS,cnt<<BLK_SIZE_BITS);
break;
case BDT_ISO_FILE_READ:
case BDT_ISO_FILE_WRITE:
FRBlks(bd->file_dsk,buf,blk,cnt);
break;
case BDT_ATA:
case BDT_ATAPI:
res=ATARBlks(dv,buf,blk,cnt);
break;
}
bd->last_time=tS;
if (bd->flags & BDF_READ_CACHE)
DskCacheAdd(dv,buf,blk,cnt);
}
if (unlock)
DrvUnlock(dv);
} catch
if (unlock)
DrvUnlock(dv);
return res;
}
Bool WBlks(CDrv *dv,U8 *buf, I64 blk, I64 cnt)
{//Write blk cnt from buf to Drv.
Bool res=TRUE,unlock;
CBlkDev *bd=dv->bd;
if (cnt<=0) return TRUE;
DrvChk(dv);
try {
unlock=DrvLock(dv);
BlkDevInit(bd);
if (bd->flags&BDF_READ_ONLY && !(bd->flags & BDF_READ_ONLY_OVERRIDE))
throw('BlkDev');
if (dv->drv_offset && blk<dv->drv_offset ||
blk+cnt>dv->drv_offset+dv->size)
throw('Drv');
if (cnt>0) {
switch (bd->type) {
case BDT_RAM:
MemCpy(bd->RAM_dsk+blk<<BLK_SIZE_BITS,buf,cnt<<BLK_SIZE_BITS);
break;
case BDT_ISO_FILE_READ:
case BDT_ISO_FILE_WRITE:
FWBlks(bd->file_dsk,buf,blk,cnt);
break;
case BDT_ATA:
case BDT_ATAPI:
res=ATAWBlks(dv,buf,blk,cnt);
break;
}
bd->last_time=tS;
if (bd->flags & BDF_READ_CACHE)
DskCacheAdd(dv,buf,blk,cnt);
}
if (unlock)
DrvUnlock(dv);
} catch
if (unlock)
DrvUnlock(dv);
return res;
}
+187
View File
@@ -0,0 +1,187 @@
Bool BlkDevLock(CBlkDev *bd)
{//Make this task have exclusive access to BlkDev.
BlkDevChk(bd);
while (bd->lock_fwding)
bd=bd->lock_fwding; //If two blkdevs on same controller, use just one lock
if (!Bt(&bd->locked_flags,BDlf_LOCKED) || bd->owning_task!=Fs) {
while (LBts(&bd->locked_flags,BDlf_LOCKED))
Yield;
bd->owning_task=Fs;
return TRUE;
} else
return FALSE;
}
Bool BlkDevUnlock(CBlkDev *bd,Bool rst=FALSE)
{//Release exclusive lock on access to BlkDev.
BlkDevChk(bd);
while (bd->lock_fwding)
bd=bd->lock_fwding; //If two blkdevs on same controller, use just one lock
if (Bt(&bd->locked_flags,BDlf_LOCKED) && bd->owning_task==Fs) {
if (rst)
bd->flags&=~(BDF_INITIALIZED|BDF_INIT_IN_PROGRESS);
bd->owning_task=NULL;
LBtr(&bd->locked_flags,BDlf_LOCKED);
Yield; //Prevent deadlock
return TRUE;
} else
return FALSE;
}
Bool BlkDevInit(CBlkDev *bd)
{
CDirEntry de;
U8 buf[STR_LEN];
CDrv *dv=Let2Drv(bd->first_drv_let);
Bool res=FALSE;
if (!LBts(&bd->flags,BDf_INITIALIZED)) {
bd->flags|=BDF_INIT_IN_PROGRESS;
switch (bd->type) {
case BDT_RAM:
if (!bd->RAM_dsk) {
bd->RAM_dsk=AMAlloc((bd->max_blk+1)<<BLK_SIZE_BITS);
bd->max_blk=MSize(bd->RAM_dsk)>>BLK_SIZE_BITS-1;
}
dv->fs_type=FSt_REDSEA;
dv->size=bd->max_blk+1-bd->drv_offset;
if (RedSeaValidate(bd->first_drv_let))
RedSeaInit(dv);
else
RedSeaFmt(bd->first_drv_let);
res=TRUE;
break;
case BDT_ISO_FILE_READ:
if (FileFind(bd->file_dsk_name,&de,FUF_JUST_FILES)) {
bd->max_blk=de.size>>BLK_SIZE_BITS-1;
try bd->file_dsk=FOpen(bd->file_dsk_name,"rc",bd->max_blk+1);
catch {
if (Fs->except_ch=='File')
PrintErr("Not Contiguous. Move file to filename.ISO.C.\n");
Fs->catch_except=TRUE;
}
if (bd->file_dsk) {
dv->fs_type=FSt_REDSEA;
dv->size=bd->max_blk+1-bd->drv_offset;
if (RedSeaValidate(bd->first_drv_let)) {
RedSeaInit(dv);
res=TRUE;
} else
PrintErr("Not RedSea\n");
}
}
break;
case BDT_ISO_FILE_WRITE:
if (!bd->file_dsk_name) {
StrPrint(buf,"%C:/Drv%C.ISO.C",
blkdev.boot_drv_let,bd->first_drv_let);
bd->file_dsk_name=AStrNew(buf);
}
if (bd->max_blk<7)
bd->max_blk=7;
bd->file_dsk=FOpen(bd->file_dsk_name,"wc",bd->max_blk+1);
dv->fs_type=FSt_REDSEA;
dv->size=bd->max_blk+1-bd->drv_offset;
RedSeaFmt(bd->first_drv_let);
CallExtStr("RedSeaISO9660",bd->file_dsk_name,bd->first_drv_let);
res=TRUE;
break;
case BDT_ATA:
bd->max_reads=128;
bd->max_writes=1;
res=ATAInit(bd);
break;
case BDT_ATAPI:
//0xFFFF*4 is too big for my taste
bd->max_reads=0x800*4;
//max of maybe a quarter of disk cache
if (bd->max_reads>blkdev.cache_size/BLK_SIZE/4)
bd->max_reads=blkdev.cache_size/BLK_SIZE/4 & ~3;
if (bd->max_reads<128)
bd->max_reads=128;
bd->max_writes=0xFFFF*4;
if (res=ATAInit(bd))
dv->size=bd->max_blk+1;
break;
}
if (res && bd->flags & BDF_READ_CACHE)
DskCacheInvalidate(dv);
bd->flags&=~BDF_INIT_IN_PROGRESS;
} else
res=TRUE;
return res;
}
U0 BlkDevsRelease()
{//When task dies, release all owned BlkDevs.
I64 i;
CBlkDev *bd;
for (i=0;i<BLKDEVS_NUM;i++) {
bd=&blkdev.blkdevs[i];
if (bd->owning_task==Fs && bd->bd_signature==BD_SIGNATURE_VAL)
BlkDevUnlock(bd,TRUE);
}
}
CBlkDev *BlkDevNextFreeSlot(U8 first_drv_let,I64 type)
{//Locate free slot for new BlkDev, like during $LK,"Mount",A="MN:Mount"$().
I64 i=0;
CBlkDev *res;
if (Let2BlkDevType(first_drv_let)!=type)
throw('BlkDev');
do {
res=&blkdev.blkdevs[i];
if (res->bd_signature!=BD_SIGNATURE_VAL) {
MemSet(res,0,sizeof(CBlkDev));
res->first_drv_let=first_drv_let;
res->type=type;
res->flags=BDF_READ_CACHE;
res->blk_size=BLK_SIZE;
res->max_blk=0xEFFFFFFF;
switch (type) {
case BDT_RAM:
res->flags&=~BDF_READ_CACHE;
break;
case BDT_ISO_FILE_READ:
res->flags|=BDF_READ_ONLY;
break;
case BDT_ATAPI:
res->flags|=BDF_REMOVABLE|BDF_READ_ONLY;
res->blk_size=DVD_BLK_SIZE;
break;
}
return res;
}
} while (++i<BLKDEVS_NUM);
throw('BlkDev');
return NULL; //never gets here
}
U0 BlkDevDel(CBlkDev *bd)
{//Delete BlkDev
DrvBlkDevDel(bd);
FClose(bd->file_dsk);
Free(bd->file_dsk_name);
Free(bd->dev_id_record);
MemSet(bd,0,sizeof(CBlkDev));
}
CBlkDev *BlkDevChk(CBlkDev *bd,Bool except=TRUE)
{//Check for valid BlkDev. Throw exception.
if (!bd || bd->bd_signature!=BD_SIGNATURE_VAL ||
!(BDT_NULL<bd->type<BDT_TYPES_NUM)) {
if (except)
throw('BlkDev');
else
return NULL;
} else
return bd;
}
CBlkDev *Let2BlkDev(U8 drv_let=0,Bool except=TRUE)
{//Drv letter to BlkDev ptr.
CDrv *dv;
if (dv=Let2Drv(drv_let,except))
return BlkDevChk(dv->bd,except);
else
return NULL;
}
+247
View File
@@ -0,0 +1,247 @@
//ISO1 is ISO9660
//ISO2 is ISO13490
//ISO3 is ISO13346
Bool ISOInit(CDrv *dv,I64 blk)
{
CBlkDev *bd=dv->bd;
I64 spc=bd->blk_size>>BLK_SIZE_BITS,i=blk/spc,drv_offset=0;
CISO1PriDesc *iso=MAlloc(bd->blk_size);
CISO1DirEntry *de;
Bool unlock,res=FALSE;
U8 buf[8];
try {
unlock=DrvLock(dv);
dv->fs_type=FSt_ISO9660;
dv->spc=spc;
dv->data_area=dv->root_cluster=dv->drv_offset=bd->drv_offset=dv->size=0;
while (TRUE) {
dv->size=MaxI64(dv->size,(i+1)*spc);
RBlks(dv,iso,i*spc,spc);
buf[0](U32)=iso->id[0](U32);
buf[4](U16)=iso->id[4](U8);
switch (LstMatch(buf,"CD001\0CDW02\0BEA01\0BOOT2\0NSR02\0NSR03\0TEA01\0",
LMF_EXACT)) {
case 0:
switch (iso->type) {
case ISO1T_BOOT_RECORD:
drv_offset+=(2*DVD_BLK_SIZE+DVD_BLK_SIZE)/BLK_SIZE;
break;
case ISO1T_SUPPLEMENTARY_DESC:
de=&iso->root_dir_record;
dv->size=iso->vol_space_size.little*bd->blk_size>>BLK_SIZE_BITS;
if (!StrCmp(iso->publisher_id,"TempleOS RedSea")) {
dv->fs_type=FSt_REDSEA;
bd->drv_offset=dv->drv_offset=19<<2+drv_offset;
bd->max_blk=dv->size-1;
dv->size-=bd->drv_offset;
RedSeaInit(dv);
} else
dv->root_cluster=de->loc.little;
res=TRUE;
goto di_done;
case ISO1T_TERMINATOR:
throw('Drv');
}
break;
default: //Its normal for ISO13346 to read NULL blk as terminator
PrintErr("File System Not Supported\n");
throw('Drv');
}
i++;
}
di_done:
Free(iso);
if (unlock)
DrvUnlock(dv);
} catch {
dv->fs_type=FSt_ISO9660;
dv->spc=spc;
dv->drv_offset=bd->drv_offset=dv->data_area=dv->root_cluster=0;
Free(iso);
if (unlock)
DrvUnlock(dv);
}
return res;
}
U0 DVDImageRead(U8 dvd_drv_let,U8 *out_name)
{//Read entire CD/DVD image into ISO file.
CDrv *dv=Let2Drv(dvd_drv_let);
CBlkDev *bd=dv->bd;
U8 *buf=MAlloc(COPY_BUF_BLKS<<BLK_SIZE_BITS),
*out_name2=DftExt(out_name,"ISO");
CFile *f=FOpen(out_name2,"w");
I64 n,spc=bd->blk_size>>BLK_SIZE_BITS,blk=0,cnt,retry;
BlkDevInit(bd);
if (bd->type!=BDT_ATAPI)
throw('BlkDev');
if (!out_name)
out_name=blkdev.dft_iso_filename;
cnt=CeilU64(dv->size,spc);
while (cnt>0) {
if (cnt>COPY_BUF_BLKS)
n=COPY_BUF_BLKS;
else
n=cnt;
if (n>bd->max_reads)
n=bd->max_reads;
retry=4;
while (--retry)
if (ATAPIReadBlks2(bd,tS+7.0+0.004*n/spc,buf,blk/spc,n/spc,TRUE))
//n is 0x800 if max_reads. Up to 8 additional seconds
break;
if (!retry)
ATAPIReadBlks2(bd,0,buf,blk/spc,n/spc,TRUE);
FWBlks(f,buf,blk,n);
cnt-=n;
blk+=n;
}
FClose(f);
Free(buf);
Free(out_name2);
}
class CDualBuf
{
U8 *buf0,*buf1;
I64 in_buf,out_buf,cnt;
U8 *filename;
CBlkDev *dvd_bd;
};
U0 DVDImageWriteTask(CDualBuf *d)
{
U8 *buf;
I64 n,blk=0,cnt=d->cnt;
CFile *f;
if (FileAttr(d->filename)&RS_ATTR_CONTIGUOUS)
f=FOpen(d->filename,"rc");
else
f=FOpen(d->filename,"r");
while (cnt>0) {
if (cnt>COPY_BUF_BLKS)
n=COPY_BUF_BLKS;
else
n=cnt;
if (n>d->dvd_bd->max_writes)
n=d->dvd_bd->max_writes;
if (d->in_buf&1)
buf=d->buf1;
else
buf=d->buf0;
while (d->in_buf>d->out_buf+1)
Yield;
FRBlks(f,buf,blk,n);
d->in_buf++;
cnt-=n;
blk+=n;
}
FClose(f);
}
U0 DVDImageWrite(U8 dvd_drv_let,U8 *in_name=NULL,I64 media_type=MT_DVD)
{//Write CD/DVD ISO file to disk.
CDualBuf *d=CAlloc(sizeof(CDualBuf));
U8 *buf,*in_name2,*in_name3;
I64 i,n,spc,blk=0,cnt;
CDrv *dv=Let2Drv(dvd_drv_let);
CBlkDev *bd=dv->bd,*bd2;
CTask *task;
CFile *f;
if (!in_name)
in_name=blkdev.dft_iso_filename;
in_name3=DftExt(in_name,"ISO");
in_name2=FileNameAbs(in_name3);
f=FOpen(in_name2,"r");
if (!f) {
Free(d);
return;
}
cnt=(FSize(f)+BLK_SIZE-1)>>BLK_SIZE_BITS;
FClose(f);
if (bd->type!=BDT_ATAPI)
throw('BlkDev');
bd2=Let2BlkDev(*in_name2);
while (bd2->lock_fwding)
bd2=bd2->lock_fwding; //If two blkdevs on same controller, use one lock
if ((bd2->type==BDT_ATA || bd2->type==BDT_ATAPI) &&
bd2->base0==bd->base0) {
PrintErr("Can't burn CD/DVD on same ATA controller as file.\n\n");
throw('BlkDev');
}
bd->flags|=BDF_READ_ONLY_OVERRIDE;
BlkDevInit(bd);
spc=bd->blk_size>>BLK_SIZE_BITS;
if (dv->size<cnt)
dv->size=cnt;
d->filename=in_name2;
d->dvd_bd=bd;
d->buf0=MAlloc(COPY_BUF_BLKS<<BLK_SIZE_BITS);
d->buf1=MAlloc(COPY_BUF_BLKS<<BLK_SIZE_BITS);
d->cnt=cnt;
task=Spawn(&DVDImageWriteTask,d,"Write CD/DVD");
while (d->in_buf<=d->out_buf)
Yield;
BlkDevLock(bd);
ATAPIWaitReady(bd,0);
progress1=0; progress1_max=cnt;
StrCpy(progress1_desc,"Writing");
while (cnt>0) {
if (cnt>COPY_BUF_BLKS)
n=COPY_BUF_BLKS;
else
n=cnt;
if (n>bd->max_writes)
n=bd->max_writes;
if (d->out_buf&1)
buf=d->buf1;
else
buf=d->buf0;
while (d->in_buf<=d->out_buf)
Yield;
ATAPIWriteBlks(bd,buf,blk/spc,(n+spc-1)/spc);
d->out_buf++;
cnt-=n;
blk+=n;
progress1+=n;
}
ATAPISync(bd);
progress1=0; progress1_max=2;
StrCpy(progress1_desc,"Closing");
for (i=0;i<2;i++) {
ATAPIClose(bd,0x100,i); //Close tracks
progress1++;
}
ATAPISync(bd);
ATAPIClose(bd,0x200); //close disk
ATAPISync(bd);
if (media_type==MT_DVD) {
ATAPIClose(bd,0x300);
ATAPISync(bd);
}
*progress1_desc=0;
progress1=progress1_max=0;
bd->flags&=~BDF_READ_ONLY_OVERRIDE;
BlkDevUnlock(bd);
Free(d->buf0);
Free(d->buf1);
Free(in_name2);
Free(in_name3);
Free(d);
}
+265
View File
@@ -0,0 +1,265 @@
I64 FSize(CFile *f)
{//Report size of opened file in bytes.
if (f)
return f->de.size;
else
return 0;
}
CFile *FOpen(U8 *filename,U8 *flags,I64 cnt=0)
{//Allows flags "r","w","w+". "c" for contiguous.
//(It uses $LK,"StrOcc",A="MN:StrOcc"$() for 'w', 'r', '+', 'c')
CFile *f=CAlloc(sizeof(CFile));
CDirContext *dirc;
U8 *full_name;
Bool contiguous=StrOcc(flags,'c');
f->cluster=INVALID_CLUSTER;
f->fblk_num=0;
if (cnt>0)
f->max_blk=cnt-1;
else
f->max_blk=I64_MAX;
f->file_cluster_num=INVALID_CLUSTER;
full_name=FileNameAbs(filename);
f->dv=Let2Drv(*full_name);
if (f->dv->fs_type==FSt_REDSEA)
contiguous=TRUE;
if (contiguous) {
f->flags|=FF_CONTIGUOUS;
if (f->dv->fs_type!=FSt_REDSEA &&
!(FileAttr(filename) & RS_ATTR_CONTIGUOUS))
throw('File');
}
f->cluster_buf=CAlloc(f->dv->spc<<BLK_SIZE_BITS);
if (StrOcc(flags,'w')) {
f->flags=f->flags|FF_WRITE|FF_NEEDS_WRITE;
if (StrOcc(flags,'+')) {
if (FileFind(full_name,&f->de,FUF_JUST_FILES)) {
Free(full_name);
if (contiguous)
f->max_blk=(FSize(f)+BLK_SIZE-1)>>BLK_SIZE_BITS-1;
return f;
}
} else
Del(full_name,,,FALSE);
f->de.full_name=full_name;
f->flags|=FF_NEW_FILE;
if (dirc=DirContextNew(full_name)) {
StrCpy(f->de.name,dirc->mask);
if (cnt>0) {//We pre-alloc the whole thing.
f->de.cluster=ClustersAlloc(f->dv,0,
(cnt+f->dv->spc-1)/f->dv->spc,contiguous);
f->de.size=cnt<<BLK_SIZE_BITS;
DirNew(dirc->dv,Fs->cur_dir,&f->de,TRUE);
f->flags&=~FF_NEW_FILE;
}
DirContextDel(dirc);
return f;
}
} else {
if (FileFind(full_name,&f->de,FUF_JUST_FILES)) {
Free(full_name);
f->max_blk=(FSize(f)+BLK_SIZE-1)>>BLK_SIZE_BITS-1;
return f;
}
}
Free(f->cluster_buf);
Free(full_name);
Free(f);
return NULL;
}
U0 FClose(CFile *f)
{//Close CFile, updating directory.
CDirContext *dirc;
if (f) {
if (f->flags & FF_BUF_DIRTY) {
WClusters(f->dv,f->cluster_buf,f->cluster,1);
f->flags&=~FF_BUF_DIRTY;
}
if (f->flags & FF_NEEDS_WRITE) {
if (dirc=DirContextNew(f->de.full_name)) {
if (!(f->flags & FF_USE_OLD_DATETIME))
f->de.datetime=Now;
if (f->flags & FF_NEW_FILE)
DirNew(dirc->dv,Fs->cur_dir,&f->de,TRUE);
else
DirNew(dirc->dv,Fs->cur_dir,&f->de,FALSE);
DirContextDel(dirc);
} else
throw('File');
}
Free(f->cluster_buf);
Free(f->de.full_name);
Free(f);
}
}
I64 FSetCluster(CFile *f,I64 c,I64 blk,Bool read)
{
CDrv *dv=f->dv;
I64 i;
if (f->cluster!=c) {
if (f->flags & FF_BUF_DIRTY) {
i=dv->spc;
if (f->max_blk!=I64_MAX) {
i=f->max_blk+1-f->file_cluster_num*dv->spc;
if (i>dv->spc)
i=dv->spc;
}
WClustersBlks(dv,f->cluster_buf,f->cluster,i);
f->flags=f->flags & ~FF_BUF_DIRTY;
}
f->cluster=c;
f->file_cluster_num=blk/dv->spc;
if (read) {
i=dv->spc;
if (f->max_blk!=I64_MAX) {
i=f->max_blk+1-f->file_cluster_num*dv->spc;
if (i>dv->spc)
i=dv->spc;
}
c=RClustersBlks(dv,f->cluster_buf,c,i);
}
}
return c;
}
Bool FRBlks(CFile *f,U8 *buf,I64 blk=FFB_NEXT_BLK,I64 cnt=1)
{//Read [nth,n+cnt) blks of file.
CDrv *dv=f->dv;
I64 spc=dv->spc,i,j,c=f->de.cluster;
if (!f || !dv) return FALSE;
if (blk==FFB_NEXT_BLK)
blk=f->fblk_num;
if (blk+cnt-1>f->max_blk)
return FALSE;
if (cnt<=0) return TRUE;
if (f->flags & FF_CONTIGUOUS) {
RBlks(dv,buf,Cluster2Blk(dv,c)+blk,cnt);
blk+=cnt;
} else {
i=blk/spc;
if (0<=f->file_cluster_num<=i) {
c=f->cluster;
i-=f->file_cluster_num;
}
if (i>0)
c=ClusterNumNext(dv,c,i);
if (i=blk%spc) {
c=FSetCluster(f,c,blk,TRUE);
if (cnt<spc-i)
j=cnt;
else
j=spc-i;
MemCpy(buf,f->cluster_buf+i<<BLK_SIZE_BITS,j<<BLK_SIZE_BITS);
buf+=j<<BLK_SIZE_BITS;
cnt-=j;
blk+=j;
}
while (cnt>=spc) {
c=FSetCluster(f,c,blk,TRUE);
MemCpy(buf,f->cluster_buf,spc<<BLK_SIZE_BITS);
buf+=spc<<BLK_SIZE_BITS;
cnt-=spc;
blk+=spc;
}
if (cnt>0) {
c=FSetCluster(f,c,blk,TRUE);
MemCpy(buf,f->cluster_buf,cnt<<BLK_SIZE_BITS);
buf+=cnt<<BLK_SIZE_BITS;
blk+=cnt;
}
}
f->fblk_num=blk;
return TRUE;
}
Bool FWBlks(CFile *f,U8 *buf,I64 blk=FFB_NEXT_BLK,I64 cnt=1)
{//Write [nth,n+cnt) blks of file.
CDrv *dv=f->dv;
I64 spc=dv->spc,i,j,c=f->de.cluster,c1;
if (!f || !dv) return FALSE;
if (blk==FFB_NEXT_BLK)
blk=f->fblk_num;
if (blk+cnt-1>f->max_blk)
return FALSE;
if (!(f->flags & FF_WRITE))
return FALSE;
if (cnt<=0) return TRUE;
if (f->flags & FF_CONTIGUOUS) {
WBlks(dv,buf,Cluster2Blk(dv,c)+blk,cnt);
blk+=cnt;
} else {
if (!c) {
c=ClustersAlloc(dv,0,1,FALSE);
f->file_cluster_num=0;
f->cluster=c;
f->de.cluster=c;
f->flags|=FF_NEEDS_WRITE|FF_NEW_FILE;
}
i=blk/spc;
if (0<=f->file_cluster_num<=i) {
c=f->cluster;
i-=f->file_cluster_num;
}
while (i>0) {
c1=c;
c=ClusterNumNext(dv,c1,1);
if (c==INVALID_CLUSTER) {
c=ClustersAlloc(dv,c1,i,FALSE);
if (i>1)
c=ClusterNumNext(dv,c,i-1);
break;
} else
i--;
}
if (i=blk%spc) {
FSetCluster(f,c,blk,TRUE);
if (cnt<spc-i)
j=cnt;
else
j=spc-i;
MemCpy(f->cluster_buf+BLK_SIZE*i,buf,j<<BLK_SIZE_BITS);
f->flags|=FF_BUF_DIRTY;
buf+=j<<BLK_SIZE_BITS;
cnt-=j;
blk+=j;
if (cnt>0) {
c1=c;
c=ClusterNumNext(dv,c1,1);
if (c==INVALID_CLUSTER)
c=ClustersAlloc(dv,c1,1,FALSE);
}
}
while (cnt>=spc) {
FSetCluster(f,c,blk,FALSE);
MemCpy(f->cluster_buf,buf,spc<<BLK_SIZE_BITS);
f->flags|=FF_BUF_DIRTY;
buf+=spc<<BLK_SIZE_BITS;
cnt-=spc;
blk+=spc;
if (cnt>0) {
c1=c;
c=ClusterNumNext(dv,c1,1);
if (c==INVALID_CLUSTER)
c=ClustersAlloc(dv,c1,1,FALSE);
}
}
if (cnt>0) {
FSetCluster(f,c,blk,TRUE);
MemCpy(f->cluster_buf,buf,cnt<<BLK_SIZE_BITS);
f->flags|=FF_BUF_DIRTY;
buf+=cnt<<BLK_SIZE_BITS;
blk+=cnt;
}
if (f->de.size<blk<<BLK_SIZE_BITS)
f->de.size=blk<<BLK_SIZE_BITS;
}
f->fblk_num=blk;
return TRUE;
}
+145
View File
@@ -0,0 +1,145 @@
U0 DskCacheInit(I64 size_in_U8s)
{
CCacheBlk *tmpc;
I64 i,cnt;
while (LBts(&sys_semas[SEMA_DSK_CACHE],0))
Yield;
Free(blkdev.cache_ctrl);
Free(blkdev.cache_base);
Free(blkdev.cache_hash_table);
if (size_in_U8s<0x2000) {
blkdev.cache_ctrl=NULL;
blkdev.cache_base=NULL;
blkdev.cache_hash_table=NULL;
} else {
blkdev.cache_ctrl=ACAlloc(offset(CCacheBlk.body));
blkdev.cache_base=AMAlloc(size_in_U8s);
QueInit(blkdev.cache_ctrl);
cnt=MSize(blkdev.cache_base)/sizeof(CCacheBlk);
blkdev.cache_size=cnt*BLK_SIZE;
for (i=0;i<cnt;i++) {
tmpc=blkdev.cache_base+i;
QueIns(tmpc,blkdev.cache_ctrl->last_lru);
tmpc->next_hash=tmpc->last_hash=tmpc;
tmpc->dv=NULL;
tmpc->blk=0;
}
blkdev.cache_hash_table=AMAlloc(DSK_CACHE_HASH_SIZE*sizeof(U8 *)*2);
for (i=0;i<DSK_CACHE_HASH_SIZE;i++) {
tmpc=blkdev.cache_hash_table(U8 *)+i*sizeof(U8 *)*2
-offset(CCacheBlk.next_hash);
tmpc->next_hash=tmpc->last_hash=tmpc;
}
}
LBtr(&sys_semas[SEMA_DSK_CACHE],0);
}
I64 DskCacheHash(I64 blk)
{
I64 i=blk & (DSK_CACHE_HASH_SIZE-1);
return blkdev.cache_hash_table(U8 *)+i<<4-offset(CCacheBlk.next_hash);
}
U0 DskCacheQueRem(CCacheBlk *tmpc)
{
QueRem(tmpc);
tmpc->next_hash->last_hash=tmpc->last_hash;
tmpc->last_hash->next_hash=tmpc->next_hash;
}
U0 DskCacheQueIns(CCacheBlk *tmpc)
{
CCacheBlk *tmp_n,*tmp_l;
QueIns(tmpc,blkdev.cache_ctrl->last_lru);
tmp_l=DskCacheHash(tmpc->blk);
tmp_n=tmp_l->next_hash;
tmpc->last_hash=tmp_l;
tmpc->next_hash=tmp_n;
tmp_l->next_hash=tmp_n->last_hash=tmpc;
}
CCacheBlk *DskCacheFind(CDrv *dv,I64 blk)
{
CCacheBlk *tmpc,*tmpc1=DskCacheHash(blk);
tmpc=tmpc1->next_hash;
while (tmpc!=tmpc1) {
if (tmpc->dv==dv && tmpc->blk==blk)
return tmpc;
tmpc=tmpc->next_hash;
}
return NULL;
}
U0 DskCacheAdd(CDrv *dv,U8 *buf, I64 blk, I64 cnt)
{
CCacheBlk *tmpc;
if (blkdev.cache_base) {
while (LBts(&sys_semas[SEMA_DSK_CACHE],0))
Yield;
while (cnt-->0) {
if (!(tmpc=DskCacheFind(dv,blk)))
tmpc=blkdev.cache_ctrl->next_lru;
DskCacheQueRem(tmpc);
MemCpy(&tmpc->body,buf,BLK_SIZE);
tmpc->dv=dv;
tmpc->blk=blk;
DskCacheQueIns(tmpc);
blk++;
buf+=BLK_SIZE;
}
LBtr(&sys_semas[SEMA_DSK_CACHE],0);
}
}
U0 DskCacheInvalidate2(CDrv *dv)
{
CCacheBlk *tmpc,*tmpc1;
if (blkdev.cache_base) {
while (LBts(&sys_semas[SEMA_DSK_CACHE],0))
Yield;
tmpc=blkdev.cache_ctrl->last_lru;
while (tmpc!=blkdev.cache_ctrl) {
tmpc1=tmpc->last_lru;
if (tmpc->dv==dv) {
DskCacheQueRem(tmpc);
tmpc->dv=NULL;
tmpc->blk=0;
tmpc->next_hash=tmpc->last_hash=tmpc;
QueIns(tmpc,blkdev.cache_ctrl->last_lru);
}
tmpc=tmpc1;
}
LBtr(&sys_semas[SEMA_DSK_CACHE],0);
}
}
U0 RCache(CDrv *dv,U8 **_buf, I64 *_blk, I64 *_cnt)
{
CCacheBlk *tmpc;
if (blkdev.cache_base) {
while (LBts(&sys_semas[SEMA_DSK_CACHE],0))
Yield;
//fetch leading blks from cache
while (*_cnt>0) {
if (tmpc=DskCacheFind(dv,*_blk)) {
MemCpy(*_buf,&tmpc->body,BLK_SIZE);
*_cnt-=1;
*_buf+=BLK_SIZE;
*_blk+=1;
} else
break;
}
//fetch trailing blks from cache
while (*_cnt>0) {
if (tmpc=DskCacheFind(dv,*_blk+*_cnt-1)) {
MemCpy(*_buf+(*_cnt-1)<<BLK_SIZE_BITS,&tmpc->body,BLK_SIZE);
*_cnt-=1;
} else
break;
}
LBtr(&sys_semas[SEMA_DSK_CACHE],0);
}
}
+151
View File
@@ -0,0 +1,151 @@
I64 ClusterNumNext(CDrv *dv,I64 c,I64 cnt=1)
{//Return next cnt'th cluster in chain.
Bool unlock;
DrvChk(dv);
if (cnt<=0) return c;
try {
unlock=DrvLock(dv);
switch (dv->fs_type) {
case FSt_ISO9660:
case FSt_REDSEA:
c+=cnt;
break;
case FSt_FAT32:
while (cnt-->0 && 0<c<0x0FFFFFF8) {
DrvFATBlkSet(dv,c);
c=dv->cur_fat_blk[c & (BLK_SIZE/4-1)];
}
if (!(0<c<0x0FFFFFF8))
c=INVALID_CLUSTER;
break;
default:
throw('Drv');
}
if (unlock)
DrvUnlock(dv);
} catch
if (unlock)
DrvUnlock(dv);
return c;
}
I64 Cluster2Blk(CDrv *dv,I64 c)
{//Drv cluster num to blk num.
DrvChk(dv);
switch (dv->fs_type) {
case FSt_REDSEA:
return c;
case FSt_ISO9660:
case FSt_FAT32:
return dv->data_area+c*dv->spc;
default:
throw('Drv');
}
}
I64 RClustersBlks(CDrv *dv,U8 *buf,I64 c,I64 blks)
{//Accepts blk count, so padding on last cluster is not read.
I64 i;
Bool unlock;
DrvChk(dv);
if (blks<=0) return c;
try {
unlock=DrvLock(dv);
switch (dv->fs_type) {
case FSt_ISO9660:
RBlks(dv,buf,dv->data_area+c*dv->spc,blks);
c+=(blks+dv->spc-1)/dv->spc;
break;
case FSt_REDSEA:
RBlks(dv,buf,c,blks);
c+=blks;
break;
case FSt_FAT32:
while (blks && 0<c<0x0FFFFFF8) {
i=blks;
if (i>dv->spc)
i=dv->spc;
RBlks(dv,buf,dv->data_area+c*dv->spc,i);
buf+=i<<BLK_SIZE_BITS;
c=ClusterNumNext(dv,c,1);
blks-=i;
}
if (blks)
throw('Drv');
break;
default:
throw('Drv');
}
if (unlock)
DrvUnlock(dv);
} catch
if (unlock)
DrvUnlock(dv);
return c;
}
I64 RClusters(CDrv *dv,U8 *buf,I64 c,I64 cnt)
{//Read cluster cnt from drv to buf.
return RClustersBlks(dv,buf,c,cnt*dv->spc);
}
I64 WClustersBlks(CDrv *dv,U8 *buf,I64 c,I64 blks)
{//Accepts blk count, so padding on last cluster is not written.
I64 i;
Bool unlock;
DrvChk(dv);
if (blks<=0) return c;
try {
unlock=DrvLock(dv);
switch (dv->fs_type) {
case FSt_REDSEA:
WBlks(dv,buf,c,blks);
c=0;
break;
case FSt_FAT32:
while (blks) {
if (!(0<c<0x0FFFFFF8))
throw('Drv');
i=blks;
if (i>dv->spc)
i=dv->spc;
WBlks(dv,buf,dv->data_area+c*dv->spc,i);
buf+=i<<BLK_SIZE_BITS;
c=ClusterNumNext(dv,c);
blks-=i;
}
break;
default:
throw('Drv');
}
if (unlock)
DrvUnlock(dv);
} catch
if (unlock)
DrvUnlock(dv);
return c;
}
I64 WClusters(CDrv *dv,U8 *buf,I64 c,I64 cnt)
{//Write cluster cnt from buf to drv.
return WClustersBlks(dv,buf,c,cnt*dv->spc);
}
I64 ClustersAlloc(CDrv *dv,I64 c=0,I64 cnt=1,Bool contiguous=FALSE)
{//Alloc cluster cnt into chain.
//c=0 means first cluster in chain
DrvChk(dv);
if (cnt<=0) return c;
switch (dv->fs_type) {
case FSt_REDSEA:
return RedSeaAllocClusters(dv,cnt);
case FSt_FAT32:
if (contiguous) {
if (c) throw('File');
return FAT32AllocContiguousClusters(dv,cnt);
} else
return FAT32AllocClusters(dv,c,cnt);
default:
throw('Drv');
}
}
+106
View File
@@ -0,0 +1,106 @@
Bool CopySingleZ(U8 *f1,U8 *f2) //Just one file
{
U8 *file_buf=NULL;
I64 size,attr=0,c;
CDirEntry de;
if (FileFind(f1,&de,FUF_JUST_FILES)) {
Free(de.full_name);
file_buf=FileRead(f1,&size,&attr);
attr=FileAttr(f2,attr);
if (file_buf) {
"Copying %s to %s\n",f1,f2;
c=FileWrite(f2,file_buf,size,de.datetime,attr);
Free(file_buf);
return ToBool(c);
} else
PrintErr("File not found.\n");
} else
PrintErr("File not found.\n");
return FALSE;
}
#define COPY_BUF_BLKS 0x80
Bool CopySingle(U8 *f1,U8 *f2) //Just one file
{
U8 *absf1=FileNameAbs(f1),*absf2=FileNameAbs(f2),*buf;
I64 cnt,n,size,attr1=FileAttr(f1),attr2=FileAttr(f2),i,j;
CFile *in_file=NULL,*out_file=NULL;
if (!StrCmp(absf1,absf2)) {//onto self?
Free(absf1);
Free(absf2);
return FALSE;
}
Free(absf1);
Free(absf2);
if (attr1!=attr2)
return CopySingleZ(f1,f2);
buf=MAlloc(COPY_BUF_BLKS<<BLK_SIZE_BITS);
if (attr1 & RS_ATTR_CONTIGUOUS)
in_file=FOpen(f1,"rc");
else
in_file=FOpen(f1,"r");
if (in_file) {
size=FSize(in_file);
cnt=(size+BLK_SIZE-1)>>BLK_SIZE_BITS;
if (attr2 & RS_ATTR_CONTIGUOUS)
out_file=FOpen(f2,"wc",cnt);
else
out_file=FOpen(f2,"w",cnt);
if (out_file) {
"Copying %s to %s\n",f1,f2;
j=size;
while (cnt>0) {
if (cnt>COPY_BUF_BLKS) {
n=COPY_BUF_BLKS;
i=n<<BLK_SIZE_BITS;
} else {
n=cnt;
i=j;
}
FRBlks(in_file, buf,FFB_NEXT_BLK,n);
FWBlks(out_file,buf,FFB_NEXT_BLK,n);
cnt-=n;
j-=n<<BLK_SIZE_BITS;
}
out_file->flags|=FF_USE_OLD_DATETIME;
out_file->de.datetime=in_file->de.datetime;
out_file->de.size=size;
out_file->de.attr=FileAttr(f2,in_file->de.attr);
FClose(out_file);
FClose(in_file);
Free(buf);
return TRUE;
} else
PrintErr("File not found.\n");
FClose(in_file);
} else
PrintErr("File not found.\n");
Free(buf);
return FALSE;
}
I64 Del(U8 *files_find_mask,Bool make_mask=FALSE,
Bool del_dir=FALSE,Bool print_msg=TRUE)
{//Delete files.
I64 res=0;
CDirContext *dirc;
if (dirc=DirContextNew(files_find_mask,make_mask)) {
switch (dirc->dv->fs_type) {
case FSt_REDSEA:
res=RedSeaFilesDel(dirc->dv,Fs->cur_dir,dirc->mask,
0,del_dir,print_msg);
break;
case FSt_FAT32:
res=FAT32FilesDel(dirc->dv,Fs->cur_dir,dirc->mask,
0,del_dir,print_msg);
break;
case FSt_ISO9660:
PrintErr("Not Writable\n");
break;
default:
PrintErr("File System Not Supported\n");
}
DirContextDel(dirc);
}
return res;
}
+214
View File
@@ -0,0 +1,214 @@
Bool DirNew(CDrv *dv,U8 *cur_dir,CDirEntry *tmpde,Bool free_old_chain=TRUE)
{//Makes a directory entry in the directory from a $LK,"CDirEntry",A="MN:CDirEntry"$ node.
switch (dv->fs_type) {
case FSt_REDSEA:
return RedSeaDirNew(dv,cur_dir,tmpde,free_old_chain);
case FSt_FAT32:
return FAT32DirNew(dv,cur_dir,tmpde,free_old_chain);
case FSt_ISO9660:
PrintErr("Not Writable\n");
return FALSE;
default:
PrintErr("File System Not Supported\n");
return FALSE;
}
}
U0 DirEntryDel(CDirEntry *tmpde)
{//Free node returned from $LK,"FilesFind",A="MN:FilesFind"$(). Doesn't Free user_data.
//Does not change the directory on disk.
if (tmpde) {
Free(tmpde->full_name);
Free(tmpde);
}
}
U0 DirEntryDel2(CDirEntry *tmpde)
{//Free node returned from $LK,"FilesFind",A="MN:FilesFind"$(). Frees user_data
//Does not change the directory on disk.
if (tmpde) {
Free(tmpde->full_name);
Free(tmpde->user_data);
Free(tmpde);
}
}
U0 DirTreeDel(CDirEntry *tmpde)
{//Free tree returned from $LK,"FilesFind",A="MN:FilesFind"$(). Doesn't Free user_data.
//Does not change the directory on disk.
CDirEntry *tmpde2;
while (tmpde) {
tmpde2=tmpde->next;
if (tmpde->sub)
DirTreeDel(tmpde->sub);
DirEntryDel(tmpde);
tmpde=tmpde2;
}
}
U0 DirTreeDel2(CDirEntry *tmpde)
{//Free tree returned from $LK,"FilesFind",A="MN:FilesFind"$(). Frees user_data
//Does not change the directory on disk.
CDirEntry *tmpde2;
while (tmpde) {
tmpde2=tmpde->next;
if (tmpde->sub)
DirTreeDel2(tmpde->sub);
DirEntryDel2(tmpde);
tmpde=tmpde2;
}
}
I64 DirEntryCompareName(CDirEntry *e1,CDirEntry *e2)
{
U8 buf1[CDIR_FILENAME_LEN],buf2[CDIR_FILENAME_LEN],
buf3[CDIR_FILENAME_LEN],buf4[CDIR_FILENAME_LEN];
I64 d1=0,d2=0;
if (e1->attr & RS_ATTR_DIR)
d1=1;
if (e2->attr & RS_ATTR_DIR)
d2=1;
if (d1!=d2)
return d2-d1;
else {
StrCpy(buf1,e1->name);
StrCpy(buf2,e2->name);
FileExtRem(buf1,buf3);
FileExtRem(buf2,buf4);
if (d1=StrCmp(buf3,buf4))
return d1;
return StrCmp(buf1,buf2);
}
}
I64 DirEntryCompareCluster(CDirEntry *e1,CDirEntry *e2)
{
return e1->cluster-e2->cluster;
}
#define SK_NAME 0
#define SK_CLUSTER 1
U0 DirFilesSort(CDirEntry **_tmpde,I64 key)
{
I64 i,cnt;
CDirEntry *tmpde=*_tmpde,*tmpde1,**sort_buf;
if (tmpde) {
cnt=LinkedLstCnt(tmpde);
if (cnt>1) {
sort_buf=MAlloc(cnt*sizeof(U8 *));
i=0;
tmpde1=tmpde;
while (tmpde1) {
sort_buf[i++]=tmpde1;
tmpde1=tmpde1->next;
}
switch [key] {
case SK_NAME:
QSortI64(sort_buf,cnt,&DirEntryCompareName);
break;
case SK_CLUSTER:
QSortI64(sort_buf,cnt,&DirEntryCompareCluster);
break;
}
tmpde=sort_buf[0];
*_tmpde=tmpde;
for (i=0;i<cnt-1;i++) {
tmpde1=sort_buf[i];
tmpde1->next=sort_buf[i+1];
}
tmpde1=sort_buf[i];
tmpde1->next=NULL;
Free(sort_buf);
tmpde1=tmpde;
while (tmpde1) {
if (tmpde1->sub)
DirFilesSort(&tmpde1->sub,key);
tmpde1=tmpde1->next;
}
} else
if (tmpde->sub)
DirFilesSort(&tmpde->sub,key);
}
}
CDirEntry *DirFilesFlatten(CDirEntry *tmpde,CDirEntry **_res,I64 fuf_flags)
{//Returns last node
CDirEntry *tmpde1;
Bool del;
if (tmpde)
while (TRUE) {
tmpde1=tmpde->next;
if (!(tmpde->attr&RS_ATTR_DIR)||!(fuf_flags&FUF_JUST_FILES)) {
_res=*_res=tmpde;
del=FALSE;
} else
del=TRUE;
if (tmpde->sub) {
_res=DirFilesFlatten(tmpde->sub,_res,fuf_flags);
tmpde->sub=NULL;
}
if (del)
DirEntryDel(tmpde);
if (tmpde1)
tmpde=tmpde1;
else
break;
}
*_res=NULL;
return _res;
}
U0 PutFileLink(U8 *filename,U8 *full_name=NULL,I64 line=0,Bool plain_text=FALSE)
{//Put $LK,"DolDoc",A="FI:::/Doc/DolDocOverview.DD"$ file,line link to StdOut, $LK,"DocPut",A="MN:DocPut"$.
U8 *st;
if (!filename) return;
if (IsRaw) {
if (line)
"%s,%04d",filename,line;
else
"%s",filename;
} else {
//LK_DOC,LK_DOC_ANCHOR,LK_DOC_FIND,LK_DOC_LINE
if (filename[0]=='A'&&filename[2]==':') {
if (line) //See $LK,"SpriteEdText",A="MN:SpriteEdText"$()
"$$LK,\"%s,%04d\",A=\"AL:%s,%d\"$$",filename+3,line,filename+3,line;
else
"$$LK,\"%s\",A=\"AI:%s\"$$",filename+3,filename+3;
} else {
if (!full_name)
full_name=st=FileNameAbs(filename);
else
st=NULL;
if (plain_text) {
if (line)
"$$LK,\"%s,%04d\",A=\"PL:%s,%d\"$$",filename,line,full_name,line;
else
"$$LK,\"%s\",A=\"PI:%s\"$$",filename,full_name;
} else {
if (line)
"$$LK,\"%s,%04d\",A=\"FL:%s,%d\"$$",filename,line,full_name,line;
else
"$$LK,\"%s\",A=\"FI:%s\"$$",filename,full_name;
}
Free(st);
}
}
}
U0 PutDirLink(U8 *dirname,U8 *full_name=NULL)
{//Put $LK,"DolDoc",A="FI:::/Doc/DolDocOverview.DD"$ dir macro to StdOut, $LK,"DocPut",A="MN:DocPut"$.
U8 *st;
if (!dirname) return;
if (IsRaw)
"%s",dirname;
else {
if (!full_name)
full_name=st=DirNameAbs(dirname);
else
st=NULL;
"$$MA,T=\"%s\",LM=\"Cd(\\\"%s\\\");Dir;\n\"$$",dirname,full_name;
Free(st);
}
}
+200
View File
@@ -0,0 +1,200 @@
U0 HomeSet(U8 *dirname)
{//Change home directory.
dirname=DirNameAbs(dirname);
Free(blkdev.home_dir);
blkdev.home_dir=AStrNew(dirname);
Free(dirname);
}
Bool Cd(U8 *dirname=NULL,Bool make_dirs=FALSE)
{//Change directory. Optionally, make directories, too.
I64 maxlen,cur_dir_cluster=0;
U8 *chg_to_buf,*new_cur_dir,*buf;
CDrv *dv;
Bool res=TRUE;
if (!dirname)
dirname="~";
else if (!*dirname)
return TRUE;
if (dirname[1]==':') {
if (*dirname==':') {
if (Fs->cur_dv!=Let2Drv(':') && !Drv(*dirname))
return FALSE;
} else if (Fs->cur_dv!=Let2Drv(*dirname) && !Drv(*dirname))
return FALSE;
dirname+=2;
}
if (*dirname=='/' || !*dirname || !Fs->cur_dir) {
Free(Fs->cur_dir);
Fs->cur_dir=StrNew("/");
if (*dirname=='/')
dirname++;
}
chg_to_buf=MStrUtil(dirname,
SUF_REM_LEADING|SUF_REM_TRAILING|SUF_REM_CTRL_CHARS);
maxlen=StrLen(Fs->cur_dir)+1+StrLen(chg_to_buf)+1;
new_cur_dir=MAlloc(maxlen);
buf=MAlloc(maxlen);
StrCpy(new_cur_dir,Fs->cur_dir);
while (*chg_to_buf && res) {
StrFirstRem(chg_to_buf,"/",buf);
if (!*buf)
StrCpy(new_cur_dir,"/");
else if (!StrCmp(buf,"..")) {
StrLastRem(new_cur_dir,"/");
if (!*new_cur_dir)
StrCpy(new_cur_dir,"/");
} else if (!StrCmp(buf,"~")) {
Free(new_cur_dir);
new_cur_dir=MAlloc(StrLen(blkdev.home_dir+2)+1+StrLen(chg_to_buf)+1);
StrCpy(new_cur_dir,blkdev.home_dir+2);
if (Fs->cur_dv!=Let2Drv('~') && !Drv('~'))
return FALSE;
} else if (StrCmp(buf,".") && *buf) {
dv=Fs->cur_dv;
cur_dir_cluster=Name2DirCluster(dv,new_cur_dir);
switch (dv->fs_type) {
case FSt_REDSEA:
res=RedSeaCd(buf,cur_dir_cluster);
break;
case FSt_FAT32:
res=FAT32Cd(buf,cur_dir_cluster);
break;
case FSt_ISO9660:
res=ISO1Cd(buf,cur_dir_cluster);
break;
default:
PrintErr("File System Not Supported\n");
res=FALSE;
}
if (!res && make_dirs) {
Free(Fs->cur_dir);
Fs->cur_dir=StrNew(new_cur_dir);
res=MkDir(buf);
}
if (res) {
if (StrCmp(new_cur_dir,"/"))
CatPrint(new_cur_dir,"/");
CatPrint(new_cur_dir,buf);
}
}
}
Free(Fs->cur_dir);
Fs->cur_dir=StrNew(new_cur_dir);
Free(buf);
Free(chg_to_buf);
Free(new_cur_dir);
return res;
}
Bool IsDir(U8 *dir_name)
{//Is a str a valid, existing Dir?
U8 *mask=MStrPrint("%s/*",dir_name);
Bool res,old_silent=Silent;
CDirContext *dirc;
if (dirc=DirContextNew(mask)) {
DirContextDel(dirc);
res=TRUE;
} else
res=FALSE;
Free(mask);
Silent(old_silent);
return res;
}
I64 Dir(U8 *files_find_mask,Bool full)
{//List directory.
CDirEntry *tmpde1=NULL,*tmpde2;
U8 *st;
CDateStruct ds;
I64 csize=0xFFFF,c=0xFFFF,res=0;
tmpde1=FilesFind(files_find_mask);
if (!(st=CurDir))
PrintErr("Invalid Drive\n");
else {
if (tmpde1) {
Free(st);
st=MAllocIdent(tmpde1->full_name);
StrLastRem(st,"/");
if (!st[2])
StrCpy(st+2,"/");
//Find max columns
tmpde2=tmpde1;
while (tmpde2) {
if (tmpde2->size>csize)
csize=tmpde2->size;
if (tmpde2->cluster>c)
c=tmpde2->cluster;
tmpde2=tmpde2->next;
}
csize=Bsr(csize)/4+1;
c=Bsr(c)/4+1;
"$$MA,T=\"Directory\",LM=\"PopUpCd;Dir;\n\"$$ of %s\n",st;
if (full)
"__DATE__ __TIME__ %*ts %*ts\n",
csize,"SIZE",c,"CLUSTER";
else
"DATE_ TIME_ %*ts\n",csize,"SIZE";
while (tmpde1) {
tmpde2=tmpde1->next;
res++;
if (full)
"%D %T %0*tX %0*tX ",tmpde1->datetime,tmpde1->datetime,
csize,tmpde1->size,c,tmpde1->cluster;
else {
Date2Struct(&ds,tmpde1->datetime+local_time_offset);
"%02d/%02d %02d:%02d %0*tX ",ds.mon,ds.day_of_mon,ds.hour,ds.min,
csize,tmpde1->size;
}
if (tmpde1->attr & RS_ATTR_DIR)
PutDirLink(tmpde1->name,tmpde1->full_name);
else
PutFileLink(tmpde1->name,tmpde1->full_name);
'\n';
DirEntryDel(tmpde1);
tmpde1=tmpde2;
}
} else
"No matching entries\n";
Free(st);
}
return res;
}
Bool MkDir(U8 *filename,I64 entry_cnt=0)
{//Make directory. $LK,"Cd",A="MN:Cd"$() can also make directories.
//entry_cnt is for preallocating dir blks, leave it zero if you like.
U8 *name;
CDirContext *dirc;
Bool res=FALSE;
if (FileFind(filename,,FUF_JUST_DIRS))
return FALSE;
if (dirc=DirContextNew(filename)) {
if (*dirc->mask) {
if (!FileNameChk(dirc->mask))
PrintErr("Invalid FileName.\n");
else {
"Make Directory:%s\n",filename;
name=MStrUtil(dirc->mask,
SUF_REM_LEADING|SUF_REM_TRAILING|SUF_REM_CTRL_CHARS);
switch (dirc->dv->fs_type) {
case FSt_REDSEA:
res=RedSeaMkDir(dirc->dv,Fs->cur_dir,name,entry_cnt);
break;
case FSt_FAT32:
res=FAT32MkDir(dirc->dv,Fs->cur_dir,name,entry_cnt);
break;
case FSt_ISO9660:
PrintErr("Not Writable\n");
break;
default:
PrintErr("File System Not Supported\n");
}
Free(name);
}
}
DirContextDel(dirc);
}
return res;
}
+87
View File
@@ -0,0 +1,87 @@
U0 DirContextDel(CDirContext *dirc,Bool restore=TRUE)
{//Change back to old cur_dir and drv.
CBlkDev *bd;
if (!dirc) return;
if (restore) {
bd=dirc->old_dv->bd;
if (!(bd->flags & BDF_INIT_IN_PROGRESS)) {
if (dirc->old_dir) {
Drv(Drv2Let(dirc->old_dv));
Cd(dirc->old_dir);
}
} else {
Fs->cur_dv=dirc->old_dv;
Free(Fs->cur_dir);
Fs->cur_dir=StrNew("/");
}
}
Free(dirc->old_dir);
Free(dirc->mask);
Free(dirc);
}
CDirContext *DirContextNew(U8 *_mask,Bool make_mask=FALSE,
Bool make_dirs=FALSE,Bool no_mask=FALSE)
{//Save cur_dir and drv. Change to new dir.
Bool valid=TRUE,old_silent;
I64 mask_len=StrLen(_mask);
U8 *buf,*mask,*tmp_mask,*semicolon_mask;
CDirContext *dirc=CAlloc(sizeof(CDirContext));
dirc->old_dir=StrNew(Fs->cur_dir);
dirc->old_dv=Fs->cur_dv;
mask=MStrUtil(_mask,SUF_REM_LEADING|SUF_REM_TRAILING|SUF_REM_CTRL_CHARS);
tmp_mask=mask;
if (*mask && mask[1]==':') {
if (Fs->cur_dv!=Let2Drv(*mask) && !Drv(*mask))
valid=FALSE;
mask+=2;
}
if (*mask=='~' && Fs->cur_dv!=Let2Drv('~') && !Drv('~'))
valid=FALSE;
dirc->dv=Fs->cur_dv;
DrvChk(dirc->dv);
buf=MAlloc(mask_len+2);
StrCpy(buf,mask);
dirc->mask=MAlloc(mask_len+2);
if (no_mask)
*dirc->mask=0;
else if (StrOcc(buf,';')) {
semicolon_mask=MAlloc(mask_len+2);
StrCpy(semicolon_mask,mask);
StrFirstRem(semicolon_mask,";",buf);
StrLastRem(buf,"/",dirc->mask);
CatPrint(dirc->mask,";%s",semicolon_mask);
Free(semicolon_mask);
} else
StrLastRem(buf,"/",dirc->mask);
if (*mask=='/' && !*buf)
StrCpy(buf,"/");
//If began with Dir, change to Dir.
if (*buf && !Cd(buf,make_dirs))
valid=FALSE;
if (valid && make_mask) {
if (!*dirc->mask) {
Free(dirc->mask);
dirc->mask=StrNew("*");
} else {
if (!make_dirs || FileNameChk(dirc->mask)) {
old_silent=Silent;
//Try mask to see if Dir. If Dir, change to dir and set to "*".
if (Cd(dirc->mask,make_dirs)) {
Free(dirc->mask);
dirc->mask=StrNew("*");
}
Silent(old_silent);
}
}
}
Free(buf);
Free(tmp_mask);
if (!valid) {
DirContextDel(dirc);
dirc=NULL;
}
return dirc;
}
+367
View File
@@ -0,0 +1,367 @@
Bool DrvLock(CDrv *dv)
{//Make this task have exclusive access to drv & BlkDev.
DrvChk(dv);
BlkDevLock(dv->bd);
if (!Bt(&dv->locked_flags,DVlf_LOCKED) || dv->owning_task!=Fs) {
while (LBts(&dv->locked_flags,DVlf_LOCKED))
Yield;
dv->owning_task=Fs;
return TRUE;
} else
return FALSE;
}
Bool DrvUnlock(CDrv *dv,Bool rst=FALSE)
{//Release exclusive lock on access to drv & BlkDev.
DrvChk(dv);
if (Bt(&dv->locked_flags,DVlf_LOCKED) && dv->owning_task==Fs) {
BlkDevUnlock(dv->bd,rst);
dv->owning_task=NULL;
LBtr(&dv->locked_flags,DVlf_LOCKED);
Yield; //Prevent deadlock
return TRUE;
} else
return FALSE;
}
U0 DrvsRelease()
{//When task dies, release all owned drvs.
I64 i;
CDrv *dv;
for (i=0;i<DRVS_NUM;i++) {
dv=&blkdev.drvs[i];
if (dv->owning_task==Fs && dv->dv_signature==DRV_SIGNATURE_VAL)
DrvUnlock(dv,TRUE);
}
}
CDrv *DrvMakeFreeSlot(U8 drv_let)
{//Make a slot free for a new drv, like during $LK,"Mount",A="MN:Mount"$().
//!!! drv_let is not a $LK,"remapped",A="MN:DrvMap"$ drv.
I64 i=Let2Let(drv_let)-'A';
CDrv *res;
if (!(0<=i<DRVS_NUM))
throw('Drv');
res=&blkdev.drvs[i];
MemSet(res,0,sizeof(CDrv));
res->drv_let='A'+i;
return res;
}
U8 DrvNextFreeLet(U8 first_drv_let='C')
{//Locate free slot for new drv, like during $LK,"Mount",A="MN:Mount"$().
//!!! first_drv_let is not a $LK,"remapped",A="MN:DrvMap"$ drv.
I64 i=Let2Let(first_drv_let)-'A',type=Let2BlkDevType(first_drv_let);
if (!(0<=i<DRVS_NUM))
throw('Drv');
do
if (blkdev.drvs[i].dv_signature!=DRV_SIGNATURE_VAL) {
if (Let2BlkDevType(i+'A')!=type)
throw('Drv');
else
return i+'A';
}
while (++i<DRVS_NUM);
throw('Drv');
return 0; //Never gets here.
}
U0 DrvDel(CDrv *dv)
{//Delete drv
if (dv->fs_type==FSt_REDSEA && dv->next_free)
RedSeaFreeFreeLst(dv);
Free(dv->cur_fat_blk);
Free(dv->fis);
MemSet(dv,0,sizeof(CDrv));
}
U0 DrvBlkDevDel(CBlkDev *bd)
{//Delete drv's of BlkDev
I64 i;
CDrv *dv;
for (i=0;i<DRVS_NUM;i++) {
dv=&blkdev.drvs[i];
if (dv->bd==bd)
DrvDel(dv);
}
}
U0 DrvFATBlkAlloc(CDrv *dv)
{
DrvChk(dv);
Free(dv->cur_fat_blk);
dv->cur_fat_blk=AMAlloc(BLK_SIZE);
dv->cur_fat_blk_num=0;
dv->fat_blk_dirty=0;
RBlks(dv,dv->cur_fat_blk,dv->fat1,1);
}
U0 DrvFATBlkClean(CDrv *dv,I64 fat_sel=3)
{
if ((dv->fs_type==FSt_FAT32 || dv->fs_type==FSt_REDSEA) &&
Bt(&dv->fat_blk_dirty,0)) {
if (dv->fat1==dv->fat2) {
WBlks(dv,dv->cur_fat_blk,dv->fat1+dv->cur_fat_blk_num,1);
LBtr(&dv->fat_blk_dirty,0);
} else {
if (fat_sel==3 || !fat_sel)
WBlks(dv,dv->cur_fat_blk,dv->fat1+dv->cur_fat_blk_num,1);
if (fat_sel==3 || fat_sel==1) {
WBlks(dv,dv->cur_fat_blk,dv->fat2+dv->cur_fat_blk_num,1);
LBtr(&dv->fat_blk_dirty,0);
}
}
}
}
U0 DrvFATBlkSet(CDrv *dv,I64 c,I64 fat_sel=3)
{
I64 fat_blk_num;
if (c==INVALID_CLUSTER)
throw('Drv');
switch (dv->fs_type) {
case FSt_FAT32:
fat_blk_num=c>>(BLK_SIZE_BITS-2);
break;
case FSt_REDSEA:
fat_blk_num=(c-dv->data_area)>>(BLK_SIZE_BITS+3);
break;
default:
throw('Drv');
}
if (fat_blk_num!=dv->cur_fat_blk_num) {
DrvFATBlkClean(dv,fat_sel);
dv->cur_fat_blk_num=fat_blk_num;
if (fat_sel==3 || !fat_sel)
RBlks(dv,dv->cur_fat_blk,dv->fat1+dv->cur_fat_blk_num,1);
else
RBlks(dv,dv->cur_fat_blk,dv->fat2+dv->cur_fat_blk_num,1);
}
}
CDrv *DrvChk(CDrv *dv,Bool except=TRUE)
{//Check for valid drv. Throw exception.
if (!dv || dv->dv_signature!=DRV_SIGNATURE_VAL) {
if (except)
throw('Drv');
else
return NULL;
} else
return dv;
}
U8 Drv2Let(CDrv *dv=NULL)
{//Drv ptr to Drv letter.
if (!dv)
dv=Fs->cur_dv;
DrvChk(dv);
return dv->drv_let;
}
U8 Let2Let(U8 drv_let=0)
{//Drv letter to Drv letter.
if (!drv_let)
drv_let=Drv2Let(Fs->cur_dv);
else if (drv_let==':')
drv_let=blkdev.boot_drv_let;
else if (drv_let=='~')
drv_let=*blkdev.home_dir;
return ToUpper(drv_let);
}
I64 Let2BlkDevType(U8 drv_let)
{//Drv letter to BlkDev Type. drv_let=0 not allowed. See $LK,"BDT_NULL",A="MN:BDT_NULL"$.
drv_let=Let2Let(drv_let);
if ('A'<=drv_let<='B')
return BDT_RAM;
if ('C'<=drv_let<='L')
return BDT_ATA;
if ('M'<=drv_let<='P')
return BDT_ISO_FILE_READ;
if ('Q'<=drv_let<='S')
return BDT_ISO_FILE_WRITE;
if ('T'<=drv_let<='Z')
return BDT_ATAPI;
return BDT_NULL;
}
CDrv *Let2Drv(U8 drv_let=0,Bool except=TRUE)
{//Drv letter to Drv ptr.
CDrv *dv;
if (!drv_let)
dv=Fs->cur_dv;
else {
drv_let=Let2Let(drv_let);
if (!('A'<=drv_let<='Z')) {
if (except)
throw('Drv');
else
return NULL;
}
dv=blkdev.let_to_drv[drv_let-'A'];
}
return DrvChk(dv,except);
}
CBlkDev *DrvIsWritable(U8 drv_let=0,Bool except=FALSE)
{//Is drive writable?
CBlkDev *bd;
if (!(bd=Let2BlkDev(drv_let,except)) || bd->flags & BDF_READ_ONLY) {
if (except)
throw('Drv');
else
return NULL;
} else
return bd;
}
U0 DskCacheInvalidate(CDrv *dv)
{//Needed for removable media. Called by $LK,"ChgDsk",A="MN:ChgDsk"$().
Bool unlock;
CBlkDev *bd=dv->bd;
DrvChk(dv);
try {
unlock=DrvLock(dv);
BlkDevInit(bd);
if (bd->flags & BDF_READ_CACHE)
DskCacheInvalidate2(dv);
if (bd->type==BDT_ATAPI && !(bd->flags & BDF_READ_ONLY_OVERRIDE))
ISOInit(dv,(32767/bd->blk_size+1)*bd->blk_size>>BLK_SIZE_BITS);
if (unlock)
DrvUnlock(dv);
} catch
if (unlock)
DrvUnlock(dv);
}
U0 ChgDsk(U8 drv_let=0)
{//Change disk. (Needed for removable media.)
CDrv *dv=Let2Drv(drv_let);
CBlkDev *bd=dv->bd;
if (!(bd->flags&BDF_INITIALIZED))
BlkDevInit(bd);
else if (bd->flags&BDF_REMOVABLE) {
if (bd->type==BDT_ATAPI)
ATAInit(bd); //TODO: This is a kludge for QEMU?
DskCacheInvalidate(dv);
}
Drv(drv_let);
RedSeaFreeFreeLst(dv);
}
Bool DrvMap(U8 drv_let,CDrv *dv)
{//Make drive letter map to another.
drv_let=Let2Let(drv_let);
if ('A'<=drv_let<='Z') {
blkdev.let_to_drv[drv_let-'A']=dv;
dv->drv_let=drv_let;
return TRUE;
} else
return FALSE;
}
Bool Drv(U8 drv_let)
{//Change drive. You can set drive with $LK,"Cd",A="MN:Cd"$() as well.
CDrv *dv=Let2Drv(drv_let);
CBlkDev *bd;
bd=BlkDevChk(dv->bd);
if (dv!=Fs->cur_dv) {
if (bd->flags & BDF_REMOVABLE && !(bd->flags & BDF_INITIALIZED))
ChgDsk(Drv2Let(dv));
if (bd->type==BDT_RAM ||
bd->type==BDT_ISO_FILE_READ || bd->type==BDT_ISO_FILE_WRITE)
BlkDevInit(bd);
}
Fs->cur_dv=dv;
Free(Fs->cur_dir);
Fs->cur_dir=StrNew("/");
switch (dv->fs_type) {
case FSt_REDSEA:
case FSt_FAT32:
case FSt_ISO9660:
return TRUE;
default:
PrintErr("File System Not Supported\n");
return FALSE;
}
}
U8 *DrvSerialNum(U8 drv_let=0)
{//20 bytes max.
CBlkDev *bd=Let2BlkDev(drv_let);
U16 *st,*res=NULL;
I64 i;
if (bd->dev_id_record) {
st=CAlloc(20+1);
for (i=0;i<10;i++)
st[i]=EndianU16(bd->dev_id_record[10+i]);
res=MStrUtil(st,SUF_REM_LEADING|SUF_REM_TRAILING);
Free(st);
}
return res;
}
U8 *DrvModelNum(U8 drv_let=0)
{//40 bytes max.
CBlkDev *bd=Let2BlkDev(drv_let);
U16 *st,*res=NULL;
I64 i;
if (bd->dev_id_record) {
st=CAlloc(40+1);
for (i=0;i<20;i++)
st[i]=EndianU16(bd->dev_id_record[27+i]);
res=MStrUtil(st,SUF_REM_LEADING|SUF_REM_TRAILING);
Free(st);
}
return res;
}
U8 blkdev_text_attr[BDT_TYPES_NUM]={BLACK,LTCYAN,WHITE,LTGREEN,LTRED,LTBLUE};
U8 drv_text_attr[3]={BLACK,BLUE,RED};
U8 DrvTextAttrGet(U8 drv_let=0)
{//Get color of drive.
drv_let=Let2Let(drv_let);
if ('A'<=drv_let<='Z')
return blkdev_text_attr[Let2BlkDevType(drv_let)]<<4|
drv_text_attr[drv_let%sizeof(drv_text_attr)];
else
return BLACK<<4|WHITE;
}
U0 DrvRep()
{//Drive report.
CDrv *dv;
CBlkDev *bd;
I64 ch,i,drv_let,attr;
U8 *st;
"\nDefined Drives:\n";
for (i=0,dv=blkdev.drvs;i<DRVS_NUM;i++,dv++) {
if (dv->dv_signature==DRV_SIGNATURE_VAL) {
bd=dv->bd;
drv_let=Drv2Let(dv);
if (Bt(&dv->fs_type,FStf_DISABLE))
ch='-';
else if (drv_let==blkdev.boot_drv_let)
ch=':';
else
ch='+';
attr=DrvTextAttrGet(drv_let);
"$$FG,%d$$$$BG,%d$$%C %-8Z %-10Z %04X %04X %02X\n",
attr&15,attr>>4,drv_let,dv->fs_type&FSG_TYPE_MASK,"ST_DRV_TYPES",
bd->type,"ST_BLKDEV_TYPES",bd->base0,bd->base1,bd->unit;
if (st=DrvModelNum(drv_let)) {
" Model# :%s\n",st;
Free(st);
}
if (st=DrvSerialNum(drv_let)) {
" Serial#:%s\n",st;
Free(st);
}
if (bd->type==BDT_ISO_FILE_READ || bd->type==BDT_ISO_FILE_WRITE)
" File=\"%s\"\n",bd->file_dsk_name;
" %016X-%016X\n$$FG$$$$BG$$",dv->drv_offset,dv->drv_offset+dv->size-1;
}
}
"Home Dir:\"%s\"\n",blkdev.home_dir;
}
+129
View File
@@ -0,0 +1,129 @@
U8 *FileRead(U8 *filename,I64 *_size=NULL,I64 *_attr=NULL)
{//Read whole file from disk.
CHashGeneric *tmph;
U8 *absname,*altname,*curname,*res=NULL;
I64 i,size=0,attr=0;
CDirContext *dirc;
CArcCompress *arc;
absname=FileNameAbs(filename);
altname=ToggleZorNotZ(absname);
if ((tmph=HashFind(absname,adam_task->hash_table,HTT_FILE))||
(tmph=HashFind(altname,adam_task->hash_table,HTT_FILE))) {
size=tmph->user_data1;
res=MAlloc(size+1);
MemCpy(res,tmph->user_data0,size);
res[size]=0; //Terminate
attr=FileAttr(tmph->str,attr);
} else {
for (i=0;i<2 && !res;i++) {//Try name, then altname
if (!i)
curname=absname;
else
curname=altname;
if (dirc=DirContextNew(curname)) {
switch (dirc->dv->fs_type) {
case FSt_REDSEA:
res=RedSeaFileRead(dirc->dv,Fs->cur_dir,dirc->mask,&size,&attr);
break;
case FSt_FAT32:
res=FAT32FileRead(dirc->dv,Fs->cur_dir,dirc->mask,&size,&attr);
break;
case FSt_ISO9660:
res=ISO1FileRead(dirc->dv,Fs->cur_dir,dirc->mask,&size,&attr);
break;
default:
PrintErr("File System Not Supported\n");
}
DirContextDel(dirc);
}
}
//Search parent directories.
for (i=0;i<2 && !res;i++) {//Try name, then altname
if (!i)
curname=absname;
else
curname=altname;
if (dirc=DirContextNew(curname)) {
while (!res && StrCmp(Fs->cur_dir,"/")) {
Cd("..");
switch (Fs->cur_dv->fs_type) {
case FSt_REDSEA:
res=RedSeaFileRead(dirc->dv,Fs->cur_dir,dirc->mask,&size,&attr);
break;
case FSt_FAT32:
res=FAT32FileRead(dirc->dv,Fs->cur_dir,dirc->mask,&size,&attr);
break;
case FSt_ISO9660:
res=ISO1FileRead(dirc->dv,Fs->cur_dir,dirc->mask,&size,&attr);
break;
default:
PrintErr("File System Not Supported\n");
}
}
DirContextDel(dirc);
}
}
if (!res) {
"%s ",filename;
PrintErr("File not found.\n");
}
if (res && attr & RS_ATTR_RESIDENT)
HashGenericAdd(curname,HTT_FILE,AMAllocIdent(res),size,0,adam_task);
}
if (res && attr & RS_ATTR_COMPRESSED) {
arc=res;
size=arc->expanded_size;
res=ExpandBuf(arc);
Free(arc);
}
if (_attr) *_attr=attr;
if (_size) *_size=size;
Free(absname);
Free(altname);
return res;
}
I64 FileWrite(U8 *filename,U8 *fbuf,I64 size,CDate cdt=0,I64 attr=0)
{//Write whole file to disk.
I64 c=0;
CHashGeneric *tmph;
CDirContext *dirc;
U8 *fbuf2,*absname=FileNameAbs(filename);
if (dirc=DirContextNew(filename,FALSE,TRUE)) {
attr=FileAttr(dirc->mask,attr);
if (attr&RS_ATTR_COMPRESSED) {
fbuf=CompressBuf(fbuf,size);
size=fbuf(CArcCompress *)->compressed_size;
fbuf2=fbuf;
} else
fbuf2=NULL;
if (!cdt) cdt=Now;
switch (dirc->dv->fs_type) {
case FSt_REDSEA:
c=RedSeaFileWrite(dirc->dv,Fs->cur_dir,dirc->mask,fbuf,size,cdt,attr);
break;
case FSt_FAT32:
c=FAT32FileWrite(dirc->dv,Fs->cur_dir,dirc->mask,fbuf,size,cdt,attr);
break;
case FSt_ISO9660:
PrintErr("Not Writable\n");
break;
default:
PrintErr("File System Not Supported\n");
}
if (tmph=HashFind(absname,adam_task->hash_table,HTT_FILE)) {
if (attr & RS_ATTR_RESIDENT) {
Free(tmph->user_data0);
tmph->user_data0=AMAllocIdent(fbuf);
tmph->user_data1=size;
} else
HashRemDel(tmph,adam_task->hash_table);
} else if (attr & RS_ATTR_RESIDENT)
HashGenericAdd(absname,HTT_FILE,AMAllocIdent(fbuf),size,0,adam_task);
Free(fbuf2);
DirContextDel(dirc);
}
Free(absname);
return c;
}
+162
View File
@@ -0,0 +1,162 @@
CDirEntry *FilesFind2(U8 *files_find_mask,I64 fuf_flags)
{
CDrv *dv=Fs->cur_dv;
CDirEntry *res=NULL;
DrvChk(dv);
switch (dv->fs_type) {
case FSt_REDSEA:
res=RedSeaFilesFind(files_find_mask,fuf_flags);
break;
case FSt_FAT32:
res=FAT32FilesFind(files_find_mask,fuf_flags);
break;
case FSt_ISO9660:
res=ISO1FilesFind(files_find_mask,fuf_flags);
break;
default:
PrintErr("File System Not Supported\n");
res=NULL;
}
if (res) {
DirFilesSort(&res,SK_NAME);
if (fuf_flags&(FUF_FLATTEN_TREE|FUF_JUST_FILES))
DirFilesFlatten(res,&res,fuf_flags);
if (fuf_flags&FUF_CLUSTER_ORDER)
DirFilesSort(&res,SK_CLUSTER);
}
return res;
}
CDirEntry *FilesFind(U8 *files_find_mask,I64 fuf_flags=0)
{/* See $LK,"::/Doc/FileUtils.DD"$.
Find files and make a directory tree in memory.
When done, you free with $LK,"DirEntryDel",A="MN:DirEntryDel"$(),$LK,"DirEntryDel2",A="MN:DirEntryDel2"$(),
$LK,"DirTreeDel",A="MN:DirTreeDel"$() or $LK,"DirTreeDel2",A="MN:DirTreeDel2"$().
*/
CDirEntry *res;
CDirContext *dirc;
if (fuf_flags&~FUG_FILES_FIND)
throw('FUF');
if (fuf_flags&FUF_SINGLE) {
res=MAlloc(sizeof(CDirEntry));
if (!FileFind(files_find_mask,res)) {
Free(res);
return NULL;
}
} else if (dirc=DirContextNew(files_find_mask,TRUE)) {
res=FilesFind2(dirc->mask,fuf_flags);
DirContextDel(dirc);
} else
return NULL;
return res;
}
Bool FileFind(U8 *filename,CDirEntry *_de=NULL,I64 fuf_flags=0)
{//$LK,"FUF_JUST_DIRS",A="MN:FUF_JUST_DIRS"$, $LK,"FUF_JUST_FILES",A="MN:FUF_JUST_FILES"$, $LK,"FUF_Z_OR_NOT_Z",A="MN:FUF_Z_OR_NOT_Z"$, $LK,"FUF_SCAN_PARENTS",A="MN:FUF_SCAN_PARENTS"$
//If you pass _de, you must Free(_de->full_name);
I64 i,j,cur_dir_cluster;
U8 *altname,*curname,*full_name=NULL;
CDirEntry de;
CDirContext *dirc;
Bool res=FALSE,old_silent;
if (fuf_flags&~FUG_FILE_FIND)
throw('FUF');
if (!filename || *filename && filename[1]==':' && !Let2Drv(*filename,FALSE))
return FALSE;
altname=ToggleZorNotZ(filename);
if (fuf_flags&FUF_Z_OR_NOT_Z)
j=2;
else
j=1;
for (i=0;i<j && !res;i++) {
if (!i)
curname=filename;
else
curname=altname;
old_silent=Silent;
if (!(dirc=DirContextNew(curname)))
Silent(old_silent);
else {
Silent(old_silent);
cur_dir_cluster=Name2DirCluster(dirc->dv,Fs->cur_dir);
switch (dirc->dv->fs_type) {
case FSt_REDSEA:
res=RedSeaFileFind(dirc->dv,cur_dir_cluster,dirc->mask,
&de,fuf_flags);
break;
case FSt_FAT32:
res=FAT32FileFind(dirc->dv,cur_dir_cluster,dirc->mask,
&de,fuf_flags);
break;
case FSt_ISO9660:
res=ISO1FileFind(dirc->dv,cur_dir_cluster,dirc->mask,
&de,fuf_flags);
break;
default:
PrintErr("File System Not Supported\n");
}
if (res && _de) {
if (StrCmp(Fs->cur_dir,"/"))
full_name=MStrPrint("%C:%s/%s",
Drv2Let(Fs->cur_dv),Fs->cur_dir,de.name);
else
full_name=MStrPrint("%C:/%s",Drv2Let(Fs->cur_dv),de.name);
}
DirContextDel(dirc);
}
}
for (i=0;i<j && !res && fuf_flags&FUF_SCAN_PARENTS;i++) {
if (!i)
curname=filename;
else
curname=altname;
old_silent=Silent;
if (!(dirc=DirContextNew(curname)))
Silent(old_silent);
else {
Silent(old_silent);
cur_dir_cluster=Name2DirCluster(dirc->dv,Fs->cur_dir);
while (!res && StrCmp(Fs->cur_dir,"/")) {
Cd("..");
cur_dir_cluster=Name2DirCluster(dirc->dv,Fs->cur_dir);
switch (dirc->dv->fs_type) {
case FSt_REDSEA:
res=RedSeaFileFind(dirc->dv,cur_dir_cluster,
dirc->mask,&de,fuf_flags);
break;
case FSt_FAT32:
res=FAT32FileFind(dirc->dv,cur_dir_cluster,
dirc->mask,&de,fuf_flags);
break;
case FSt_ISO9660:
res=ISO1FileFind(dirc->dv,cur_dir_cluster,
dirc->mask,&de,fuf_flags);
break;
default:
PrintErr("File System Not Supported\n");
}
}
if (res && _de) {
if (StrCmp(Fs->cur_dir,"/"))
full_name=MStrPrint("%C:%s/%s",
Drv2Let(Fs->cur_dv),Fs->cur_dir,de.name);
else
full_name=MStrPrint("%C:/%s",
Drv2Let(Fs->cur_dv),de.name);
}
DirContextDel(dirc);
}
}
if (_de) {
if (res) {
MemCpy(_de,&de,sizeof(CDirEntry));
_de->full_name=full_name;
} else
MemSet(_de,0,sizeof(CDirEntry));
}
Free(altname);
return res;
}
+95
View File
@@ -0,0 +1,95 @@
Bool DrvTypeSet(U8 drv_let,I64 type=FSt_REDSEA)
{//Very dangerous
I64 i,j,ext_base,drv_num,offset,cur_type;
CMasterBoot mbr;
CBlkDev *bd;
drv_let=Let2Let(drv_let);
bd=Let2BlkDev(drv_let);
drv_num=bd->first_drv_let-'A';
switch (bd->type) {
case BDT_ATA:
offset=0;
ext_base=INVALID_CLUSTER;
while (TRUE) {
ATAReadBlks(bd,&mbr,offset,1);
j=-1;
for (i=0;i<4;i++) {
cur_type=mbr.p[i].type;
if (cur_type) {
if (cur_type==5 || cur_type==15)
j=i;
else {
if (drv_num+'A'==drv_let) {
switch (type) {
case FSt_REDSEA:
mbr.p[i].type=MBR_PT_REDSEA;
break;
case FSt_FAT32:
mbr.p[i].type=MBR_PT_FAT32a;
break;
default:
throw('Drv');
}
mbr.p[i].active=0x80;
ATAWriteBlks(bd,&mbr,offset,1);
return TRUE;
}
drv_num++;
}
}
}
if (j<0)
break;
if (!mbr.p[j].offset)
break;
if (ext_base==INVALID_CLUSTER) {
offset=mbr.p[j].offset;
ext_base=offset;
} else
offset=mbr.p[j].offset+ext_base;
}
break;
}
}
U0 Fmt(I64 drv_let,Bool quick=TRUE,Bool confirm=TRUE,I64 type=FSt_FAT32)
{//Format hard drive or RAM drive.
//$BK,1$Warning:$BK,0$ Destroys all prev info.
//quick=FALSE means fill entire drive with zeros.
//Choose $LK,"FSt_FAT32",A="MN:FSt_FAT32"$ or $LK,"FSt_REDSEA",A="MN:FSt_REDSEA"$.
//You don't format a CD/DVD with this.
CDrv *dv=Let2Drv(drv_let);
Bool old_silent=IsSilent;
if (confirm && !AreYouSure)
return;
if (!dv) {
PrintErr("Invalid Drive\n");
return;
}
switch (type) {
case FSt_FAT32:
if (dv->bd->type==BDT_ATA) {
Silent;
Drv(drv_let);
Silent(old_silent);
FAT32Fmt(drv_let,quick);
DskCacheInvalidate(Let2Drv(drv_let));
Drv(drv_let);
break;
}
"Using RedSea File System.\n";
case FSt_REDSEA:
Silent;
Drv(drv_let);
Silent(old_silent);
RedSeaFmt(drv_let,quick);
DskCacheInvalidate(Let2Drv(drv_let));
Drv(drv_let);
break;
case FSt_ISO9660:
PrintErr("Not Writable\n");
break;
default:
PrintErr("File System Not Supported\n");
}
}
+343
View File
@@ -0,0 +1,343 @@
U8 *FileExtDot(U8 *src)
{//Find dot char in name.
I64 ch;
while (ch=*src++)
if (ch=='.' && *src!='/' && *src!='.')
return src-1;
return NULL;
}
U8 *FileExtRem(U8 *src,U8 *dst=NULL)
{//Remove filename extension from str.
U8 *ptr;
if (ptr=FileExtDot(src)) {
if (dst)
StrCpy(dst,ptr+1);
*ptr=0;
} else if (dst)
*dst=0;
return dst;
}
Bool IsDotZ(U8 *filename)
{//Does name end in .Z?
I64 i=StrLen(filename);
if (StrOcc(filename,'.')>1 && filename[i-1]=='Z' && filename[i-2]=='.')
return TRUE;
else
return FALSE;
}
Bool IsDotC(U8 *filename)
{//Does name end in .C?
I64 i=StrLen(filename);
if (StrOcc(filename,'.')>1 && filename[i-1]=='C' && filename[i-2]=='.')
return TRUE;
else
return FALSE;
}
Bool FilesFindMatch(U8 *_test_name,U8 *files_find_mask,I64 fuf_flags=0)
{//Does filename meet $LK,"Files Find",A="FI:::/Doc/FileUtils.DD"$ mask?
I64 tn_len=StrLen(_test_name),mask_len=StrLen(files_find_mask);
U8 *mask1=MAlloc(mask_len+1),*mask2=MAlloc(mask_len+1),
*ptr,*test_name1,*test_name2;
Bool res=FALSE;
StrCpy(mask1,files_find_mask);
if (StrOcc(_test_name,'/')) {
test_name1=MAlloc(tn_len+1);
test_name2=MAlloc(tn_len+1);
StrCpy(test_name1,_test_name);
StrLastRem(test_name1,"/",test_name2);
} else {
test_name1=NULL;
test_name2=NULL;
}
while (TRUE) {
StrFirstRem(mask1,";",mask2);
if (!test_name2 || StrOcc(mask2,'/'))
ptr=_test_name;
else
ptr=test_name2;
if (*mask2) {
if (*mask2=='!') {
if (WildMatch(ptr,mask2+1)) {
res=FALSE;
break;
}
} else {
if (WildMatch(ptr,mask2)) {
if (Bt(&fuf_flags,FUf_JUST_TXT) &&
!FilesFindMatch(_test_name,FILEMASK_TXT)) {
res=FALSE;
break;
} else if (Bt(&fuf_flags,FUf_JUST_DD) &&
!FilesFindMatch(_test_name,FILEMASK_DD)) {
res=FALSE;
break;
} else if (Bt(&fuf_flags,FUf_JUST_SRC) &&
!FilesFindMatch(_test_name,FILEMASK_SRC)) {
res=FALSE;
break;
} else if (Bt(&fuf_flags,FUf_JUST_AOT) &&
!FilesFindMatch(_test_name,FILEMASK_AOT)) {
res=FALSE;
break;
} else if (Bt(&fuf_flags,FUf_JUST_JIT) &&
!FilesFindMatch(_test_name,FILEMASK_JIT)) {
res=FALSE;
break;
} else if (Bt(&fuf_flags,FUf_JUST_GR) &&
!FilesFindMatch(_test_name,FILEMASK_GR)) {
res=FALSE;
break;
} else
res=TRUE;
}
}
} else
break;
}
Free(test_name1);
Free(test_name2);
Free(mask1);
Free(mask2);
return res;
}
U8 *DirNameAbs(U8 *_dirname)
{//MAlloc absolute dir string with drv letter.
I64 maxlen;
U8 drv[3],*res,*buf,*buf2,*buf3,*buf4,*dirname,*free_dirname;
if (!Fs->cur_dir || !*Fs->cur_dir)
return StrNew(_dirname);
free_dirname=dirname=MStrUtil(_dirname,
SUF_REM_LEADING|SUF_REM_TRAILING|SUF_REM_CTRL_CHARS);
*drv=Drv2Let;
drv[1]=':';
drv[2]=0;
if (*dirname && dirname[1]==':') {
if (*dirname==':')
*drv=blkdev.boot_drv_let;
else if (*dirname=='~')
*drv=*blkdev.home_dir;
else
*drv=*dirname;
dirname=dirname+2;
buf=StrNew("/");
} else
buf=StrNew(Fs->cur_dir);
if (*dirname=='/') {
Free(buf);
buf=StrNew("/");
dirname++;
}
buf2=StrNew(dirname);
maxlen=StrLen(buf)+1+StrLen(buf2)+1;
buf3=MAlloc(maxlen);
buf4=MAlloc(maxlen);
StrCpy(buf3,buf);
while (*buf2) {
StrFirstRem(buf2,"/",buf4);
if (!*buf4)
StrCpy(buf3,"/");
else if (!StrCmp(buf4,"..")) {
StrLastRem(buf3,"/");
if (!*buf3)
StrCpy(buf3,"/");
} else if (!StrCmp(buf4,"~")) {
Free(buf3);
buf3=MAlloc(StrLen(blkdev.home_dir+2)+1+StrLen(buf2)+1);
StrCpy(buf3,blkdev.home_dir+2);
*drv=*blkdev.home_dir;
} else if (!StrCmp(buf4,"."));
else if (*buf4) {
if (StrCmp(buf3,"/"))
CatPrint(buf3,"/");
CatPrint(buf3,buf4);
}
}
Free(buf);
res=MAlloc(StrLen(buf3)+3);
StrCpy(res,drv);
StrCpy(res+2,buf3);
Free(buf2);
Free(buf3);
Free(buf4);
Free(free_dirname);
return res;
}
U8 *FileNameAbs(U8 *_filename,I64 fuf_flags=0)
{//Absolute filename. Accepts $LK,"FUF_Z_OR_NOT_Z",A="MN:FUF_Z_OR_NOT_Z"$, $LK,"FUF_SCAN_PARENTS",A="MN:FUF_SCAN_PARENTS"$.
U8 *res,*filename,*buf,*buf_file,*buf_dir,*free_filename,*free_buf;
CDirEntry de;
free_filename=filename=MStrUtil(_filename,
SUF_REM_LEADING|SUF_REM_TRAILING|SUF_REM_CTRL_CHARS);
free_buf=buf=StrNew(filename);
if (*buf && buf[1]==':') {
buf+=2;
filename+=2;
}
buf_file=MAlloc(StrLen(free_filename)+1);
StrLastRem(buf,"/",buf_file);
if (*filename=='/' && !*buf)
StrCpy(buf,"/");
buf_dir=DirNameAbs(free_buf);
Free(free_buf);
res=MAlloc(StrLen(buf_dir)+1+StrLen(buf_file)+1);
StrCpy(res,buf_dir);
if (res[StrLen(res)-1]!='/')
CatPrint(res,"/");
CatPrint(res,buf_file);
Free(buf_file);
Free(buf_dir);
Free(free_filename);
if (fuf_flags && FileFind(res,&de,fuf_flags|FUF_JUST_FILES)) {
Free(res);
res=de.full_name;
}
return res;
}
U8 *ChgExt(U8 *filename,U8 *extension)
{//Change filename extension.
U8 *res=MAlloc(StrLen(filename)+1+StrLen(extension)+1);
StrCpy(res,filename);
if (FileExtDot(filename))
FileExtRem(res);
return CatPrint(res,".%s",extension);
}
U8 *DftExt(U8 *filename,U8 *extension)
{//Give extension if has none.
U8 *res=MAlloc(StrLen(filename)+1+StrLen(extension)+1);
StrCpy(res,filename);
if (!FileExtDot(filename))
CatPrint(res,".%s",extension);
return res;
}
CDirEntry *Cd2DirEntry(CDirEntry *tmpde,U8 *abs_name)
{
I64 i;
while (tmpde) {
i=StrLen(tmpde->full_name);
if (StrNCmp(tmpde->full_name,abs_name,i)||
i && tmpde->full_name[i-1]!='/' && abs_name[i] && abs_name[i]!='/')
tmpde=tmpde->next;
else
if (StrLen(abs_name)==i)
return tmpde;
else
return Cd2DirEntry(tmpde->sub,abs_name);
}
return NULL;
}
I64 FileAttr(U8 *name,I64 attr=0)
{
if (IsDotZ(name))
attr|=RS_ATTR_COMPRESSED;
else
attr&=~RS_ATTR_COMPRESSED;
if (IsDotC(name))
attr|=RS_ATTR_CONTIGUOUS;
return attr;
}
Bool FileNameChk(U8 *filename)
{//Return check for valid filename, not checking existence.
U8 *ptr=filename;
if (!filename) return FALSE;
if (!*ptr) return FALSE;
if (*ptr=='.') {
if (!ptr[1]) return TRUE;
if (ptr[1]=='.' && !ptr[2]) return TRUE;
}
if (StrLen(filename)>=CDIR_FILENAME_LEN) return FALSE;
while (*ptr)
if (!Bt(char_bmp_filename,*ptr++))
return FALSE;
return TRUE;
}
U8 *ToggleZorNotZ(U8 *name)
{//MAlloc name with Z if not Z or vice versa.
U8 *res;
if (IsDotZ(name)) {
res=StrNew(name);
res[StrLen(name)-2]=0;
} else
res=MStrPrint("%s.Z",name);
return res;
}
U8 *FileNameTmpTxt()
{//Make pretty-safe tmp filename in home dir.
return MStrPrint("~/SysTmp%X.DD.Z",GetTSC>>8&0xFFFFFFFF);
}
U8 *CurDir(CTask *task=NULL,CTask *mem_task=NULL)
{//MAlloc copy of cur dir with drv letter.
U8 *st;
if (!task) task=Fs;
if (!task->cur_dir)
return NULL;
st=MAlloc(StrLen(task->cur_dir)+3,mem_task);
*st=Drv2Let(task->cur_dv);
st[1]=':';
StrCpy(st+2,task->cur_dir);
return st;
}
U8 *DirFile(U8 *dirname,U8 *name=NULL,U8 *_extension=NULL)
{/*Strips file from dirname, scans for file upward until found or
returns default.
("/Kernel/KHashA.HC.Z",NULL,NULL) returns "D:/Kernel"
("/Kernel",NULL,"PRJ.Z") returns "D:/Kernel/Kernel.PRJ.Z"
("/Kernel/BlkDev",NULL,"PRJ.Z") returns "D:/Kernel/Kernel.PRJ.Z"
("/Apps/Psalmody","Load","HC.Z") returns "D:/Apps/Psalmody/Load.HC.Z"
*/
U8 *st=DirNameAbs(dirname),*st2,*st3,*res,*dft=NULL,*ext;
if (_extension && *_extension) {
if (*_extension=='.')
ext=StrNew(_extension);
else
ext=MStrPrint(".%s",_extension);
} else
ext=StrNew("");
while (StrOcc(st,'/')&&!IsDir(st))
StrLastRem(st,"/");
while (StrOcc(st,'/')) {
st2=StrNew(st);
st3=StrNew(st);
StrLastRem(st2,"/",st3);
if (name)
res=MStrPrint("%s/%s%s",st,name,ext);
else {
if (*ext)
res=MStrPrint("%s/%s%s",st,st3,ext);
else
res=StrNew(st);
}
if (!dft)
dft=StrNew(res);
if (!*ext && (!name||!*name) || FileFind(res)) {
Free(st3);
Free(st2);
Free(st);
Free(dft);
Free(ext);
return res;
}
Free(st);
st=st2;
Free(st3);
}
Free(st);
Free(ext);
return dft;
}
+97
View File
@@ -0,0 +1,97 @@
Bool CFileNameTo(U8 *dst,U8 *src)
{
MemSet(dst,0,CDIR_FILENAME_LEN);
if (!FileNameChk(src))
return FALSE;
StrCpy(dst,src);
return TRUE;
}
I64 Name2DirCluster(CDrv *dv,U8 *dirname)
{
Bool cont=TRUE,unlock;
I64 cur_dir_cluster;
CDirEntry de;
U8 *buf=StrNew(dirname),*buf2=StrNew(dirname);
DrvChk(dv);
try {
unlock=DrvLock(dv);
cur_dir_cluster=dv->root_cluster;
while (*buf && cont) {
StrFirstRem(buf,"/",buf2);
if (*buf2) {
switch (dv->fs_type) {
case FSt_REDSEA:
cont=RedSeaFileFind(dv,cur_dir_cluster,buf2,&de,FUF_JUST_DIRS);
break;
case FSt_FAT32:
cont=FAT32FileFind(dv,cur_dir_cluster,buf2,&de,FUF_JUST_DIRS);
break;
case FSt_ISO9660:
cont=ISO1FileFind(dv,cur_dir_cluster,buf2,&de,FUF_JUST_DIRS);
break;
default:
throw('Drv');
}
cur_dir_cluster=de.cluster;
}
}
if (!cont) {
"%s ",dirname;
PrintErr("File not found.\n");
cur_dir_cluster=0;
}
if (unlock)
DrvUnlock(dv);
} catch
if (unlock)
DrvUnlock(dv);
Free(buf);
Free(buf2);
return cur_dir_cluster;
}
I64 Name2ParentDirCluster(CDrv *dv,U8 *dirname)
{
Bool cont=TRUE,unlock;
I64 cur_dir_cluster,cur_dir_cluster2;
CDirEntry de;
U8 *buf=StrNew(dirname),*buf2=StrNew(dirname);
DrvChk(dv);
try {
unlock=DrvLock(dv);
cur_dir_cluster=cur_dir_cluster2=dv->root_cluster;
while (*buf && cont) {
cur_dir_cluster2=cur_dir_cluster;
StrFirstRem(buf,"/",buf2);
if (*buf2) {
switch (dv->fs_type) {
case FSt_REDSEA:
cont=RedSeaFileFind(dv,cur_dir_cluster,buf2,&de,FUF_JUST_DIRS);
break;
case FSt_FAT32:
cont=FAT32FileFind(dv,cur_dir_cluster,buf2,&de,FUF_JUST_DIRS);
break;
case FSt_ISO9660:
cont=ISO1FileFind(dv,cur_dir_cluster,buf2,&de,FUF_JUST_DIRS);
break;
default:
throw('Drv');
}
cur_dir_cluster=de.cluster;
}
}
if (!cont) {
"%s ",dirname;
PrintErr("File not found.\n");
cur_dir_cluster2=0;
}
if (unlock)
DrvUnlock(dv);
} catch
if (unlock)
DrvUnlock(dv);
Free(buf);
Free(buf2);
return cur_dir_cluster2;
}
+961
View File
@@ -0,0 +1,961 @@
U0 CDate2Dos(U16 *t,U16 *d,CDate cdt)
{
CDateStruct ds;
Date2Struct(&ds,cdt);
*d=ds.day_of_mon+(ds.mon+(ds.year-1980)<<4)<<5;
*t=ds.sec>>1+(ds.min+ds.hour<<6)<<5;
}
CDate Dos2CDate(U16 t,U16 d)
{
CDateStruct ds;
MemSet(&ds,0,sizeof(CDateStruct));
ds.day_of_mon=d&0x1F; d=d>>5;
ds.mon=d&0xF;
ds.year=d>>4+1980;
ds.sec=(t&0x1F)*2; t=t>>5;
ds.min=t&0x3F;
ds.hour=t>>6;
return Struct2Date(&ds);
}
U0 FAT32Init(CDrv *dv)
{
CFAT32Boot br32;
Bool unlock;
try {
unlock=DrvLock(dv);
dv->fs_type=FSt_FAT32;
RBlks(dv,&br32,dv->drv_offset,1);
dv->file_system_info_sect=dv->drv_offset+br32.file_system_info_sect;
dv->fat1=dv->drv_offset+br32.reserved_sects;
dv->fat2=dv->fat1+br32.sects_per_fat;
dv->data_area=dv->fat2+br32.sects_per_fat
-2*br32.sects_per_cluster; //Starts at Cluster 2
dv->spc=br32.sects_per_cluster;
dv->root_cluster=br32.root_cluster;
DrvFATBlkAlloc(dv);
Free(dv->fis);
dv->fis=AMAlloc(BLK_SIZE);
RBlks(dv,dv->fis,dv->file_system_info_sect,1);
if (unlock)
DrvUnlock(dv);
} catch
if (unlock)
DrvUnlock(dv);
}
U0 FAT32Fmt(U8 drv_let,Bool quick=TRUE)
{
CFAT32Boot *br=CAlloc(BLK_SIZE);
CFAT32FileInfoSect *fis=CAlloc(BLK_SIZE);
CDrv *dv=Let2Drv(drv_let);
I64 i,l;
try {
DrvLock(dv);
DrvTypeSet(drv_let,FSt_FAT32);
dv->fs_type=FSt_FAT32;
br->jump_and_nop[0]=OC_JMP_REL8;
br->jump_and_nop[1]=offset(CFAT32Boot.code)-2;
br->jump_and_nop[2]=OC_NOP;
br->oem_name[0](I64)='MSWIN4.1';
br->bytes_per_sect=BLK_SIZE;
if (dv->size<= 500000)
br->sects_per_cluster=1;
else if (dv->size<=2000000)
br->sects_per_cluster=2;
else if (dv->size<=6000000)
br->sects_per_cluster=4;
else if (dv->size<=12000000)
br->sects_per_cluster=8;
else if (dv->size<=33000000)
br->sects_per_cluster=16;
else if (dv->size<=67000000)
br->sects_per_cluster=32;
else
br->sects_per_cluster=64;
br->reserved_sects=32;
br->copies_of_fat=2;
br->media_desc=0xF8;
br->sects=dv->size;
l=(br->sects/br->sects_per_cluster)>>(BLK_SIZE_BITS-2)+1;
br->sects_per_fat=l;
br->root_cluster=2;
br->file_system_info_sect=1;
br->log_drv_num=0x80;
br->ext_signature=0x29;
br->serial_num=RandU32;
MemCpy(br->vol_name,"NO NAME ",11);
br->fat_name[0](I64)='FAT32 ';
br->signature=0xAA55;
fis->signature1='RRaA';
fis->signature2='rrAa';
fis->free_clusters=-1;
fis->most_recently_alloced=0;
fis->signature3=0xAA550000;
if (quick)
i=br->reserved_sects+2*l+4*br->sects_per_cluster;
else
i=dv->size;
WZeroBlks(dv,dv->drv_offset,i);
WBlks(dv,fis,dv->drv_offset+br->file_system_info_sect,1);
WBlks(dv,br,dv->drv_offset,1);
FAT32Init(dv);
ClustersAlloc(dv,0,1,FALSE); //Alloc #1
br->root_cluster=ClustersAlloc(dv,0,1,FALSE);
WBlks(dv,br,dv->drv_offset,1);
FAT32Init(dv);
DrvUnlock(dv);
} catch
DrvUnlock(dv);
Free(br);
Free(fis);
}
Bool FATNameTo(U8 *dst,U8 *src)
{
I64 i;
MemSet(dst,CH_SPACE,11);
if (!FileNameChk(src))
return FALSE;
if (!StrCmp(src,"..")) {
*dst='.';
dst[1]='.';
return TRUE;
} else if (!StrCmp(src,".")) {
*dst='.';
return TRUE;
}
i=0;
while (i<8 && *src && *src!='.')
dst[i++]=ToUpper(*src++);
i=8;
if (*src=='.') src++;
while (*src)
if (*src!='.')
dst[i++]=ToUpper(*src++);
else
src++;
return TRUE;
}
I64 FATNameXSum(U8 *src)
{
I64 i,res=0;
for (i=0;i<11;i++)
if (res&1)
res.u8[0]=0x80+res>>1+*src++;
else
res.u8[0]=res>>1+*src++;
return res;
}
Bool FATFromName(U8 *dst,U8 *src)
{
I64 i,j,k=0;
for (j=7;j>=0 && src[j]==CH_SPACE;j--);
for(i=0;i<=j;i++)
dst[k++]=src[i];
for (j=10;j>=8 && src[j]==CH_SPACE;j--);
if (*src!='.' && j!=7)
dst[k++]='.';
for(i=8;i<=j;i++)
dst[k++]=src[i];
dst[k++]=0;
return FileNameChk(dst);
}
U8 fat_long_name_map[13]={
offset(CFAT32DirEntryLong.name1),
offset(CFAT32DirEntryLong.name1)+2,
offset(CFAT32DirEntryLong.name1)+4,
offset(CFAT32DirEntryLong.name1)+6,
offset(CFAT32DirEntryLong.name1)+8,
offset(CFAT32DirEntryLong.name2),
offset(CFAT32DirEntryLong.name2)+2,
offset(CFAT32DirEntryLong.name2)+4,
offset(CFAT32DirEntryLong.name2)+6,
offset(CFAT32DirEntryLong.name2)+8,
offset(CFAT32DirEntryLong.name2)+10,
offset(CFAT32DirEntryLong.name3),
offset(CFAT32DirEntryLong.name3)+2
};
Bool DirLongNameFill(CDirEntry *tmpde,CFAT32DirEntryLong *de,I64 *xsum)
{
I64 i;
U8 *ptr=de;
if (de->ord&0x40) {
MemSet(tmpde,0,sizeof(CDirEntry));
*xsum=de->xsum;
} else if (de->type || de->zero || de->xsum!=*xsum) {
MemSet(tmpde,0,sizeof(CDirEntry));
*xsum=0;
return FALSE;
}
switch (de->ord&0x3F) {
case 1:
for (i=0;i<13;i++)
if (!(tmpde->name[i]=ptr[fat_long_name_map[i]]))
return TRUE;
break;
case 2:
for (i=0;i<12;i++)
if (!(tmpde->name[i+13]=ptr[fat_long_name_map[i]]))
return TRUE;
break;
}
return TRUE;
}
Bool FAT32CDirFill(CDirEntry *tmpde,
CFAT32DirEntry *de,CDate _local_time_offset)
{
Bool res;
if (*tmpde->name)
res=TRUE;
else
res=FATFromName(tmpde->name,de->name);
tmpde->cluster=de->cluster_lo+de->cluster_hi<<16;
tmpde->size=de->size;
tmpde->attr=de->attr;
tmpde->datetime=Dos2CDate(de->WrtTime,de->WrtDate)-_local_time_offset;
return res;
}
Bool FAT32DirFill(CFAT32DirEntry *de,
CDirEntry *tmpde,I64 *_de_cnt,CDate _local_time_offset)
{//Fill up to 3 entries and store cnt of entries.
I64 de_cnt=0,i,l,xsum,ord;
U8 *ptr,dname[16];
CFAT32DirEntryLong *ld=de;
Bool res;
MemSet(de,0,sizeof(CFAT32DirEntry));
res=FATNameTo(de->name,tmpde->name);
FATFromName(dname,de->name);
if (StrCmp(dname,tmpde->name)) {
ord=0x41;
xsum=FATNameXSum(de->name);
if ((l=StrLen(tmpde->name))>13) {
ptr=&ld[de_cnt];
MemSet(ptr,0,sizeof(CFAT32DirEntryLong));
ld[de_cnt].attr=RS_ATTR_LONG_NAME;
ld[de_cnt].xsum=xsum;
ld[de_cnt].ord=0x42;
for (i=13;i<l;i++)
ptr[fat_long_name_map[i-13]]=tmpde->name[i];
i++;
for (;i<26;i++)
ptr[fat_long_name_map[i-13]](U16)=0xFFFF;
ord=1;
l=13;
de_cnt++;
}
ptr=&de[de_cnt];
MemSet(ptr,0,sizeof(CFAT32DirEntryLong));
ld[de_cnt].attr=RS_ATTR_LONG_NAME;
ld[de_cnt].xsum=xsum;
ld[de_cnt].ord=ord;
for (i=0;i<l;i++)
ptr[fat_long_name_map[i]]=tmpde->name[i];
i++;
for (;i<13;i++)
ptr[fat_long_name_map[i]](U16)=0xFFFF;
de_cnt++;
MemSet(&de[de_cnt],0,sizeof(CFAT32DirEntry));
res=FATNameTo(de[de_cnt].name,tmpde->name);
}
de[de_cnt].cluster_lo=tmpde->cluster.u16[0];
de[de_cnt].cluster_hi=tmpde->cluster.u16[1];
if (!(tmpde->attr&RS_ATTR_DIR))
de[de_cnt].size=tmpde->size;
de[de_cnt].attr=tmpde->attr;
if (!tmpde->datetime)
tmpde->datetime=Now;
CDate2Dos(&de[de_cnt].WrtTime,&de[de_cnt].WrtDate,
tmpde->datetime+_local_time_offset);
if (_de_cnt)
*_de_cnt=de_cnt+1;
return res;
}
Bool FAT32FileFind(CDrv *dv,I64 cur_dir_cluster,
U8 *name,CDirEntry *_res,I64 fuf_flags=0)
{//$LK,"FUF_JUST_DIRS",A="MN:FUF_JUST_DIRS"$, $LK,"FUF_JUST_FILES",A="MN:FUF_JUST_FILES"$
Bool res=FALSE,unlock;
CFAT32DirEntry *buf;
I64 xsum=0,attr,cur_dir_entry,entries_per_cluster;
U8 dname[CDIR_FILENAME_LEN],ch;
CDirEntry long_name;
if (fuf_flags&~FUG_FILE_FIND)
throw('FUF');
MemSet(_res,0,sizeof(CDirEntry));
MemSet(&long_name,0,sizeof(CDirEntry));
DrvChk(dv);
if (dv->fs_type!=FSt_FAT32)
PrintErr("Not FAT32 Drv\n");
else if (!CFileNameTo(dname,name))
PrintErr("Invalid FileName.\n");
else
try {
unlock=DrvLock(dv);
buf=MAlloc(BLK_SIZE*dv->spc);
entries_per_cluster=dv->spc<<FAT32_ENTRIES_BITS;
RClusters(dv,buf,cur_dir_cluster,1);
cur_dir_entry=0;
while (ch=*buf[cur_dir_entry].name) {
attr=buf[cur_dir_entry].attr;
if (ch!=0xE5) {
if (attr&RS_ATTR_LONG_NAME_MASK==RS_ATTR_LONG_NAME)
DirLongNameFill(&long_name,&buf[cur_dir_entry],&xsum);
else {
if (!(attr&RS_ATTR_VOL_ID)) {
if (xsum==FATNameXSum(buf[cur_dir_entry].name))
MemCpy(_res,&long_name,sizeof(CDirEntry));
else
MemSet(_res,0,sizeof(CDirEntry));
if (!(fuf_flags&FUF_JUST_DIRS && !(attr & RS_ATTR_DIR)) &&
!(fuf_flags&FUF_JUST_FILES && attr & RS_ATTR_DIR) &&
FAT32CDirFill(_res,&buf[cur_dir_entry],
dv->fat32_local_time_offset) &&
!StrCmp(dname,_res->name)) {
res=TRUE;
goto fff_done;
}
}
MemSet(&long_name,0,sizeof(CDirEntry));
}
} else
MemSet(&long_name,0,sizeof(CDirEntry));
if (++cur_dir_entry==entries_per_cluster) {
cur_dir_cluster=ClusterNumNext(dv,cur_dir_cluster);
if (!(0<cur_dir_cluster<0x0FFFFFF8))
break;
else {
RClusters(dv,buf,cur_dir_cluster,1);
cur_dir_entry=0;
}
}
}
MemSet(_res,0,sizeof(CDirEntry));
fff_done:
Free(buf);
if (unlock)
DrvUnlock(dv);
} catch
if (unlock)
DrvUnlock(dv);
return res;
}
U8 *FAT32FileRead(CDrv *dv,U8 *cur_dir,U8 *filename,I64 *_size,I64 *_attr)
{
U8 *buf=NULL;
CDirEntry de;
I64 c,blk_cnt,cur_dir_cluster;
DrvChk(dv);
*_size=0;
*_attr=0;
if (dv->fs_type!=FSt_FAT32)
PrintErr("Not FAT32 Drv\n");
else
try {
DrvLock(dv);
cur_dir_cluster=Name2DirCluster(dv,cur_dir);
if (FAT32FileFind(dv,cur_dir_cluster,filename,&de,FUF_JUST_FILES)) {
blk_cnt=(de.size+BLK_SIZE-1)>>BLK_SIZE_BITS;
buf=MAlloc(blk_cnt<<BLK_SIZE_BITS+1);
c=de.cluster;
if (!(0<c<0x0FFFFFF8))
c=0x0FFFFFFF;
else
c=RClustersBlks(dv,buf,c,blk_cnt);
buf[de.size]=0; //Terminate
*_size=de.size;
*_attr=FileAttr(de.name,de.attr);
}
DrvUnlock(dv);
} catch
DrvUnlock(dv);
return buf;
}
Bool FAT32Cd(U8 *name,I64 cur_dir_cluster)
{
CDirEntry de;
if (Fs->cur_dv->fs_type!=FSt_FAT32)
PrintErr("Not FAT32 Drv\n");
else if (FAT32FileFind(Fs->cur_dv,cur_dir_cluster,name,&de,FUF_JUST_DIRS))
return TRUE;
else {
"%s ",name;
PrintErr("File not found.\n");
}
return FALSE;
}
U0 FAT32FreeClusters(CDrv *dv,I64 c)
{
I64 next,saved_c=c;
Bool unlock,unlock_break;
DrvChk(dv);
if (!(0<c<0x0FFFFFF8)) return;
if (dv->fs_type!=FSt_FAT32)
PrintErr("Not FAT32 Drv\n");
else
try {
unlock_break=BreakLock;
unlock=DrvLock(dv);
DrvFATBlkClean(dv);
do {
DrvFATBlkSet(dv,c,0);
next=dv->cur_fat_blk[c&(BLK_SIZE/4-1)];
dv->cur_fat_blk[c&(BLK_SIZE/4-1)]=0;
LBts(&dv->fat_blk_dirty,0);
c=next;
} while (0<c<0x0FFFFFF8);
DrvFATBlkClean(dv,0);
c=saved_c;
do {
DrvFATBlkSet(dv,c,1);
next=dv->cur_fat_blk[c&(BLK_SIZE/4-1)];
dv->cur_fat_blk[c&(BLK_SIZE/4-1)]=0;
LBts(&dv->fat_blk_dirty,0);
c=next;
} while (0<c<0x0FFFFFF8);
DrvFATBlkClean(dv,1);
if (unlock)
DrvUnlock(dv);
if (unlock_break)
BreakUnlock;
} catch {
if (unlock)
DrvUnlock(dv);
if (unlock_break)
BreakUnlock;
}
}
I64 FAT32AllocClusters(CDrv *dv,I64 c,I64 cnt)
{
Bool wrap_around=FALSE,unlock,unlock_break;
I64 first=INVALID_CLUSTER,j,l;
if (cnt<=0) return 0x0FFFFFFF;
try {
unlock_break=BreakLock;
unlock=DrvLock(dv);
l=(dv->size+dv->drv_offset-dv->data_area)/dv->spc-1;
j=dv->fis->most_recently_alloced;
while (cnt-->0) {
while (TRUE) {
j++;
if (j<1) j=1;
if (j>=l) {
if (wrap_around)
throw('Drv');
j=1;
wrap_around=TRUE;
}
DrvFATBlkSet(dv,j);
if (!dv->cur_fat_blk[j&(BLK_SIZE/4-1)])
break;
}
if (!(0<first<0x0FFFFFF8))
first=j;
if (0<c<l) {
DrvFATBlkSet(dv,c);
dv->cur_fat_blk[c&(BLK_SIZE/4-1)]=j;
LBts(&dv->fat_blk_dirty,0);
}
c=j;
}
if (0<c<l) {
DrvFATBlkSet(dv,c);
dv->cur_fat_blk[c&(BLK_SIZE/4-1)]=0x0FFFFFFF;
LBts(&dv->fat_blk_dirty,0);
}
DrvFATBlkClean(dv);
dv->fis->most_recently_alloced=j;
dv->fis->free_clusters=-1;
WBlks(dv,dv->fis,dv->file_system_info_sect,1);
} catch {
if (unlock)
DrvUnlock(dv);
if (unlock_break)
BreakUnlock;
}
if (unlock)
DrvUnlock(dv);
if (unlock_break)
BreakUnlock;
return first;
}
I64 FAT32AllocContiguousClusters(CDrv *dv,I64 cnt)
{
I64 i,first=1;
Bool cont,unlock,unlock_break;
if (cnt<=0) return 0x0FFFFFFF;
try {
unlock_break=BreakLock;
unlock=DrvLock(dv);
while (TRUE) {
first++;
i=0;
cont=TRUE;
while (cont && i<cnt) {
if ((first+i+1)*dv->spc+dv->data_area>dv->size+dv->drv_offset)
throw('Drv');
DrvFATBlkSet(dv,first+i);
if (dv->cur_fat_blk[(first+i)&(BLK_SIZE/4-1)])
cont=FALSE;
else
i++;
}
if (!cont)
first=first+i;
else {
DrvFATBlkClean(dv);
for (i=0;i<cnt;i++) {
DrvFATBlkSet(dv,first+i,0);
if (i+1==cnt)
dv->cur_fat_blk[(first+i)&(BLK_SIZE/4-1)]=0x0FFFFFFF;
else
dv->cur_fat_blk[(first+i)&(BLK_SIZE/4-1)]=first+i+1;
LBts(&dv->fat_blk_dirty,0);
}
DrvFATBlkClean(dv,0);
for (i=0;i<cnt;i++) {
DrvFATBlkSet(dv,first+i,1);
if (i+1==cnt)
dv->cur_fat_blk[(first+i)&(BLK_SIZE/4-1)]=0x0FFFFFFF;
else
dv->cur_fat_blk[(first+i)&(BLK_SIZE/4-1)]=first+i+1;
LBts(&dv->fat_blk_dirty,0);
}
DrvFATBlkClean(dv,1);
break;
}
}
} catch {
if (unlock)
DrvUnlock(dv);
if (unlock_break)
BreakUnlock;
}
if (unlock)
DrvUnlock(dv);
if (unlock_break)
BreakUnlock;
return first;
}
Bool FAT32DirNew(CDrv *dv,U8 *cur_dir,CDirEntry *tmpde,Bool free_old_chain)
{
//See $LK,"::/Doc/CutCorners.DD"$.
CFAT32DirEntry *buf,*last_buf,*tmp_buf,de[3];
I64 i,attr,avail_cnt,de_cnt,c,
cur_dir_entry,entries_per_cluster,
cur_dir_cluster,xsum=0,last_dir_cluster=INVALID_CLUSTER;
U8 ch;
Bool written=FALSE,unlock,unlock_break;
CDirEntry long_name;
FAT32DirFill(&de,tmpde,&de_cnt,dv->fat32_local_time_offset);
MemSet(&long_name,0,sizeof(CDirEntry));
try {
unlock_break=BreakLock;
unlock=DrvLock(dv);
cur_dir_cluster=Name2DirCluster(dv,cur_dir);
buf =MAlloc(BLK_SIZE*dv->spc);
last_buf=CAlloc(BLK_SIZE*dv->spc);
entries_per_cluster=dv->spc<<FAT32_ENTRIES_BITS;
RClusters(dv,buf,cur_dir_cluster,1);
cur_dir_entry=0;
while (ch=*buf[cur_dir_entry].name) {
attr=buf[cur_dir_entry].attr;
if (ch!=0xE5 && attr&RS_ATTR_LONG_NAME_MASK==RS_ATTR_LONG_NAME)
DirLongNameFill(&long_name,&buf[cur_dir_entry],&xsum);
else {
avail_cnt=FAT32_ENTRIES_PER_BLK-cur_dir_entry
&(FAT32_ENTRIES_PER_BLK-1);
for (i=0;i<avail_cnt;i++)
if (*buf[cur_dir_entry+i].name!=0xE5) {
if (*buf[cur_dir_entry+i].name)
avail_cnt=i;
break;
}
if (ch==0xE5 && !written && avail_cnt>=de_cnt) {
MemCpy(&buf[cur_dir_entry],&de,de_cnt*sizeof(CFAT32DirEntry));
WBlks(dv,&buf[cur_dir_entry & -FAT32_ENTRIES_PER_BLK],
dv->data_area+cur_dir_cluster*dv->spc
+cur_dir_entry>>FAT32_ENTRIES_BITS,1);
cur_dir_entry+=de_cnt-1; //gets inc'ed
written=TRUE;
} else if (ch!=0xE5 && !(attr&RS_ATTR_VOL_ID)) {
if (xsum!=FATNameXSum(buf[cur_dir_entry].name))
MemSet(&long_name,0,sizeof(CDirEntry));
if (!*long_name.name)
FATFromName(long_name.name,buf[cur_dir_entry].name);
//Del old entry with same name
if (!StrCmp(long_name.name,tmpde->name)) {
if (free_old_chain)
FAT32FreeClusters(dv,buf[cur_dir_entry].cluster_lo+
buf[cur_dir_entry].cluster_hi<<16);
if (!written) {
MemCpy(&buf[cur_dir_entry],&de[de_cnt-1],sizeof(CFAT32DirEntry));
WBlks(dv,&buf[cur_dir_entry & -FAT32_ENTRIES_PER_BLK],
dv->data_area+cur_dir_cluster*dv->spc
+cur_dir_entry>>FAT32_ENTRIES_BITS,1);
written=TRUE;
} else {
*buf[cur_dir_entry].name=0xE5;
i=1;
while (i<=cur_dir_entry &&
buf[cur_dir_entry-i].attr&RS_ATTR_LONG_NAME_MASK
==RS_ATTR_LONG_NAME)
*buf[cur_dir_entry-i++].name=0xE5;
i--;
WBlks(dv,&buf[(cur_dir_entry-i)&-FAT32_ENTRIES_PER_BLK],
dv->data_area+cur_dir_cluster*dv->spc
+(cur_dir_entry-i)>>FAT32_ENTRIES_BITS,
(i+FAT32_ENTRIES_PER_BLK)>>FAT32_ENTRIES_BITS);
if (i==cur_dir_entry && 0<last_dir_cluster<0x0FFFFFF8) {
i=1;
while (i<=entries_per_cluster &&
last_buf[entries_per_cluster-i].attr
&RS_ATTR_LONG_NAME_MASK==RS_ATTR_LONG_NAME)
*last_buf[entries_per_cluster-i++].name=0xE5;
if (--i>0)
WBlks(dv,&buf[(entries_per_cluster-i)&-FAT32_ENTRIES_PER_BLK],
dv->data_area+last_dir_cluster*dv->spc
+(entries_per_cluster-i)>>FAT32_ENTRIES_BITS,
(i+FAT32_ENTRIES_PER_BLK-1)>>FAT32_ENTRIES_BITS);
}
}
break;
}
}
MemSet(&long_name,0,sizeof(CDirEntry));
}
if (++cur_dir_entry==entries_per_cluster) {
last_dir_cluster=cur_dir_cluster;
tmp_buf=buf; buf=last_buf; last_buf=tmp_buf;
c=ClusterNumNext(dv,cur_dir_cluster);
if (!(0<c<0x0FFFFFF8)) {
c=ClustersAlloc(dv,cur_dir_cluster,1,FALSE);
MemSet(buf,0,BLK_SIZE*dv->spc);
WClusters(dv,buf,c,1);
} else
RClusters(dv,buf,c,1);
cur_dir_cluster=c;
cur_dir_entry=0;
}
}
if (!written) {
avail_cnt=FAT32_ENTRIES_PER_BLK-cur_dir_entry & (FAT32_ENTRIES_PER_BLK-1);
if (avail_cnt<de_cnt) {
for (i=0;i<avail_cnt;i++)
*buf[cur_dir_entry+i].name=0xE5;
WBlks(dv,&buf[cur_dir_entry &-FAT32_ENTRIES_PER_BLK],
dv->data_area+cur_dir_cluster*dv->spc
+cur_dir_entry>>FAT32_ENTRIES_BITS,1);
cur_dir_entry+=avail_cnt;
if (cur_dir_entry==entries_per_cluster) {
last_dir_cluster=cur_dir_cluster;
tmp_buf=buf; buf=last_buf; last_buf=tmp_buf;
cur_dir_cluster=ClustersAlloc(dv,cur_dir_cluster,1);
cur_dir_entry=0;
MemSet(buf,0,BLK_SIZE*dv->spc);
WClusters(dv,buf,cur_dir_cluster,1);
}
}
MemCpy(&buf[cur_dir_entry],&de,de_cnt*sizeof(CFAT32DirEntry));
WBlks(dv,&buf[cur_dir_entry &-FAT32_ENTRIES_PER_BLK],
dv->data_area+cur_dir_cluster*dv->spc+
cur_dir_entry>>FAT32_ENTRIES_BITS,1);
cur_dir_entry+=de_cnt;
if (cur_dir_entry==entries_per_cluster) {
cur_dir_cluster=ClustersAlloc(dv,cur_dir_cluster,1);
MemSet(buf,0,BLK_SIZE*dv->spc);
WClusters(dv,buf,cur_dir_cluster,1);
} else {
MemSet(&buf[cur_dir_entry],0,sizeof(CFAT32DirEntry));
WBlks(dv,&buf[cur_dir_entry &-FAT32_ENTRIES_PER_BLK],
dv->data_area+cur_dir_cluster*dv->spc
+cur_dir_entry>>FAT32_ENTRIES_BITS,1);
}
}
Free(last_buf);
Free(buf);
if (unlock)
DrvUnlock(dv);
if (unlock_break)
BreakUnlock;
} catch {
if (unlock)
DrvUnlock(dv);
if (unlock_break)
BreakUnlock;
}
return FALSE;
}
I64 FAT32FilesDel(CDrv *dv,U8 *cur_dir,U8 *files_find_mask,I64 fuf_flags,
Bool del_dir,Bool print_msg)
{
CFAT32DirEntry *buf,*last_buf,*tmp_buf;
I64 i,res=0,attr,xsum=0,last_dir_cluster=INVALID_CLUSTER,
cur_dir_entry,entries_per_cluster,cur_dir_cluster;
U8 ch;
Bool unlock_break;
CDirEntry long_name;
MemSet(&long_name,0,sizeof(CDirEntry));
try {
unlock_break=BreakLock;
DrvLock(dv);
cur_dir_cluster=Name2DirCluster(dv,cur_dir);
buf =MAlloc(BLK_SIZE*dv->spc);
last_buf=CAlloc(BLK_SIZE*dv->spc);
entries_per_cluster=dv->spc<<FAT32_ENTRIES_BITS;
RClusters(dv,buf,cur_dir_cluster,1);
cur_dir_entry=0;
while (ch=*buf[cur_dir_entry].name) {
attr=buf[cur_dir_entry].attr;
if (ch!=0xE5 && ch!='.') {
if (attr&RS_ATTR_LONG_NAME_MASK==RS_ATTR_LONG_NAME)
DirLongNameFill(&long_name,&buf[cur_dir_entry],&xsum);
else {
if (!(attr & RS_ATTR_VOL_ID) &&
(del_dir || !(attr & RS_ATTR_DIR))) {
if (xsum!=FATNameXSum(buf[cur_dir_entry].name))
MemSet(&long_name,0,sizeof(CDirEntry));
if (!*long_name.name)
FATFromName(long_name.name,buf[cur_dir_entry].name);
if (FilesFindMatch(long_name.name,files_find_mask,fuf_flags)) {
if (!(attr & RS_ATTR_DIR)) res++;
if (print_msg)
"Del %s\n",long_name.name;
*buf[cur_dir_entry].name=0xE5;
i=1;
while (i<=cur_dir_entry &&
buf[cur_dir_entry-i].attr&RS_ATTR_LONG_NAME_MASK
==RS_ATTR_LONG_NAME)
*buf[cur_dir_entry-i++].name=0xE5;
i--;
WBlks(dv,&buf[(cur_dir_entry-i)&-FAT32_ENTRIES_PER_BLK],
dv->data_area+cur_dir_cluster*dv->spc
+(cur_dir_entry-i)>>FAT32_ENTRIES_BITS,
(i+FAT32_ENTRIES_PER_BLK)>>FAT32_ENTRIES_BITS);
if (i==cur_dir_entry && last_dir_cluster!=INVALID_CLUSTER) {
i=1;
while (i<=entries_per_cluster &&
last_buf[entries_per_cluster-i].attr
&RS_ATTR_LONG_NAME_MASK==RS_ATTR_LONG_NAME)
*last_buf[entries_per_cluster-i++].name=0xE5;
if (--i>0)
WBlks(dv,&buf[(entries_per_cluster-i)&-FAT32_ENTRIES_PER_BLK],
dv->data_area+last_dir_cluster*dv->spc
+(entries_per_cluster-i)>>FAT32_ENTRIES_BITS,
(i+FAT32_ENTRIES_PER_BLK-1)>>FAT32_ENTRIES_BITS);
}
FAT32FreeClusters(dv,buf[cur_dir_entry].cluster_lo+
buf[cur_dir_entry].cluster_hi<<16);
}
}
MemSet(&long_name,0,sizeof(CDirEntry));
}
} else
MemSet(&long_name,0,sizeof(CDirEntry));
if (++cur_dir_entry==entries_per_cluster) {
last_dir_cluster=cur_dir_cluster;
cur_dir_cluster=ClusterNumNext(dv,cur_dir_cluster,1);
tmp_buf=buf; buf=last_buf; last_buf=tmp_buf;
RClusters(dv,buf,cur_dir_cluster,1);
cur_dir_entry=0;
}
}
Free(buf);
Free(last_buf);
DrvUnlock(dv);
if (unlock_break)
BreakUnlock;
} catch {
DrvUnlock(dv);
if (unlock_break)
BreakUnlock;
}
return res;
}
I64 FAT32FileWrite(CDrv *dv,U8 *cur_dir,U8 *name,U8 *buf,I64 size,
CDate cdt,I64 attr)
{
CDirEntry de;
I64 c=0,blk_cnt;
Bool contiguous;
MemSet(&de,0,sizeof(CDirEntry));
if (size<0) size=0;
if (dv->fs_type!=FSt_FAT32)
PrintErr("Not FAT32 Drv\n");
else if (!CFileNameTo(de.name,name))
PrintErr("Invalid FileName.\n");
else {
FAT32FilesDel(dv,cur_dir,de.name,0,FALSE,FALSE);
if (attr & RS_ATTR_CONTIGUOUS)
contiguous=TRUE;
else
contiguous=FALSE;
de.size=size;
if (blk_cnt=(size+BLK_SIZE-1)>>BLK_SIZE_BITS)
c=ClustersAlloc(dv,0,(blk_cnt+dv->spc-1)/dv->spc,contiguous);
else
c=0x0FFFFFFF;
de.cluster=c;
de.attr=attr;
de.datetime=cdt;
if (blk_cnt)
WClustersBlks(dv,buf,c,blk_cnt);
FAT32DirNew(dv,cur_dir,&de,TRUE);
}
return c;
}
CDirEntry *FAT32FilesFind(U8 *files_find_mask,
I64 fuf_flags,CDirEntry *parent=NULL,I64 *_dir_size=NULL)
{
CDrv *dv=Fs->cur_dv;
CFAT32DirEntry *buf;
I64 attr,xsum=0,dir_size=0,sub_dir_size,
cur_dir_cluster,cur_dir_entry,entries_per_cluster;
U8 ch;
CDirEntry *res=NULL,*tmpde,long_name;
if (fuf_flags&~FUG_FILES_FIND)
throw('FUF');
try {
MemSet(&long_name,0,sizeof(CDirEntry));
DrvLock(dv);
cur_dir_cluster=Name2DirCluster(dv,Fs->cur_dir);
buf=MAlloc(BLK_SIZE*dv->spc);
entries_per_cluster=dv->spc<<FAT32_ENTRIES_BITS;
RClusters(dv,buf,cur_dir_cluster,1);
dir_size+=dv->spc*BLK_SIZE;
cur_dir_entry=0;
while (ch=*buf[cur_dir_entry].name) {
attr=buf[cur_dir_entry].attr;
if (ch!=0xE5) {
if (attr&RS_ATTR_LONG_NAME_MASK==RS_ATTR_LONG_NAME)
DirLongNameFill(&long_name,&buf[cur_dir_entry],&xsum);
else {
if (!(attr&RS_ATTR_VOL_ID)) {
tmpde=MAlloc(sizeof(CDirEntry));
if (xsum==FATNameXSum(buf[cur_dir_entry].name))
MemCpy(tmpde,&long_name,sizeof(CDirEntry));
else
MemSet(tmpde,0,sizeof(CDirEntry));
if (FAT32CDirFill(tmpde,&buf[cur_dir_entry],
dv->fat32_local_time_offset)) {
tmpde->parent=parent;
if (Bt(&fuf_flags,FUf_RECURSE) && attr&RS_ATTR_DIR &&
*tmpde->name!='.') {
tmpde->next=res;
res=tmpde;
tmpde->full_name=DirNameAbs(tmpde->name);
DrvUnlock(dv);
if (Cd(tmpde->name)) {
tmpde->sub=FAT32FilesFind(files_find_mask,fuf_flags,
tmpde,&sub_dir_size);
tmpde->size=sub_dir_size;
Cd("..");
}
DrvLock(dv);
} else {
tmpde->full_name=FileNameAbs(tmpde->name);
if ((attr&RS_ATTR_DIR || !Bt(&fuf_flags,FUf_JUST_DIRS)) &&
!(Bt(&fuf_flags,FUf_RECURSE) &&
*tmpde->name=='.' && attr&RS_ATTR_DIR) &&
FilesFindMatch(tmpde->full_name,files_find_mask,
fuf_flags)) {
tmpde->next=res;
res=tmpde;
} else
DirEntryDel(tmpde);
}
} else
DirEntryDel(tmpde);
}
MemSet(&long_name,0,sizeof(CDirEntry));
}
} else
MemSet(&long_name,0,sizeof(CDirEntry));
if (++cur_dir_entry==entries_per_cluster) {
cur_dir_cluster=ClusterNumNext(dv,cur_dir_cluster);
if (cur_dir_cluster==INVALID_CLUSTER)
break;
else {
RClusters(dv,buf,cur_dir_cluster,1);
dir_size+=dv->spc*BLK_SIZE;
cur_dir_entry=0;
}
}
}
Free(buf);
DrvUnlock(dv);
} catch
DrvUnlock(dv);
if (_dir_size)
*_dir_size=dir_size;
return res;
}
Bool FAT32MkDir(CDrv *dv,U8 *cur_dir,U8 *name,I64 entry_cnt)
{
I64 c,cur_dir_cluster=Name2DirCluster(dv,cur_dir),
//Rough estimate of size
size=CeilU64((entry_cnt+2)<<FAT32_ENTRIES_BITS,dv->spc<<BLK_SIZE_BITS);
U8 *buf=CAlloc(size);
CDirEntry d_native;
CFAT32DirEntry *dFAT=buf;
Bool unlock_break;
try {
unlock_break=BreakLock;
c=FileWrite(name,buf,size,0,RS_ATTR_DIR);
MemSet(&d_native,0,sizeof(CDirEntry));
d_native.attr=RS_ATTR_DIR;
*d_native.name='.';
d_native.name[1]=0;
d_native.cluster=c;
d_native.size=0;
d_native.datetime=Now;
FAT32DirFill(dFAT,&d_native,NULL,dv->fat32_local_time_offset);
dFAT++;
MemSet(&d_native,0,sizeof(CDirEntry));
d_native.attr=RS_ATTR_DIR;
*d_native.name='.';
d_native.name[1]='.';
d_native.name[2]=0;
d_native.cluster=cur_dir_cluster;
d_native.size=0;
d_native.datetime=Now;
FAT32DirFill(dFAT,&d_native,NULL,dv->fat32_local_time_offset);
WClusters(dv,buf,c,1);
Free(buf);
if (unlock_break)
BreakUnlock;
} catch
if (unlock_break)
BreakUnlock;
return TRUE;
}
+232
View File
@@ -0,0 +1,232 @@
U0 Date2ISO1(CISO1Date *dst,CDate cdt)
{
CDateStruct ds;
Date2Struct(&ds,cdt);
dst->year=ds.year-ISO1_BASE_YEAR;
dst->mon=ds.mon;
dst->day=ds.day_of_mon;
dst->hour=ds.hour;
dst->min=ds.min;
dst->sec=ds.sec;
dst->sec100=ds.sec100;
}
CDate ISO1DateStruct2CDate(CISO1Date *dt)
{
CDateStruct ds;
MemSet(&ds,0,sizeof(CDateStruct));
ds.day_of_mon=dt->day;
ds.mon=dt->mon;
ds.year=dt->year+ISO1_BASE_YEAR;
ds.sec100=dt->sec100;
ds.sec=dt->sec;
ds.min=dt->min;
ds.hour=dt->hour;
return Struct2Date(&ds);
}
Bool ISO1FromName(U8 *dst,U8 *src)
{
I64 i,j,n;
MemSet(dst,0,CDIR_FILENAME_LEN);
n=*src++;
if (n==1 && !*src) {
*dst='.';
} else if (n==1 && *src==1) {
*dst='.';
dst[1]='.';
} else {
n>>=1;
j=0;
for (i=0;i<n;i++) {
src++;
if (*src==';')
break;
if (Bt(char_bmp_filename,*src)) {
if (j>=CDIR_FILENAME_LEN-1)
return FALSE;
dst[j++]=*src++;
} else
return FALSE;
}
}
return FileNameChk(dst);
}
Bool ISO1CDirFill(CDirEntry *tmpde,CISO1DirEntry *de)
{
Bool res;
MemSet(tmpde,0,sizeof(CDirEntry));
res=ISO1FromName(tmpde->name,&de->name_len);
tmpde->cluster=de->loc.little;
tmpde->size=de->size.little;
tmpde->attr=FileAttr(tmpde->name);
if (de->flags & ISO1_ATTR_DIR)
tmpde->attr|=RS_ATTR_DIR;
tmpde->datetime=ISO1DateStruct2CDate(&de->date);
return res;
}
Bool ISO1FileFind(CDrv *dv,I64 cur_dir_cluster,U8 *name,
CDirEntry *_res,I64 fuf_flags=0)
{//$LK,"FUF_JUST_DIRS",A="MN:FUF_JUST_DIRS"$, $LK,"FUF_JUST_FILES",A="MN:FUF_JUST_FILES"$
CISO1DirEntry *isoptr,*buf;
U8 dname[CDIR_FILENAME_LEN];
Bool res=FALSE,unlock;
I64 i;
if (fuf_flags&~FUG_FILE_FIND)
throw('FUF');
DrvChk(dv);
if (dv->fs_type!=FSt_ISO9660)
PrintErr("Not ISO9660 Drv\n");
else
try {
unlock=DrvLock(dv);
isoptr=MAlloc(dv->spc<<BLK_SIZE_BITS);
RClusters(dv,isoptr,cur_dir_cluster,1);
if (isoptr->name_len==1 && !isoptr->name) {//curdir
i=(isoptr->size.little+dv->spc<<BLK_SIZE_BITS-1)/dv->spc<<BLK_SIZE_BITS;
buf=MAlloc(dv->spc<<BLK_SIZE_BITS*i);
RClusters(dv,buf,cur_dir_cluster,i);
Free(isoptr);
} else {
buf=isoptr;
i=1;
}
i*=dv->spc<<BLK_SIZE_BITS;
isoptr=buf;
while (i>0) {
if (!isoptr->len) {
isoptr(U8 *)++;
i--;
} else {
ISO1FromName(dname,&isoptr->name_len);
if (*dname) {
if (!StrCmp(name,dname)) {
res=ISO1CDirFill(_res,isoptr);
if (res &&
!(fuf_flags&FUF_JUST_DIRS &&
!(_res->attr & RS_ATTR_DIR)) &&
!(fuf_flags&FUF_JUST_FILES && _res->attr & RS_ATTR_DIR) )
goto iff_done;
else
res=FALSE;
}
}
i-=isoptr->len;
isoptr(U8 *)+=isoptr->len;
}
}
iff_done:
Free(buf);
if (unlock)
DrvUnlock(dv);
} catch
if (unlock)
DrvUnlock(dv);
return res;
}
U8 *ISO1FileRead(CDrv *dv,U8 *cur_dir,U8 *filename,I64 *_size,I64 *_attr)
{
U8 *buf=NULL;
CDirEntry de;
I64 c,blk_cnt,cur_dir_cluster;
DrvChk(dv);
*_size=0;
*_attr=0;
if (dv->fs_type!=FSt_ISO9660)
PrintErr("Not ISO9660 Drv\n");
else
try {
DrvLock(dv);
cur_dir_cluster=Name2DirCluster(dv,cur_dir);
if (ISO1FileFind(dv,cur_dir_cluster,filename,&de,FUF_JUST_FILES)) {
blk_cnt=(de.size+BLK_SIZE-1)>>BLK_SIZE_BITS;
buf=MAlloc(blk_cnt<<BLK_SIZE_BITS+1);
c=de.cluster;
c=RClustersBlks(dv,buf,c,blk_cnt);
buf[de.size]=0; //Terminate
*_size=de.size;
*_attr=FileAttr(de.name,de.attr);
}
DrvUnlock(dv);
} catch
DrvUnlock(dv);
return buf;
}
Bool ISO1Cd(U8 *name,I64 cur_dir_cluster)
{
CDirEntry de;
if (Fs->cur_dv->fs_type!=FSt_ISO9660)
PrintErr("Not ISO9660 Drv\n");
else if (ISO1FileFind(Fs->cur_dv,cur_dir_cluster,name,&de,FUF_JUST_DIRS))
return TRUE;
else {
"%s ",name;
PrintErr("File not found.\n");
}
return FALSE;
}
CDirEntry *ISO1FilesFind(U8 *files_find_mask,
I64 fuf_flags,CDirEntry *parent=NULL)
{
CDrv *dv=Fs->cur_dv;
CISO1DirEntry *buf,*buf2,*isoptr;
I64 i,cur_dir_cluster=Name2DirCluster(dv,Fs->cur_dir);
CDirEntry *res=NULL,*tmpde;
if (fuf_flags&~FUG_FILES_FIND)
throw('FUF');
isoptr=MAlloc(dv->spc<<BLK_SIZE_BITS);
RClusters(dv,isoptr,cur_dir_cluster,1);
if (isoptr->name_len==1 && !isoptr->name) {//curdir
i=(isoptr->size.little+dv->spc<<BLK_SIZE_BITS-1)/dv->spc<<BLK_SIZE_BITS;
buf=MAlloc(dv->spc<<BLK_SIZE_BITS*i);
RClusters(dv,buf,cur_dir_cluster,i);
Free(isoptr);
} else {
buf=isoptr;
i=1;
}
buf2=buf;
i*=dv->spc<<BLK_SIZE_BITS;
while (i>0) {
if (!buf->len) {
buf(U8 *)++;
i--;
} else {
tmpde=MAlloc(sizeof(CDirEntry));
if (ISO1CDirFill(tmpde,buf)) {
tmpde->parent=parent;
if (Bt(&fuf_flags,FUf_RECURSE) && tmpde->attr&RS_ATTR_DIR &&
*tmpde->name!='.') {
tmpde->next=res;
res=tmpde;
tmpde->full_name=DirNameAbs(tmpde->name);
if (Cd(tmpde->name)) {
tmpde->sub=ISO1FilesFind(files_find_mask,fuf_flags,tmpde);
Cd("..");
}
} else {
tmpde->full_name=FileNameAbs(tmpde->name);
if ((tmpde->attr & RS_ATTR_DIR ||
!Bt(&fuf_flags,FUf_JUST_DIRS)) &&
!(Bt(&fuf_flags,FUf_RECURSE) &&
*tmpde->name=='.' && tmpde->attr&RS_ATTR_DIR) &&
FilesFindMatch(tmpde->full_name,files_find_mask,fuf_flags)) {
tmpde->next=res;
res=tmpde;
} else
DirEntryDel(tmpde);
}
} else
DirEntryDel(tmpde);
i-=buf->len;
buf(U8 *)+=buf->len;
}
}
Free(buf2);
return res;
}
+637
View File
@@ -0,0 +1,637 @@
// See $LK,"RedSea File System",A="FI:::/Doc/RedSea.DD"$
U0 RedSeaFreeFreeLst(CDrv *dv)
{
CFreeLst *tmpf,*tmpf1;
Bool unlock;
try {
unlock=DrvLock(dv);
if (tmpf=dv->next_free) {
while (tmpf!=&dv->next_free) {
tmpf1=tmpf->next;
Free(tmpf);
tmpf=tmpf1;
}
}
dv->next_free=NULL;
if (unlock)
DrvUnlock(dv);
} catch
if (unlock)
DrvUnlock(dv);
}
U0 RedSeaFreeLstBuild(CDrv *dv)
{
Bool unlock;
CFreeLst *tmpf;
I64 i,first=dv->data_area,max_blk=dv->size+dv->drv_offset;
try {
unlock=DrvLock(dv);
if (dv->next_free)
RedSeaFreeFreeLst(dv);
QueInit(&dv->next_free);
while (first<max_blk) {
i=0; //count free clusters
while (first+i<max_blk) {
DrvFATBlkSet(dv,first+i);
if (Bt(dv->cur_fat_blk,(first+i-dv->data_area)&(BLK_SIZE<<3-1)))
break;
else
i++;
}
if (i) {
tmpf=AMAlloc(sizeof(CFreeLst));
tmpf->size=i;
tmpf->start=first;
QueIns(tmpf,dv->last_free);
}
first+=i+1;
}
if (unlock)
DrvUnlock(dv);
} catch
if (unlock)
DrvUnlock(dv);
}
U0 RedSeaInit(CDrv *dv)
{
CRedSeaBoot br;
Bool unlock;
try {
unlock=DrvLock(dv);
RBlks(dv,&br,dv->drv_offset,1);
if (br.signature!=MBR_PT_REDSEA || br.signature2!=0xAA55)
throw('Drv');
dv->fs_type=FSt_REDSEA;
RedSeaFreeFreeLst(dv);
dv->spc=1;
dv->size=br.sects;
dv->data_area=dv->drv_offset+br.bitmap_sects;
dv->root_cluster=br.root_cluster;
dv->fat1=dv->fat2=dv->drv_offset+1;
DrvFATBlkAlloc(dv);
if (unlock)
DrvUnlock(dv);
} catch
if (unlock)
DrvUnlock(dv);
}
Bool RedSeaValidate(U8 drv_let)
{
CDrv *dv;
CRedSeaBoot br;
if ((dv=Let2Drv(drv_let,FALSE)) && dv->fs_type==FSt_REDSEA &&
RBlks(dv,&br,dv->drv_offset,1) && br.signature==MBR_PT_REDSEA &&
br.signature2==0xAA55 && br.sects==dv->size)
return TRUE;
else
return FALSE;
}
U0 RedSeaFmt(U8 drv_let,Bool quick=TRUE)
{
U8 *root_dir;
CDirEntry *d_native;
CRedSeaBoot *br=CAlloc(BLK_SIZE);
CDrv *dv=Let2Drv(drv_let);
I64 i,n,root_dir_blks;
try {
DrvLock(dv);
// DrvTypeSet(drv_let,FSt_REDSEA);
DrvTypeSet(drv_let,FSt_FAT32);
dv->fs_type=FSt_REDSEA;
br->signature=MBR_PT_REDSEA;
br->signature2=0xAA55;
br->drv_offset=dv->drv_offset; //For CD/DVD image copy.
br->sects=dv->size;
n=(br->sects+BLK_SIZE<<3-1)/BLK_SIZE<<3;
br->bitmap_sects=n;
br->unique_id=GetTSC^Now()(U64);
br->root_cluster=0;
if (quick)
i=n+1;
else
i=dv->size;
WZeroBlks(dv,dv->drv_offset,i);
WBlks(dv,br,dv->drv_offset,1);
RedSeaInit(dv);
ClustersAlloc(dv,0,1,FALSE); //Alloc #1
root_dir_blks=MaxI64(1,dv->bd->init_root_dir_blks);
br->root_cluster=ClustersAlloc(dv,0,root_dir_blks,FALSE);
WBlks(dv,br,dv->drv_offset,1);
root_dir=CAlloc(BLK_SIZE*root_dir_blks);
d_native=root_dir-offset(CDirEntry.start);
d_native->attr=RS_ATTR_DIR|RS_ATTR_CONTIGUOUS;
*d_native->name='.';
d_native->cluster=br->root_cluster;
d_native->size=BLK_SIZE*root_dir_blks;
d_native->datetime=Now;
d_native(U8 *)+=CDIR_SIZE;
*d_native->name='.';
d_native->name[1]='.';
d_native->attr=RS_ATTR_DIR|RS_ATTR_CONTIGUOUS;
d_native->cluster=br->root_cluster;
d_native->datetime=Now;
WBlks(dv,root_dir,br->root_cluster,root_dir_blks);
RedSeaInit(dv);
DrvUnlock(dv);
} catch
DrvUnlock(dv);
Free(br);
Free(root_dir);
}
Bool RedSeaFileFind(CDrv *dv,I64 cur_dir_cluster,U8 *name,
CDirEntry *_res,I64 fuf_flags=0)
{//$LK,"FUF_JUST_DIRS",A="MN:FUF_JUST_DIRS"$, $LK,"FUF_JUST_FILES",A="MN:FUF_JUST_FILES"$
CDirEntry *buf,*buf2,*ptr;
U8 dname[CDIR_FILENAME_LEN];
I64 ch;
Bool res=FALSE,unlock;
if (fuf_flags&~FUG_FILE_FIND)
throw('FUF');
MemSet(_res,0,sizeof(CDirEntry));
DrvChk(dv);
if (dv->fs_type!=FSt_REDSEA)
PrintErr("Not RedSea Drv\n");
else if (!CFileNameTo(dname,name))
PrintErr("Invalid FileName.\n");
else
try {
unlock=DrvLock(dv);
buf2=MAlloc(BLK_SIZE);
RBlks(dv,buf2,cur_dir_cluster,1);
ptr=buf2(U8 *)-offset(CDirEntry.start);
buf=MAlloc(ptr->size);
RBlks(dv,buf,cur_dir_cluster,ptr->size>>BLK_SIZE_BITS);
Free(buf2);
ptr=buf(U8 *)-offset(CDirEntry.start);
*ptr->name='.';
ptr->name[1]=0;
while (TRUE) {
if (!(ch=*ptr->name))
break;
else if (!(ptr->attr & RS_ATTR_DELETED) &&
!(fuf_flags&FUF_JUST_DIRS && !(ptr->attr & RS_ATTR_DIR)) &&
!(fuf_flags&FUF_JUST_FILES && ptr->attr & RS_ATTR_DIR) &&
!StrCmp(dname,ptr->name)) {
MemCpy(&_res->attr,&ptr->attr,CDIR_SIZE);
res=TRUE;
goto rsff_done;
}
ptr(U8 *)+=CDIR_SIZE;
}
rsff_done:
Free(buf);
if (unlock)
DrvUnlock(dv);
} catch
if (unlock)
DrvUnlock(dv);
return res;
}
U8 *RedSeaFileRead(CDrv *dv,U8 *cur_dir,U8 *filename,I64 *_size,I64 *_attr)
{
U8 *buf=NULL;
CDirEntry de;
I64 c,blk_cnt,cur_dir_cluster;
DrvChk(dv);
*_size=0;
*_attr=0;
if (dv->fs_type!=FSt_REDSEA)
PrintErr("Not RedSea Drv\n");
else
try {
DrvLock(dv);
cur_dir_cluster=Name2DirCluster(dv,cur_dir);
if (RedSeaFileFind(dv,cur_dir_cluster,filename,&de,FUF_JUST_FILES)) {
blk_cnt=(de.size+BLK_SIZE-1)>>BLK_SIZE_BITS;
buf=MAlloc(blk_cnt<<BLK_SIZE_BITS+1);
c=de.cluster;
c=RBlks(dv,buf,c,blk_cnt);
buf[de.size]=0; //Terminate
*_size=de.size;
*_attr=FileAttr(de.name,de.attr);
}
DrvUnlock(dv);
} catch
DrvUnlock(dv);
return buf;
}
Bool RedSeaCd(U8 *name,I64 cur_dir_cluster)
{
CDirEntry de;
if (Fs->cur_dv->fs_type!=FSt_REDSEA)
PrintErr("Not RedSea Drv\n");
else if (RedSeaFileFind(Fs->cur_dv,cur_dir_cluster,name,&de,FUF_JUST_DIRS))
return TRUE;
else {
"%s ",name;
PrintErr("File not found.\n");
}
return FALSE;
}
U0 RedSeaFreeClusters(CDrv *dv,I64 c,I64 cnt)
{
CFreeLst *tmpf;
Bool found=FALSE,unlock,unlock_break;
DrvChk(dv);
if (!c) return;
if (dv->fs_type!=FSt_REDSEA)
PrintErr("Not RedSea Drv\n");
else
try {
unlock_break=BreakLock;
unlock=DrvLock(dv);
if (!dv->next_free)
RedSeaFreeLstBuild(dv);
tmpf=dv->next_free;
while (!found && tmpf!=&dv->next_free) {
if (tmpf->start+tmpf->size==c) {
tmpf->size+=cnt;
found=TRUE;
} else if (c+cnt==tmpf->start) {
tmpf->size+=cnt;
tmpf->start=c;
found=TRUE;
}
tmpf=tmpf->next;
}
if (!found) {
tmpf=AMAlloc(sizeof(CFreeLst));
tmpf->size=cnt;
tmpf->start=c;
QueIns(tmpf,dv->last_free);
}
while (cnt-->0) {
DrvFATBlkSet(dv,c);
LBtr(dv->cur_fat_blk,(c-dv->data_area)&(BLK_SIZE<<3-1));
LBts(&dv->fat_blk_dirty,0);
c++;
}
DrvFATBlkClean(dv);
if (unlock)
DrvUnlock(dv);
if (unlock_break)
BreakUnlock;
} catch {
if (unlock)
DrvUnlock(dv);
if (unlock_break)
BreakUnlock;
}
}
I64 RedSeaAllocClusters(CDrv *dv,I64 cnt)
{
CFreeLst *tmpf,*best_free=NULL;
I64 i,first,best_size=I64_MAX;
Bool unlock,unlock_break;
if (cnt<=0)
throw('Drv');
try {
unlock_break=BreakLock;
unlock=DrvLock(dv);
if (!dv->next_free)
RedSeaFreeLstBuild(dv);
tmpf=dv->next_free;
while (tmpf!=&dv->next_free) {
if (tmpf->size>=cnt && tmpf->size<best_size) {
best_free=tmpf;
best_size=tmpf->size;
if (tmpf->size==cnt)
break;
}
tmpf=tmpf->next;
}
if (!best_free)
throw('Drv');
first=best_free->start;
for (i=0;i<cnt;i++) {
DrvFATBlkSet(dv,first+i);
LBts(dv->cur_fat_blk,(first+i-dv->data_area)&(BLK_SIZE<<3-1));
LBts(&dv->fat_blk_dirty,0);
}
DrvFATBlkClean(dv);
if (best_free->size-=cnt)
best_free->start+=cnt;
else {
QueRem(best_free);
Free(best_free);
}
if (unlock)
DrvUnlock(dv);
if (unlock_break)
BreakUnlock;
} catch {
if (unlock)
DrvUnlock(dv);
if (unlock_break)
BreakUnlock;
}
return first;
}
Bool RedSeaDirNew(CDrv *dv,U8 *cur_dir,CDirEntry *tmpde,Bool free_old_chain)
{
CDirEntry *buf,*buf2,*ptr,de2;
CRedSeaBoot *br;
I64 c,ch,i=1,j=0,n=BLK_SIZE/CDIR_SIZE,dir_size,cur_dir_cluster;
Bool written=FALSE,unlock,unlock_break;
U8 *tmp,*parent_dir;
try {
unlock_break=BreakLock;
tmpde->attr|=RS_ATTR_CONTIGUOUS;
unlock=DrvLock(dv);
cur_dir_cluster=Name2DirCluster(dv,cur_dir);
buf2=MAlloc(BLK_SIZE);
RBlks(dv,buf2,cur_dir_cluster,1);
ptr=buf2(U8 *)-offset(CDirEntry.start);
buf=MAlloc(ptr->size);
RBlks(dv,buf,cur_dir_cluster,ptr->size>>BLK_SIZE_BITS);
dir_size=ptr->size;
ptr=buf(U8 *)-offset(CDirEntry.start)+CDIR_SIZE;
Free(buf2);
while (TRUE) {
if (!(ch=*ptr->name)) {
if (!written)
MemCpy(&ptr->start,&tmpde->start,CDIR_SIZE);
if ((i+1)*CDIR_SIZE+j<<BLK_SIZE_BITS<dir_size)
WBlks(dv,buf(U8 *)+j<<BLK_SIZE_BITS,cur_dir_cluster+j,1);
else {
buf2=CAlloc(dir_size+BLK_SIZE);
MemCpy(buf2,buf,dir_size);
RedSeaFreeClusters(dv,cur_dir_cluster,dir_size>>BLK_SIZE_BITS);
dir_size+=BLK_SIZE;
c=ClustersAlloc(dv,0,dir_size>>BLK_SIZE_BITS,TRUE);
Free(buf);
buf=buf2;
ptr=buf(U8 *)-offset(CDirEntry.start);
ptr->size=dir_size;
ptr->cluster=c;
WBlks(dv,buf,c,dir_size>>BLK_SIZE_BITS);
if (cur_dir_cluster==dv->root_cluster) {
br=CAlloc(BLK_SIZE);
RBlks(dv,br,dv->drv_offset,1);
br->root_cluster=c;
WBlks(dv,br,dv->drv_offset,1);
Free(br);
dv->root_cluster=c;
} else {
tmp=StrNew(cur_dir);
parent_dir=StrNew(cur_dir);
StrLastRem(parent_dir,"/",tmp);
if (!*parent_dir) {
Free(parent_dir);
parent_dir=StrNew("/");
}
if (RedSeaFileFind(dv,Name2DirCluster(dv,parent_dir),
tmp,&de2,FUF_JUST_DIRS)) {
de2.cluster=c;
de2.size=dir_size;
RedSeaDirNew(dv,parent_dir,&de2,FALSE);
} else
throw('Drv');
Free(tmp);
Free(parent_dir);
}
}
break;
} else if (ptr->attr & RS_ATTR_DELETED) {
if (!written) {
MemCpy(&ptr->start,&tmpde->start,CDIR_SIZE);
WBlks(dv,buf(U8 *)+j<<BLK_SIZE_BITS,cur_dir_cluster+j,1);
written=TRUE;
}
} else {
if (!StrCmp(tmpde->name,ptr->name)) {
if (free_old_chain)
RedSeaFreeClusters(dv,ptr->cluster,
(ptr->size+BLK_SIZE-1)>>BLK_SIZE_BITS);
if (!written)
MemCpy(&ptr->start,&tmpde->start,CDIR_SIZE);
else
ptr->attr|=RS_ATTR_DELETED;
WBlks(dv,buf(U8 *)+j<<BLK_SIZE_BITS,cur_dir_cluster+j,1);
break;
}
}
ptr(U8 *)+=CDIR_SIZE;
if (++i>=n) {
j++;
i=0;
}
}
Free(buf);
if (unlock)
DrvUnlock(dv);
if (unlock_break)
BreakUnlock;
} catch {
if (unlock)
DrvUnlock(dv);
if (unlock_break)
BreakUnlock;
}
return FALSE;
}
I64 RedSeaFilesDel(CDrv *dv,U8 *cur_dir,U8 *files_find_mask,I64 fuf_flags,
Bool del_dir,Bool print_msg)
{
CDirEntry *buf,*buf2,*ptr;
I64 i=0,res=0,ch,j=0,n=BLK_SIZE/CDIR_SIZE,cur_dir_cluster;
Bool unlock_break;
try {
unlock_break=BreakLock;
DrvLock(dv);
cur_dir_cluster=Name2DirCluster(dv,cur_dir);
buf2=MAlloc(BLK_SIZE);
RBlks(dv,buf2,cur_dir_cluster,1);
ptr=buf2(U8 *)-offset(CDirEntry.start);
buf=MAlloc(ptr->size);
RBlks(dv,buf,cur_dir_cluster,ptr->size>>BLK_SIZE_BITS);
Free(buf2);
ptr=buf(U8 *)-offset(CDirEntry.start);
*ptr->name='.';
ptr->name[1]=0;
while (TRUE) {
if (!(ch=*ptr->name))
break;
else if (!(ptr->attr & RS_ATTR_DELETED) && ch!='.' && (del_dir ||
!(ptr->attr & RS_ATTR_DIR)) &&
FilesFindMatch(ptr->name,files_find_mask,fuf_flags)) {
if (!(ptr->attr & RS_ATTR_DIR)) res++;
if (print_msg)
"Del %s\n",ptr->name;
ptr->attr|=RS_ATTR_DELETED;
WBlks(dv,buf(U8 *)+j<<BLK_SIZE_BITS,cur_dir_cluster+j,1);
RedSeaFreeClusters(dv,ptr->cluster,
(ptr->size+BLK_SIZE-1)>>BLK_SIZE_BITS);
}
ptr(U8 *)+=CDIR_SIZE;
if (++i>=n) {
j++;
i=0;
}
}
Free(buf);
DrvUnlock(dv);
if (unlock_break)
BreakUnlock;
} catch {
DrvUnlock(dv);
if (unlock_break)
BreakUnlock;
}
return res;
}
I64 RedSeaFileWrite(CDrv *dv,U8 *cur_dir,U8 *name,U8 *buf,I64 size,
CDate cdt,I64 attr)
{
CDirEntry de;
I64 c=0,blk_cnt;
MemSet(&de,0,sizeof(CDirEntry));
if (size<0) size=0;
if (dv->fs_type!=FSt_REDSEA)
PrintErr("Not RedSea Drv\n");
else if (!CFileNameTo(de.name,name))
PrintErr("Invalid FileName.\n");
else {
RedSeaFilesDel(dv,cur_dir,de.name,0,FALSE,FALSE);
de.size=size;
if (blk_cnt=(size+BLK_SIZE-1)>>BLK_SIZE_BITS)
c=ClustersAlloc(dv,0,blk_cnt,TRUE); //Always contiguous
else
c=INVALID_CLUSTER;
de.cluster=c;
de.attr=attr|RS_ATTR_CONTIGUOUS;
de.datetime=cdt;
if (blk_cnt)
WBlks(dv,buf,c,blk_cnt);
RedSeaDirNew(dv,cur_dir,&de,TRUE);
}
return c;
}
CDirEntry *RedSeaFilesFind(U8 *files_find_mask,I64 fuf_flags,
CDirEntry *parent=NULL)
{
CDrv *dv=Fs->cur_dv;
CDirEntry *buf,*buf2,*ptr,*res=NULL,*tmpde;
I64 ch,cur_dir_cluster;
if (fuf_flags&~FUG_FILES_FIND)
throw('FUF');
try {
DrvLock(dv);
cur_dir_cluster=Name2DirCluster(dv,Fs->cur_dir);
buf2=MAlloc(BLK_SIZE);
RBlks(dv,buf2,cur_dir_cluster,1);
ptr=buf2(U8 *)-offset(CDirEntry.start);
buf=MAlloc(ptr->size);
RBlks(dv,buf,cur_dir_cluster,ptr->size>>BLK_SIZE_BITS);
Free(buf2);
ptr=buf(U8 *)-offset(CDirEntry.start);
*ptr->name='.';
ptr->name[1]=0;
ptr(U8 *)+=CDIR_SIZE;
ptr->cluster=Name2ParentDirCluster(dv,Fs->cur_dir);
ptr(U8 *)-=CDIR_SIZE;
while (TRUE) {
if (!(ch=*ptr->name))
break;
else if (!(ptr->attr & RS_ATTR_DELETED)) {
tmpde=CAlloc(sizeof(CDirEntry));
MemCpy(&tmpde->start,&ptr->start,CDIR_SIZE);
tmpde->parent=parent;
if (Bt(&fuf_flags,FUf_RECURSE) && tmpde->attr&RS_ATTR_DIR &&
*tmpde->name!='.') {
tmpde->next=res;
res=tmpde;
tmpde->full_name=DirNameAbs(tmpde->name);
DrvUnlock(dv);
if (Cd(tmpde->name)) {
tmpde->sub=RedSeaFilesFind(files_find_mask,fuf_flags,tmpde);
Cd("..");
}
DrvLock(dv);
} else {
tmpde->full_name=FileNameAbs(tmpde->name);
if ((tmpde->attr&RS_ATTR_DIR ||
!Bt(&fuf_flags,FUf_JUST_DIRS)) &&
!(Bt(&fuf_flags,FUf_RECURSE) && *tmpde->name=='.' &&
tmpde->attr&RS_ATTR_DIR) &&
FilesFindMatch(tmpde->full_name,files_find_mask,fuf_flags)) {
tmpde->next=res;
res=tmpde;
} else
DirEntryDel(tmpde);
}
}
ptr(U8 *)+=CDIR_SIZE;
}
Free(buf);
DrvUnlock(dv);
} catch
DrvUnlock(dv);
return res;
}
Bool RedSeaMkDir(CDrv *dv,U8 *cur_dir,U8 *name,I64 entry_cnt)
{//entry_cnt is for preallocating dir blks.
I64 c,cur_dir_cluster=Name2DirCluster(dv,cur_dir),
size=CeilU64((entry_cnt+3)<<6,BLK_SIZE);
#assert CDIR_SIZE==64
U8 *buf=CAlloc(size);
CDirEntry *d_native=buf-offset(CDirEntry.start);
Bool unlock_break;
try {
unlock_break=BreakLock;
c=FileWrite(name,buf,size,0,RS_ATTR_DIR);
d_native->attr=RS_ATTR_DIR|RS_ATTR_CONTIGUOUS;
StrCpy(d_native->name,name);
d_native->cluster=c;
d_native->size=size;
d_native->datetime=Now;
d_native(U8 *)+=CDIR_SIZE;
d_native->attr=RS_ATTR_DIR|RS_ATTR_CONTIGUOUS;
*d_native->name='.';
d_native->name[1]='.';
d_native->name[2]=0;
d_native->cluster=cur_dir_cluster;
d_native->size=0;
d_native->datetime=Now;
WBlks(dv,buf,c,1);
Free(buf);
if (unlock_break)
BreakUnlock;
} catch
if (unlock_break)
BreakUnlock;
return TRUE;
}
+24
View File
@@ -0,0 +1,24 @@
#exe {Cd(__DIR__);};
#include "DskStrA"
#include "DskCache"
#include "DskATA"
#include "DskATAId"
#include "DskBlkDev"
#include "DskDrv"
#include "DskBlk"
#include "DskCluster"
#include "DskStrB"
#include "DskAddDev"
#include "DskDirA"
#include "FileSysISO"
#include "FileSysRedSea"
#include "FileSysFAT"
#include "DskDirContext"
#include "DskFind"
#include "DskDirB"
#include "DskFile"
#include "DskCFile"
#include "DskCopy"
#include "DskCDDVD"
#include "DskFmt"
#exe {Cd("..");};
+308
View File
@@ -0,0 +1,308 @@
//See $LK,"::/Doc/Credits.DD"$.
//See $LK,"CArcCompress",A="MN:CArcCompress"$, $LK,"CArcEntry",A="MN:CArcEntry"$, and $LK,"CArcCtrl",A="MN:CArcCtrl"$
asm {
/****
U0 ArcEntryGet(CArcCtrl *c)
{
I64 i;
CArcEntry *tmp,*tmp1;
if (c->entry_used) {
i=c->free_idx;
c->entry_used=FALSE;
c->cur_entry=c->next_entry;
c->cur_bits_in_use=c->next_bits_in_use;
if (c->next_bits_in_use<ARC_BITS_MAX) {
c->next_entry = &c->compress[i++];
if (i==c->free_limit) {
c->next_bits_in_use++;
c->free_limit=1<<c->next_bits_in_use;
}
} else {
do if (++i==c->free_limit)
i=c->min_table_entry;
while (c->hash[i]);
tmp=&c->compress[i];
c->next_entry=tmp;
tmp1=&c->hash[tmp->basecode];
while (tmp1) {
if (tmp1->next==tmp) {
tmp1->next=tmp->next;
break;
} else
tmp1=tmp1->next;
}
}
c->free_idx=i;
}
}
****/
_ARC_ENTRY_GET::
PUSH RBP
MOV RBP,RSP
PUSH RSI
PUSH RDI
MOV RSI,U64 SF_ARG1[RBP]
BTR U64 CArcCtrl.entry_used[RSI],0
JNC I32 @@30
MOV RDX,U64 CArcCtrl.free_idx[RSI]
MOV RAX,U64 CArcCtrl.next_entry[RSI]
MOV U64 CArcCtrl.cur_entry[RSI],RAX
MOV RCX,U64 CArcCtrl.next_bits_in_use[RSI]
MOV U64 CArcCtrl.cur_bits_in_use[RSI],RCX
CMP RCX,ARC_BITS_MAX
JAE @@05
MOV RAX,RDX
SHL RAX,4
LEA RAX,U64 CArcCtrl.compress[RSI+RAX]
MOV U64 CArcCtrl.next_entry[RSI],RAX
INC RDX
CMP U64 CArcCtrl.free_limit[RSI],RDX
JNE @@25
INC RCX
MOV U64 CArcCtrl.next_bits_in_use[RSI],RCX
MOV RAX,1
SHL RAX,CL
MOV U64 CArcCtrl.free_limit[RSI],RAX
JMP @@25
@@05: INC RDX
CMP U64 CArcCtrl.free_limit[RSI],RDX
JNE @@10
MOV RDX,U64 CArcCtrl.min_table_entry[RSI]
@@10: MOV RAX,U64 CArcCtrl.hash[RSI+RDX*8]
TEST RAX,RAX
JNZ @@05
MOV RDI,RDX
SHL RDI,4
LEA RDI,U64 CArcCtrl.compress[RSI+RDI]
MOV U32 CArcCtrl.next_entry[RSI],EDI
MOVZX RBX,U16 CArcEntry.basecode[RDI]
LEA RCX,U64 CArcCtrl.hash[RSI+RBX*8]
@@15: TEST RCX,RCX
JZ @@25
MOV RAX,U64 CArcEntry.next[RCX]
CMP RDI,RAX
JNE @@20
MOV RAX,U64 CArcEntry.next[RDI]
MOV U64 CArcEntry.next[RCX],RAX
JMP @@25
@@20: MOV RCX,RAX
JMP @@15
@@25: MOV U64 CArcCtrl.free_idx[RSI],RDX
@@30: POP RDI
POP RSI
POP RBP
RET1 8
}
_extern _ARC_ENTRY_GET U0 ArcEntryGet(CArcCtrl *c);
I64 ArcDetermineCompressionType(U8 *src,I64 size)
{
while (size--)
if (*src++&0x80)
return CT_8_BIT;
return CT_7_BIT;
}
U0 ArcCompressBuf(CArcCtrl *c)
{//Use $LK,"CompressBuf",A="MN:CompressBuf"$() unless doing more than one buf.
CArcEntry *tmp,*tmp1;
I64 ch,basecode;
U8 *src_ptr,*src_limit;
src_ptr=c->src_buf+c->src_pos;
src_limit=c->src_buf+c->src_size;
if (c->saved_basecode==U32_MAX)
basecode=*src_ptr++;
else
basecode=c->saved_basecode;
while (src_ptr<src_limit && c->dst_pos+c->cur_bits_in_use<=c->dst_size) {
ArcEntryGet(c);
ac_start:
if (src_ptr>=src_limit) goto ac_done;
ch=*src_ptr++;
if (tmp=c->hash[basecode])
do {
if (tmp->ch==ch) {
basecode=tmp-&c->compress[0];
goto ac_start;
}
} while (tmp=tmp->next);
BFieldOrU32(c->dst_buf,c->dst_pos,basecode);
c->dst_pos+=c->cur_bits_in_use;
c->entry_used=TRUE;
tmp=c->cur_entry;
tmp->basecode=basecode;
tmp->ch=ch;
tmp1=&c->hash[basecode];
tmp->next=tmp1->next;
tmp1->next=tmp;
basecode=ch;
}
ac_done:
c->saved_basecode=basecode;
c->src_pos=src_ptr-c->src_buf;
}
Bool ArcFinishCompression(CArcCtrl *c)
{//Do closing touch on archivew ctrl struct.
if (c->dst_pos+c->cur_bits_in_use<=c->dst_size) {
BFieldOrU32(c->dst_buf,c->dst_pos,c->saved_basecode);
c->dst_pos+=c->next_bits_in_use;
return TRUE;
} else
return FALSE;
}
U0 ArcExpandBuf(CArcCtrl *c)
{//Use $LK,"ExpandBuf",A="MN:ExpandBuf"$() unless you know what you're doing.
U8 *dst_ptr,*dst_limit;
I64 basecode,lastcode,code;
CArcEntry *tmp,*tmp1;
dst_ptr=c->dst_buf+c->dst_pos;
dst_limit=c->dst_buf+c->dst_size;
while (dst_ptr<dst_limit && c->stk_ptr!=c->stk_base)
*dst_ptr++ = * -- c->stk_ptr;
if (c->stk_ptr==c->stk_base && dst_ptr<dst_limit) {
if (c->saved_basecode==U32_MAX) {
lastcode=BFieldExtU32(c->src_buf,c->src_pos,
c->next_bits_in_use);
c->src_pos+=c->next_bits_in_use;
*dst_ptr++=lastcode;
ArcEntryGet(c);
c->last_ch=lastcode;
} else
lastcode=c->saved_basecode;
while (dst_ptr<dst_limit && c->src_pos+c->next_bits_in_use<=c->src_size) {
basecode=BFieldExtU32(c->src_buf,c->src_pos,
c->next_bits_in_use);
c->src_pos+=c->next_bits_in_use;
if (c->cur_entry==&c->compress[basecode]) {
*c->stk_ptr++=c->last_ch;
code=lastcode;
} else
code=basecode;
while (code>=c->min_table_entry) {
*c->stk_ptr++=c->compress[code].ch;
code=c->compress[code].basecode;
}
*c->stk_ptr++=code;
c->last_ch=code;
c->entry_used=TRUE;
tmp=c->cur_entry;
tmp->basecode=lastcode;
tmp->ch=c->last_ch;
tmp1=&c->hash[lastcode];
tmp->next=tmp1->next;
tmp1->next=tmp;
ArcEntryGet(c);
while (dst_ptr<dst_limit && c->stk_ptr!=c->stk_base)
*dst_ptr++ = * -- c->stk_ptr;
lastcode=basecode;
}
c->saved_basecode=lastcode;
}
c->dst_pos=dst_ptr-c->dst_buf;
}
CArcCtrl *ArcCtrlNew(Bool expand,I64 compression_type=CT_8_BIT)
{//MAlloc archive ctrl struct.
CArcCtrl *c;
c=CAlloc(sizeof(CArcCtrl));
if (expand) {
c->stk_base=MAlloc(1<<ARC_BITS_MAX);
c->stk_ptr=c->stk_base;
}
if (compression_type==CT_7_BIT)
c->min_bits=7;
else
c->min_bits=8;
c->min_table_entry=1<<c->min_bits;
c->free_idx=c->min_table_entry;
c->next_bits_in_use=c->min_bits+1;
c->free_limit=1<<c->next_bits_in_use;
c->saved_basecode=U32_MAX;
c->entry_used=TRUE;
ArcEntryGet(c);
c->entry_used=TRUE;
return c;
}
U0 ArcCtrlDel(CArcCtrl *c)
{//Free archive ctrl struct.
Free(c->stk_base);
Free(c);
}
U8 *ExpandBuf(CArcCompress *arc,CTask *mem_task=NULL)
{//See $LK,"::/Demo/Dsk/SerializeTree.HC"$.
CArcCtrl *c;
U8 *res;
if (!(CT_NONE<=arc->compression_type<=CT_8_BIT) ||
arc->expanded_size>mem_mapped_space)
throw('Compress');
res=MAlloc(arc->expanded_size+1,mem_task);
res[arc->expanded_size]=0; //terminate
switch [arc->compression_type] {
case CT_NONE:
MemCpy(res,&arc->body,arc->expanded_size);
break;
case CT_7_BIT:
case CT_8_BIT:
c=ArcCtrlNew(TRUE,arc->compression_type);
c->src_size=arc->compressed_size<<3;
c->src_pos=sizeof(CArcCompress)<<3;
c->src_buf=arc;
c->dst_size=arc->expanded_size;
c->dst_buf=res;
c->dst_pos=0;
ArcExpandBuf(c);
ArcCtrlDel(c);
break;
}
return res;
}
CArcCompress *CompressBuf(U8 *src,I64 size,CTask *mem_task=NULL)
{//See $LK,"::/Demo/Dsk/SerializeTree.HC"$.
CArcCompress *arc;
I64 size_out,compression_type=ArcDetermineCompressionType(src,size);
CArcCtrl *c=ArcCtrlNew(FALSE,compression_type);
c->src_size=size;
c->src_buf=src;
c->dst_size=(size+sizeof(CArcCompress))<<3;
c->dst_buf=CAlloc(c->dst_size>>3);
c->dst_pos=sizeof(CArcCompress)<<3;
ArcCompressBuf(c);
if (ArcFinishCompression(c) && c->src_pos==c->src_size) {
size_out=(c->dst_pos+7)>>3;
arc=MAlloc(size_out,mem_task);
MemCpy(arc,c->dst_buf,size_out);
arc->compression_type=compression_type;
arc->compressed_size=size_out;
} else {
arc=MAlloc(size+sizeof(CArcCompress),mem_task);
MemCpy(&arc->body,src,size);
arc->compression_type=CT_NONE;
arc->compressed_size=size+sizeof(CArcCompress);
}
arc->expanded_size=size;
Free(c->dst_buf);
ArcCtrlDel(c);
return arc;
}
+121
View File
@@ -0,0 +1,121 @@
U0 RawPutChar(I64 ch)
{/*For RAW output during boot and in debugger.
See $LK,"GrUpdateTextFG",A="MN:GrUpdateTextFG"$ for
the normal scrn text output routine.
See also $LK,"GrUpdateScrn",A="MN:GrUpdateScrn"$().
*/
I64 i,row,col;
U8 *ptr,*ptr1,*ptr2;
if (!(text.raw_flags&RWF_SHOW_DOLLAR)) {
if (ch=='$$') {
if (text.raw_flags&RWF_IN_DOLLAR) {
text.raw_flags&=~RWF_IN_DOLLAR;
if (!(text.raw_flags & RWF_LAST_DOLLAR)) {
text.raw_flags&=~RWF_LAST_DOLLAR;
return;
}
} else {
text.raw_flags|=RWF_IN_DOLLAR|RWF_LAST_DOLLAR;
return;
}
}
text.raw_flags&=~RWF_LAST_DOLLAR;
if (text.raw_flags&RWF_IN_DOLLAR)
return;
}
if (ch=='\t') {
RawPutChar(CH_SPACE);
while (text.raw_col & 7)
RawPutChar(CH_SPACE);
} else if (ch==CH_BACKSPACE) {
text.raw_col--;
RawPutChar(CH_SPACE);
text.raw_col--;
} else if (ch=='\n') {
RawPutChar(CH_SPACE);
while (text.raw_col % text.cols)
RawPutChar(CH_SPACE);
} else if (Bt(char_bmp_displayable,ch)) {
row=text.raw_col/text.cols%text.rows;
col=text.raw_col%text.cols;
if (!Bt(&sys_run_level,RLf_VGA)) { //if text mode
if (text.raw_flags&RWF_SCROLL && text.raw_col && !row && !col) {
MemCpy(text.vga_text_alias,text.vga_text_alias+text.cols*2,
text.cols*(text.rows-1)*2);
MemSet(text.vga_text_alias+text.cols*(text.rows-1)*2,0,text.cols*2);
text.raw_col-=text.cols;
row=text.rows-1;
}
ptr=text.vga_text_alias+(row*text.cols+col)*2;
ptr[0]=ch;
ptr[1]=BLACK<<4+WHITE;
} else {
OutU8(VGAP_IDX,VGAR_MAP_MASK);
OutU8(VGAP_DATA,0x0F); //All planes -- WHITE
if (text.raw_flags&RWF_SCROLL && text.raw_col && !row && !col) {
//Scroll cached image
MemCpy(text.raw_scrn_image,
text.raw_scrn_image+GR_WIDTH*FONT_HEIGHT>>3,
GR_WIDTH*(GR_HEIGHT-FONT_HEIGHT)>>3);
MemSet(text.raw_scrn_image+GR_WIDTH*(GR_HEIGHT-FONT_HEIGHT)>>3,0,
GR_WIDTH*FONT_HEIGHT>>3);
MemCpy(text.vga_alias,text.raw_scrn_image,GR_WIDTH*GR_HEIGHT>>3);
text.raw_col-=text.cols;
row=text.rows-1;
}
PUSHFD
CLI
ptr=ptr1=col+row*GR_WIDTH*FONT_HEIGHT>>3;
ptr+=text.vga_alias;
ptr1+=text.raw_scrn_image; //Write to cached image as well
ptr2=&text.font[ch&255];
for (i=0;i<FONT_HEIGHT;i++) {
*ptr=*ptr1=rev_bits_table[*ptr2++];
ptr+=GR_WIDTH>>3;
ptr1+=GR_WIDTH>>3;
}
POPFD
}
text.raw_col++;
}
}
U0 VGAFlush()
{//Flush winmgr vga cache, so updates whole scrn.
LBts(&sys_semas[SEMA_FLUSH_VGA_IMAGE],0);
}
U0 WinDerivedValsUpdate(CTask *task)
{//Those things calculated from other variables.
if (!task) task=Fs;
//Assert: This is called with TASKf_TASK_LOCK set
PUSHFD
CLI
task->win_width =task->win_right-task->win_left+1;
task->win_height=task->win_bottom-task->win_top+1;
task->pix_left =FONT_WIDTH*task->win_left;
task->pix_right =FONT_WIDTH*(task->win_right+1)-1;
task->pix_width =task->pix_right-task->pix_left+1;
task->pix_top =FONT_HEIGHT*task->win_top;
task->pix_bottom =FONT_HEIGHT*(task->win_bottom+1)-1;
task->pix_height =task->pix_bottom-task->pix_top+1;
POPFD
}
Bool WinInside(I64 x,I64 y,CTask *task=NULL,I64 border=0)
{//Is pixel (x,y) inside task's win? Border to FONT_WIDTH.
if (!task) task=Fs;
if (TaskValidate(task) && Bt(&task->display_flags,DISPLAYf_SHOW)) {
if (Bt(&task->display_flags,DISPLAYf_NO_BORDER))
border=0;
if (task->pix_left-border<=x<=task->pix_right+border &&
task->pix_top-border<=y<=task->pix_bottom+border)
return TRUE;
}
return FALSE;
}
+355
View File
@@ -0,0 +1,355 @@
class CLine
{
CLine *next,*last;
U8 *line;
};
U0 EdLiteUpdate(CLine *head,CLine *cur_line,I64 cur_col,I64 line_start_col)
{
I64 ch,i,j,k,k2,cursor_col,cursor_row=-1;
U8 *st;
CLine *tmpl=cur_line;
Bool done_eof=FALSE;
text.raw_col=0;
for (i=0;i<text.rows/2;i++)
if (tmpl->last!=head)
tmpl=tmpl->last;
for (i=0;i<text.rows;i++) {
if (cursor_row<0 && tmpl==cur_line) {
k=0;
for (j=0;j<cur_col;j++)
if (tmpl->line[j]=='\t')
k=(k+8)&~7;
else
k++;
cursor_col=k;
cursor_row=i;
}
if (tmpl!=head) {
st=tmpl->line;
k=0;
j=0;
while (ch=*st++) {
if (ch=='\t')
k2=(k+8)&~7;
else
k2=k+1;
if (line_start_col<=k<line_start_col+text.cols) {
'' ch;
j=k2-line_start_col;
}
k=k2;
}
if (j<text.cols)
'\n';
tmpl=tmpl->next;
} else {
if (!done_eof) {
'<EOF>';
done_eof=TRUE;
}
'\n';
}
}
text.raw_col=text.cols*cursor_row+cursor_col-line_start_col;
RawPutChar(0x7F);
}
Bool EdLite(U8 *filename,I64 num=1,I64 edf_dof_flags=0)
{//Light weight text editor for debugging.
U8 *src,*src2,*src3,*dst,*buf,*bin_data=NULL;
I64 i,cnt=0,ch,sc,size,bin_size=0,line_start_col=0,cur_col=0,
old_raw_flags=text.raw_flags;
CLine head,*tmpl,*tmpl1,*cur_line;
Bool res=FALSE,
old_raw=Raw(ON),
old_debug=DbgMode(ON),
old_single=SingleUser(ON);
if (!filename) filename=blkdev.tmp_filename;
buf=FileRead(filename,&size);
PUSHFD
CLI
text.raw_flags=text.raw_flags&~RWF_SCROLL|RWF_SHOW_DOLLAR;
kbd.scan_code=0;
QueInit(&head);
head.line=StrNew("");
if (buf) {
src=buf;
while (*src) {
src2=src;
while ((ch=*src++) && ch!='\r' && ch!='\n');
src--;
*src++=0;
if (!ch)
src--;
while (ch=='\r' && *src=='\n' || *src==CH_CURSOR)
src++;
dst=src3=src2;
while (ch=*src3++)
if (ch!='\n' && ch!=CH_CURSOR)
*dst++=ch;
*dst=0;
tmpl=MAlloc(sizeof(CLine));
tmpl->line=StrNew(src2);
QueIns(tmpl,head.last);
cnt++;
}
if (src+1-buf<size) {
bin_data=MAlloc(bin_size=size-(src-buf));
MemCpy(bin_data,src,bin_size);
}
Free(buf);
res=TRUE;
}
cur_line=head.next;
if (--num<0)
res=FALSE;
else {
if (num<=cnt)
while (num--)
cur_line=cur_line->next;
else {
cur_line=&head;
res=FALSE;
}
}
do {
if (cur_line==&head)
cur_col=0;
while (cur_col-line_start_col<0)
line_start_col-=8;
while (cur_col-line_start_col>=text.cols)
line_start_col+=8;
EdLiteUpdate(&head,cur_line,cur_col,line_start_col);
switch (ch=GetKey(&sc,FALSE,TRUE)) {
case 0:
switch (sc.u8[0]) {
case SC_CURSOR_UP:
if (cur_line->last!=&head)
cur_line=cur_line->last;
if (cur_col>StrLen(cur_line->line))
cur_col=StrLen(cur_line->line);
break;
case SC_CURSOR_DOWN:
if (cur_line!=&head)
cur_line=cur_line->next;
if (cur_col>StrLen(cur_line->line))
cur_col=StrLen(cur_line->line);
break;
case SC_CURSOR_RIGHT:
cur_col++;
if (cur_col>StrLen(cur_line->line)) {
tmpl=cur_line->next;
if (tmpl!=&head) {
cur_col=0;
cur_line=tmpl;
} else
cur_col=StrLen(cur_line->line);
}
break;
case SC_CURSOR_LEFT:
if (cur_col)
cur_col--;
else {
tmpl=cur_line->last;
if (tmpl!=&head) {
cur_line=tmpl;
cur_col=StrLen(tmpl->line);
}
}
break;
case SC_PAGE_UP:
for (i=1;i<text.rows;i++) {
if (cur_line->last!=&head)
cur_line=cur_line->last;
if (cur_col>StrLen(cur_line->line))
cur_col=StrLen(cur_line->line);
}
break;
case SC_PAGE_DOWN:
for (i=1;i<text.rows;i++) {
if (cur_line!=&head)
cur_line=cur_line->next;
if (cur_col>StrLen(cur_line->line))
cur_col=StrLen(cur_line->line);
}
break;
case SC_DELETE:
if (cur_col==StrLen(cur_line->line)) {
tmpl=cur_line->next;
if (cur_line!=&head && tmpl!=&head) {
src=MStrPrint("%s%s",cur_line->line,tmpl->line);
Free(cur_line->line);
Free(tmpl->line);
cur_line->line=src;
QueRem(tmpl);
Free(tmpl);
}
} else
StrCpy(cur_line->line+cur_col,cur_line->line+cur_col+1);
break;
}
break;
case '\n':
case '\r':
tmpl=MAlloc(sizeof(CLine));
tmpl->line=StrNew(cur_line->line+cur_col);
cur_line->line[cur_col]=0;
QueIns(tmpl,cur_line);
cur_line=tmpl;
cur_col=0;
break;
case CH_BACKSPACE:
if (cur_col) {
StrCpy(cur_line->line+cur_col-1,cur_line->line+cur_col);
cur_col--;
} else if (cur_line!=&head && cur_line->last!=&head) {
tmpl=cur_line->last;
src=MStrPrint("%s%s",tmpl->line,cur_line->line);
cur_col=StrLen(tmpl->line);
Free(cur_line->line);
Free(tmpl->line);
tmpl->line=src;
QueRem(cur_line);
Free(cur_line);
cur_line=tmpl;
}
break;
case CH_CTRLY:
if (cur_line!=&head) {
tmpl=cur_line;
cur_line=cur_line->next;
QueRem(tmpl);
Free(tmpl->line);
Free(tmpl);
cur_col=0;
}
break;
default:
if (Bt(char_bmp_printable,ch)) {
if (cur_line==&head) {
cur_line=MAlloc(sizeof(CLine));
cur_line->line=StrNew("");
QueIns(cur_line,head.last);
}
src=MAlloc(StrLen(cur_line->line)+2);
MemCpy(src,cur_line->line,cur_col);
src[cur_col]=ch;
if (cur_col<StrLen(cur_line->line))
StrCpy(src+cur_col+1,cur_line->line+cur_col);
else
src[cur_col+1]=0;
Free(cur_line->line);
cur_line->line=src;
cur_col++;
}
}
} while (ch!=CH_SHIFT_ESC && ch!=CH_ESC);
if (ch!=CH_ESC) {
if (edf_dof_flags&EDF_WAS_WRITE)
res=FALSE;
} else {
size=bin_size;
tmpl=head.next;
while (tmpl!=&head) {
size+=StrLen(tmpl->line)+1;
tmpl=tmpl->next;
}
buf=dst=MAlloc(size);
tmpl=head.next;
while (tmpl!=&head) {
i=StrLen(tmpl->line);
MemCpy(dst,tmpl->line,i);
dst+=i;
*dst++='\n';
tmpl=tmpl->next;
}
if (bin_data)
MemCpy(dst,bin_data,bin_size);
FileWrite(filename,buf,size);
Free(buf);
if (edf_dof_flags&EDF_WAS_WRITE)
res=TRUE;
}
tmpl=head.next;
while (tmpl!=&head) {
tmpl1=tmpl->next;
QueRem(tmpl);
Free(tmpl->line);
Free(tmpl);
tmpl=tmpl1;
}
Free(head.line);
Free(bin_data);
Raw(old_raw);
DbgMode(old_debug);
SingleUser(old_single);
text.raw_flags=text.raw_flags&~RWF_SHOW_DOLLAR|old_raw_flags&RWF_SHOW_DOLLAR;
POPFD
return res;
}
U0 ToFileLine(U8 *_fl_file_line,U8 **_filename,I64 *_linenum)
{//"FI:D:/Dir/File.HC,123" to "D:/Dir/File.HC" and 123.
U8 *st,*fl_file_line=StrNew(_fl_file_line);
I64 linenum;
StrFirstRem(fl_file_line,":");
st=StrNew(fl_file_line);
StrLastRem(fl_file_line,",",st);
linenum=Str2I64(st);
Free(st);
*_filename=fl_file_line;
*_linenum=linenum;
}
Bool EdLiteFileLine(U8 *fl_file_line,I64 edf_dof_flags=0)
{
Bool res;
U8 *filename;
I64 linenum;
ToFileLine(fl_file_line,&filename,&linenum);
res=EdLite(filename,linenum,edf_dof_flags);
Free(filename);
return res;
}
U0 FixSet(U8 *filename,I64 line)
{//Compiler calls this to set file line for Fix
U8 *st=MStrPrint("FL:%s,%d",filename,line);
while (LBts(&sys_semas[SEMA_FIX],0))
Yield;
Free(dbg.fix_file_line);
dbg.fix_file_line=AStrNew(st);
LBtr(&sys_semas[SEMA_FIX],0);
}
Bool Fix(I64 edf_dof_flags=0)
{//Jump to last err src code to fix it.
U8 *st;
Bool res=FALSE;
while (LBts(&sys_semas[SEMA_FIX],0))
Yield;
st=StrNew(dbg.fix_file_line);
LBtr(&sys_semas[SEMA_FIX],0);
if (st) {
if (IsRaw)
res=EdLiteFileLine(st,edf_dof_flags);
else
res=Ed(st,edf_dof_flags);
}
Free(st);
return res;
}
+132
View File
@@ -0,0 +1,132 @@
//See $LK,"::/Doc/Credits.DD"$.
U64 sys_font_cyrillic[256]= {
0x0000000000000000,0x0000000000000000,
0x000000FF00000000,0x000000FF00FF0000,//ÄÍ
0x1818181818181818,0x6C6C6C6C6C6C6C6C,//³º
0x181818F800000000,0x6C6C6CEC0CFC0000,//ÚÉ
0x1818181F00000000,0x6C6C6C6F607F0000,//¿»
0x000000F818181818,0x000000FC0CEC6C6C,//ÀÈ
0x0000001F18181818,0x0000007F606F6C6C,//Ù¼
0x0000000000000000,0x0000000000000000,
0x0000000000000000,0x0000000000000000,
0x0000000000000000,0x0000000000000000,
0x0000000000000000,0x0000000000000000,
0x0000000000000000,0x0000000000000000,
0x0000000000000000,0x0000000000000000,
0x0000000000000000,0x0000000000000000,
0x0000000000000000,0x0000000000000000,
0x0000000000000000,0x0008000000000000,//
0x0000000000000000,0x00180018183C3C18,// !
0x0000000000363636,0x006C6CFE6CFE6C6C,//"#
0x00187ED07C16FC30,0x0060660C18306606,//$$%
0x00DC66B61C36361C,0x0000000000181818,//&'
0x0030180C0C0C1830,0x000C18303030180C,//()
0x0000187E3C7E1800,0x000018187E181800,//*+
0x0C18180000000000,0x000000007E000000,//,-
0x0018180000000000,0x0000060C18306000,//./
0x003C666E7E76663C,0x007E181818181C18,//01
0x007E0C183060663C,0x003C66603860663C,//23
0x0030307E363C3830,0x003C6660603E067E,//45
0x003C66663E060C38,0x000C0C0C1830607E,//67
0x003C66663C66663C,0x001C30607C66663C,//89
0x0018180018180000,0x0C18180018180000,//:;
0x0030180C060C1830,0x0000007E007E0000,//<=
0x000C18306030180C,0x001800181830663C,//>?
0x003C06765676663C,0x006666667E66663C,//@A
0x003E66663E66663E,0x003C66060606663C,//BC
0x001E36666666361E,0x007E06063E06067E,//DE
0x000606063E06067E,0x003C66667606663C,//FG
0x006666667E666666,0x007E18181818187E,//HI
0x001C36303030307C,0x0066361E0E1E3666,//JK
0x007E060606060606,0x00C6C6D6D6FEEEC6,//LM
0x006666767E6E6666,0x003C66666666663C,//NO
0x000606063E66663E,0x006C36566666663C,//PQ
0x006666363E66663E,0x003C66603C06663C,//RS
0x001818181818187E,0x003C666666666666,//TU
0x00183C6666666666,0x00C6EEFED6D6C6C6,//VW
0x0066663C183C6666,0x001818183C666666,//XY
0x007E060C1830607E,0x003E06060606063E,//Z[
0x00006030180C0600,0x007C60606060607C,//\]
0x000000000000663C,0xFFFF000000000000,//^_
0x000000000030180C,0x007C667C603C0000,//`a
0x003E6666663E0606,0x003C6606663C0000,//bc
0x007C6666667C6060,0x003C067E663C0000,//de
0x000C0C0C3E0C0C38,0x3C607C66667C0000,//fg
0x00666666663E0606,0x003C1818181C0018,//hi
0x0E181818181C0018,0x0066361E36660606,//jk
0x003C18181818181C,0x00C6D6D6FE6C0000,//lm
0x00666666663E0000,0x003C6666663C0000,//no
0x06063E66663E0000,0xE0607C66667C0000,//pq
0x000606066E360000,0x003E603C067C0000,//rs
0x00380C0C0C3E0C0C,0x007C666666660000,//tu
0x00183C6666660000,0x006CFED6D6C60000,//vw
0x00663C183C660000,0x3C607C6666660000,//xy
0x007E0C18307E0000,0x003018180E181830,//z{
0x0018181818181818,0x000C18187018180C,//|}
0x000000000062D68C,0xFFFFFFFFFFFFFFFF,//~
0x1E30181E3303331E,0x007E333333003300,//€�
0x001E033F331E0038,0x00FC667C603CC37E,//‚ƒ
0x007E333E301E0033,0x007E333E301E0007,//„…
0x007E333E301E0C0C,0x3C603E03033E0000,//†‡
0x003C067E663CC37E,0x001E033F331E0033,//ˆ‰
0x001E033F331E0007,0x001E0C0C0C0E0033,//Š‹
0x003C1818181C633E,0x001E0C0C0C0E0007,//Œ�
0x00333F33331E0C33,0x00333F331E000C0C,//�
0x003F061E063F0038,0x00FE33FE30FE0000,//�‘
0x007333337F33367C,0x001E33331E00331E,//’“
0x001E33331E003300,0x001E33331E000700,//”•
0x007E33333300331E,0x007E333333000700,//–—
0x1F303F3333003300,0x001C3E63633E1C63,//˜™
0x001E333333330033,0x18187E03037E1818,//š›
0x003F67060F26361C,0x000C3F0C3F1E3333,//œ�
0x70337B332F1B1B0F,0x0E1B18187E18D870,//žŸ
0x000F11110F01111F,0x000101010101111F,// ¡
0x000F0107010F000A,0x001515150E151515,//¢£
0x000F10100E10100F,0x0011111315191111,//¤¥
0x001113151911040A,0x001215141414141E,//¦§
0x001111111111111F,0x000102040A111111,//¨©
0x00040E1515150E04,0x001010101E111111,//ª«
0x001F151515151515,0x000E12120E020203,//¬­
0x0013151513111111,0x000E11101C10110E,//®¯
0x0009151517151509,0x001112141E11111E,//°±
0x000E11110F010618,0x0007090709070000,//²³
0x00010101111F0000,0x000E011F110E000A,//´µ
0x0015150E15150000,0x000F100C100F0000,//¶·
0x0011131519110000,0x0013151911040A00,//¸¹
0x0009050305090000,0x00121514141E0000,//º»
0x001111151B110000,0x0011111F11110000,//¼½
0x00111111111F0000,0x00040404041F0000,//¾¿
0x0010101E11110000,0x001F151515150000,//ÀÁ
0x000E120E02030000,0x0013151311110000,//ÂÃ
0x0007090701010000,0x000E111C110E0000,//ÄÅ
0x0009151715090000,0x0012141E111E0000,//ÆÇ
0x0004120912040000,0x0004091209040000,//ÈÉ
0x001B091200000000,0x000000000009121B,//ÊË
0x001C141C090D0B09,0x000E110102040004,//ÌÍ
0x000304040E040418,0x001E02020F020A04,//ÎÏ
0x0004040000000000,0x0004040404000000,//ÐÑ
0x000E000A0A0A0000,0x000A000A0A0A0000,//ÒÓ
0x0001020408170005,0x00001B0E040E1B00,//ÔÕ
0x0001020408150205,0x00000E040404040E,//Ö×
0x00001F0A0A0A0A1F,0x0004040404150E04,//ØÙ
0x00040E1504040404,0x0001090D1F0D0901,//ÚÛ
0x001012161F161210,0x000111151F151101,//ÜÝ
0x0001020408110701,0x000000000C0C0000,//Þß
0x111F11121414141E,0x101F111111111111,//àá
0x101F151515151515,0x111F1112141E0000,//âã
0x040E15150E040400,0x101A111111110000,//äå
0x101F151515150000,0x0000000000000408,//æç
0x000000000000000A,0x0000000000000D12,//èé
0x000E011F110E0408,0x06040E11010E0000,//êë
0x0006080A0A0A000A,0x0000041F0E0E0E04,//ìí
0x00000A0011000A00,0x00000E1111110E00,//îï
0x0010101D1A150911,0x001C1019121D0911,//ðñ
0x001C0419121D0911,0x10101C1B12030203,//òó
0x00111F111F111F11,0x0000000600180003,//ôõ
0x041E141015070502,0x07020E021E020E02,//ö÷
0x0E040E041F040E04,0x1C08160017001600,//øù
0x1C080E080F080E08,0x00040E041F040E04,//úû
0x1C08090A0C0A0908,0x0609040A0A04120C,//üý
0x001414141E15151E,0xFFFFFFFFFFFFFFFF,//þÿ
};
+132
View File
@@ -0,0 +1,132 @@
//See $LK,"::/Doc/Credits.DD"$.
U64 sys_font_std[256]= {
0x0000000000000000,0x0000000000000000,
0x000000FF00000000,0x000000FF00FF0000,//騵
0x1818181818181818,0x6C6C6C6C6C6C6C6C,//竟
0x181818F800000000,0x6C6C6CEC0CFC0000,//硭
0x1818181F00000000,0x6C6C6C6F607F0000,//蕃
0x000000F818181818,0x000000FC0CEC6C6C,//檀
0x0000001F18181818,0x0000007F606F6C6C,//椇
0x0000000000000000,0x0000000000000000,
0x0000000000000000,0x0000000000000000,
0x0000000000000000,0x0000000000000000,
0x0000000000000000,0x0000000000000000,
0x0000000000000000,0x0000000000000000,
0x0000000000000000,0x0000000000000000,
0x0000000000000000,0x0000000000000000,
0x0000000000000000,0x0000000000000000,
0x0000000000000000,0x0008000000000000,//
0x0000000000000000,0x00180018183C3C18,// !
0x0000000000363636,0x006C6CFE6CFE6C6C,//"#
0x00187ED07C16FC30,0x0060660C18306606,//$$%
0x00DC66B61C36361C,0x0000000000181818,//&'
0x0030180C0C0C1830,0x000C18303030180C,//()
0x0000187E3C7E1800,0x000018187E181800,//*+
0x0C18180000000000,0x000000007E000000,//,-
0x0018180000000000,0x0000060C18306000,//./
0x003C666E7E76663C,0x007E181818181C18,//01
0x007E0C183060663C,0x003C66603860663C,//23
0x0030307E363C3830,0x003C6660603E067E,//45
0x003C66663E060C38,0x000C0C0C1830607E,//67
0x003C66663C66663C,0x001C30607C66663C,//89
0x0018180018180000,0x0C18180018180000,//:;
0x0030180C060C1830,0x0000007E007E0000,//<=
0x000C18306030180C,0x001800181830663C,//>?
0x003C06765676663C,0x006666667E66663C,//@A
0x003E66663E66663E,0x003C66060606663C,//BC
0x001E36666666361E,0x007E06063E06067E,//DE
0x000606063E06067E,0x003C66667606663C,//FG
0x006666667E666666,0x007E18181818187E,//HI
0x001C36303030307C,0x0066361E0E1E3666,//JK
0x007E060606060606,0x00C6C6D6D6FEEEC6,//LM
0x006666767E6E6666,0x003C66666666663C,//NO
0x000606063E66663E,0x006C36566666663C,//PQ
0x006666363E66663E,0x003C66603C06663C,//RS
0x001818181818187E,0x003C666666666666,//TU
0x00183C6666666666,0x00C6EEFED6D6C6C6,//VW
0x0066663C183C6666,0x001818183C666666,//XY
0x007E060C1830607E,0x003E06060606063E,//Z[
0x00006030180C0600,0x007C60606060607C,//\]
0x000000000000663C,0xFFFF000000000000,//^_
0x000000000030180C,0x007C667C603C0000,//`a
0x003E6666663E0606,0x003C6606663C0000,//bc
0x007C6666667C6060,0x003C067E663C0000,//de
0x000C0C0C3E0C0C38,0x3C607C66667C0000,//fg
0x00666666663E0606,0x003C1818181C0018,//hi
0x0E181818181C0018,0x0066361E36660606,//jk
0x003C18181818181C,0x00C6D6D6FE6C0000,//lm
0x00666666663E0000,0x003C6666663C0000,//no
0x06063E66663E0000,0xE0607C66667C0000,//pq
0x000606066E360000,0x003E603C067C0000,//rs
0x00380C0C0C3E0C0C,0x007C666666660000,//tu
0x00183C6666660000,0x006CFED6D6C60000,//vw
0x00663C183C660000,0x3C607C6666660000,//xy
0x007E0C18307E0000,0x003018180E181830,//z{
0x0018181818181818,0x000C18187018180C,//|}
0x000000000062D68C,0xFFFFFFFFFFFFFFFF,//~
0x1E30181E3303331E,0x007E333333003300,//��
0x001E033F331E0038,0x00FC667C603CC37E,//�
0x007E333E301E0033,0x007E333E301E0007,//�
0x007E333E301E0C0C,0x3C603E03033E0000,//�
0x003C067E663CC37E,0x001E033F331E0033,//�
0x001E033F331E0007,0x001E0C0C0C0E0033,//�
0x003C1818181C633E,0x001E0C0C0C0E0007,//�
0x00333F33331E0C33,0x00333F331E000C0C,//�
0x003F061E063F0038,0x00FE33FE30FE0000,//�
0x007333337F33367C,0x001E33331E00331E,//�
0x001E33331E003300,0x001E33331E000700,//�
0x007E33333300331E,0x007E333333000700,//�
0x1F303F3333003300,0x001C3E63633E1C63,//�
0x001E333333330033,0x18187E03037E1818,//�
0x003F67060F26361C,0x000C3F0C3F1E3333,//�
0x70337B332F1B1B0F,0x0E1B18187E18D870,//�
0x007E333E301E0038,0x001E0C0C0C0E001C,//嵗
0x001E33331E003800,0x007E333333003800,//╯
0x003333331F001F00,0x00333B3F3733003F,//丰
0x00007E007C36363C,0x00007E003C66663C,//戍
0x001E3303060C000C,0x000003033F000000,//貝
0x000030303F000000,0xF81973C67C1B3363,//物
0xC0F9F3E6CF1B3363,0x183C3C1818001800,//洎
0x0000CC663366CC00,0x00003366CC663300,//悖
0x1144114411441144,0x55AA55AA55AA55AA,//停
0xEEBBEEBBEEBBEEBB,0x1818181818181818,//眾
0x1818181F18181818,0x1818181F181F1818,//斯
0x6C6C6C6F6C6C6C6C,0x6C6C6C7F00000000,//須
0x1818181F181F0000,0x6C6C6C6F606F6C6C,//號
0x6C6C6C6C6C6C6C6C,0x6C6C6C6F607F0000,//獄
0x0000007F606F6C6C,0x0000007F6C6C6C6C,//播
0x0000001F181F1818,0x1818181F00000000,//噶
0x000000F818181818,0x000000FF18181818,//擱
0x181818FF00000000,0x181818F818181818,//藏
0x000000FF00000000,0x181818FF18181818,//霰
0x181818F818F81818,0x6C6C6CEC6C6C6C6C,//匸
0x000000FC0CEC6C6C,0x6C6C6CEC0CFC0000,//�
0x000000FF00EF6C6C,0x6C6C6CEF00FF0000,//帊
0x6C6C6CEC0CEC6C6C,0x000000FF00FF0000,//昅
0x6C6C6CEF00EF6C6C,0x000000FF00FF1818,//恘
0x000000FF6C6C6C6C,0x181818FF00FF0000,//倳
0x6C6C6CFF00000000,0x000000FC6C6C6C6C,//眑
0x000000F818F81818,0x181818F818F80000,//婭
0x6C6C6CFC00000000,0x6C6C6CEF6C6C6C6C,//笫
0x181818FF00FF1818,0x0000001F18181818,//崷
0x181818F800000000,0xFFFFFFFFFFFFFFFF,//窙
0xFFFFFFFF00000000,0x0F0F0F0F0F0F0F0F,//嗲
0xF0F0F0F0F0F0F0F0,0x00000000FFFFFFFF,//睧
0x006E3B133B6E0000,0x03031F331F331E00,//颬
0x0003030303637F00,0x0036363636367F00,//睼
0x007F660C180C667F,0x001E3333337E0000,//麧
0x03063E6666666600,0x00181818183B6E00,//緗
0x3F0C1E33331E0C3F,0x001C36637F63361C,//鴇
0x007736366363361C,0x001E33333E180C38,//膹
0x00007EDBDB7E0000,0x03067EDBDB7E3060,//擨
0x003C06033F03063C,0x003333333333331E,//闀
0x00003F003F003F00,0x003F000C0C3F0C0C,//貘
0x003F00060C180C06,0x003F00180C060C18,//覷
0x1818181818D8D870,0x0E1B1B1818181818,//鏷
0x000C0C003F000C0C,0x0000394E00394E00,//禴
0x000000001C36361C,0x0000001818000000,//矙
0x0000001800000000,0x383C3637303030F0,//𡜍
0x000000363636361E,0x0000003E061C301E,//𦶠
0x00003C3C3C3C0000,0xFFFFFFFFFFFFFFFF,//�
};
+338
View File
@@ -0,0 +1,338 @@
I64 HasLower(U8 *src)
{
I64 ch;
while (ch=*src++)
if ('a'<=ch<='z')
return TRUE;
return FALSE;
}
U0 HashFunSegFind(CHashTable *h,U8 *addr,
Bool *_has_lower,U64 *_best,CHash **_res)
{
Bool *has_lower=*_has_lower;
CHashExport *tmpex;
U64 i,j,best=*_best;
CHash *res=*_res;
for (i=0;i<=h->mask;i++) {
tmpex=h->body[i];
while (tmpex) {
j=0;
if (tmpex->type&HTT_FUN) {
if (!Bt(&tmpex(CHashFun *)->flags,Cf_EXTERN) &&
!Bt(&tmpex(CHashFun *)->flags,Ff_INTERNAL))
j=tmpex(CHashFun *)->exe_addr;
} else if (tmpex->type&HTT_EXPORT_SYS_SYM)
j=tmpex->val;
if (j) {
j=addr(I64)-j;
if (0<=j<=best) {
if (tmpex->type&HTT_EXPORT_SYS_SYM) {
if (j<best || j==best && !has_lower) {
has_lower=HasLower(tmpex->str);
best=j;
res=tmpex;
}
} else if (tmpex->type&HTT_FUN) {
if (j<best || j==best &&
(res && res->type&HTT_EXPORT_SYS_SYM||!has_lower)) {
has_lower=HasLower(tmpex->str);
best=j;
res=tmpex;
}
}
}
}
tmpex=tmpex->next;
}
}
*_has_lower=has_lower;
*_best=best;
*_res =res;
}
CHash *FunSegFind(U8 *addr,I64 *_offset)
{//See $LK,"Hash",A="HI:Hash"$.
CHash *res=NULL;
Bool has_lower=FALSE;
CTask *task;
CHashTable *h;
CCPU *c;
U64 i,best=0xFFFF;
if (!ChkCodePtr(addr)) {
*_offset=best;
return NULL;
}
if (IsDbgMode)
for (i=0;i<mp_cnt;i++) {
c=&cpu_structs[i];
task=c->seth_task;
do {
if (!TaskValidate(task)) goto fs_abort_task;
h=task->hash_table;
while (h) {
HashFunSegFind(h,addr,&has_lower,&best,&res);
h=h->next;
}
task=task->next_task;
} while (task!=c->seth_task);
fs_abort_task:
}
else {
h=Fs->hash_table;
while (h) {
HashFunSegFind(h,addr,&has_lower,&best,&res);
h=h->next;
}
}
*_offset=best;
return res;
}
U0 FunSegCacheAdd(CHash *tmps,U8 *addr)
{
I64 i;
CDbgInfo *dbg_info;
CFunSegCache *tmpfsc;
if (tmps && tmps->type&HTT_FUN &&
(dbg_info=tmps(CHashFun *)->dbg_info)) {
lock i=dbg.fun_seg_cache_index++;
tmpfsc=&dbg.fun_seg_cache[i&(FUN_SEG_CACHE_SIZE-1)];
tmpfsc->base=dbg_info->body[0];
if (addr<tmpfsc->base)
tmpfsc->base=addr;
tmpfsc->limit=dbg_info->body[dbg_info->max_line+1-dbg_info->min_line];
if (addr>=tmpfsc->limit)
tmpfsc->limit=addr+1;
i=MinI64(StrLen(tmps->str),FUN_SEG_CACHE_STR_LEN-1);
MemCpy(tmpfsc->str,tmps->str,i);
tmpfsc->str[i]=0;
tmpfsc->time_stamp=tS;
}
}
U8 *FunSegCacheFind(U8 *addr,I64 *_offset)
{
I64 i;
F64 timeout;
CFunSegCache *tmpfsc=dbg.fun_seg_cache;
if (addr==SYS_IDLE_PT) {
*_offset=0;
return "SYS_IDLE_PT";
} else {
timeout=tS+8.0;
for (i=0;i<FUN_SEG_CACHE_SIZE;i++,tmpfsc++)
if (tmpfsc->base<=addr<tmpfsc->limit &&
tmpfsc->time_stamp>timeout) {
*_offset=addr-tmpfsc->base;
return tmpfsc->str;
}
return NULL;
}
}
U0 StrPrintFunSeg(U8 *buf,I64 addr,I64 field_len,I64 flags)
{
I64 offset;
CHashExport *tmpex;
U8 *str,*str2;
Bool is_fun=FALSE;
if (!(flags&PRTF_TRUNCATE))
field_len=0;
if (addr) {
if (str=FunSegCacheFind(addr,&offset)) {
if (addr!=SYS_IDLE_PT)
is_fun=TRUE;
} else {
if (tmpex=FunSegFind(addr,&offset)) {
if (tmpex->type&HTT_FUN)
is_fun=TRUE;
FunSegCacheAdd(tmpex,addr);
str=tmpex->str;
}
}
if (str) {
if (offset>0xFFFF) offset=0xFFFF;
if (is_fun) {
str2=MStrPrint("&%s",str);
if (field_len>7) {
if (flags&PRTF_LEFT_JUSTIFY && StrLen(str2)<field_len-7)
StrPrint(buf,"%s+0x%04X",str2,offset);
else
StrPrint(buf,"%*ts+0x%04X",field_len-7,str2,offset);
} else
StrPrint(buf,"%s+0x%04X",str2,offset);
Free(str2);
} else {
if (field_len>7) {
if (flags&PRTF_LEFT_JUSTIFY && StrLen(str)<field_len-7)
StrPrint(buf,"%s+0x%04X",str,offset);
else
StrPrint(buf,"%*ts+0x%04X",field_len-7,str,offset);
} else
StrPrint(buf,"%s+0x%04X",str,offset);
}
return;
}
}
if (flags&PRTF_TRUNCATE)
StrPrint(buf,"%*tX",field_len,addr);
else
StrPrint(buf,"%X",addr);
}
I64 SrcLineNum(U8 *addr,I64 cnt=1)
{//linenum for src of addr.
CHashSrcSym *tmph;
I64 cur_line,first_line,last_line,num_lines,offset;
CDbgInfo *dbg_info;
U32 *body;
U8 *src,*src2;
if (tmph=FunSegFind(addr,&offset)) {
if (tmph->type&(HTT_FUN|HTT_EXPORT_SYS_SYM)) {
if (dbg_info=tmph->dbg_info) {
num_lines=dbg_info->max_line-dbg_info->min_line+1;
body=dbg_info->body;
//find first nonzero
first_line=0;
while (!body[first_line]) {
first_line++;
if (first_line>=num_lines)
return -1;
}
//find last nonzero
last_line=num_lines-1;
while (!body[last_line] && last_line>first_line)
last_line--;
//interpolate to guess line num
cur_line=ClampI64(ToF64(addr-body[first_line])*(last_line-first_line+1)/
(body[last_line]-body[first_line]+1),first_line,last_line);
//retreat while too high
while ((!body[cur_line] || body[cur_line]>=addr) && cur_line>first_line)
cur_line--;
//advance while to low
while ((!body[cur_line] || body[cur_line]<addr) && cur_line<last_line)
cur_line++;
if (addr<body[cur_line]+cnt)
return cur_line+dbg_info->min_line;
} else if (tmph->src_link) {
src =StrNew(tmph->src_link);
src2=StrNew(tmph->src_link);
StrLastRem(src,",",src2);
cur_line=Str2I64(src2);
Free(src);
Free(src2);
return cur_line;
}
}
}
return -1;
}
U8 *SrcFileName(U8 *addr,I64 cnt=1,CTask *mem_task=NULL)
{//MAlloc filename for src of addr.
CHashSrcSym *tmph;
I64 i,j,ii,offset,best=NULL,d,best_d;
U32 *body;
CDbgInfo *dbg_info;
U8 *src;
if ((tmph=FunSegFind(addr,&offset)) &&
tmph->type&(HTT_FUN|HTT_EXPORT_SYS_SYM)) {
if (dbg_info=tmph->dbg_info) {
j=dbg_info->max_line-dbg_info->min_line+1;
body=dbg_info->body;
best_d=I64_MAX;
for (i=0;i<j;i++) {
if (0<body[i]<=addr<body[i]+cnt) {
ii=i+1;
while (!body[ii])
ii++;
if (addr<body[ii]) {
d=addr(I64)-body[i];
if (d<best_d) {
best_d=d;
best=tmph->src_link;
}
}
}
}
} else
best=tmph->src_link;
}
if (best) {
src=StrNew(best,mem_task);
StrFirstRem(src,":");
StrLastRem(src,",");
return src;
} else
return NULL;
}
U8 *SrcEdLink(U8 *addr,I64 cnt=1,CTask *mem_task=NULL)
{//MAlloc file,line link to src of addr.
U8 *filename,*st,*st2;
I64 linenum;
if (filename=SrcFileName(addr,cnt)) {
linenum=SrcLineNum(addr,cnt);
if (linenum<1)
linenum=1;
st2=MStrPrint("FL:%s,%d",filename,linenum);
Free(filename);
st=StrNew(st2,mem_task);
Free(st2);
return st;
}
return NULL;
}
Bool PutSrcLink(U8 *addr,I64 cnt=1,U8 *buf=NULL)
{//Put to StdOut a $LK,"DolDoc",A="FI:::/Doc/DolDocOverview.DD"$ file,line link to src of addr.
U8 *src;
if (src=SrcEdLink(addr,cnt)) {
if (buf)
StrPrint(buf,"$$LK,\"%p\",A=\"%s\"$$",addr,src);
else
"$$LK,\"%p\",A=\"%s\"$$",addr,src;
Free(src);
return TRUE;
} else if (buf)
*buf=0;
return FALSE;
}
Bool E(U8 *addr,I64 cnt=512,I64 edf_dof_flags=0)
{//Edit src at addr.
U8 *st;
Bool res=FALSE;
if (st=SrcEdLink(addr,cnt)) {
if (IsRaw)
res=EdLiteFileLine(st,edf_dof_flags);
else
res=Ed(st,edf_dof_flags);
Free(st);
}
return res;
}
Bool Man(U8 *st,I64 edf_dof_flags=0)
{//Owner's manual for symbol. Edit src code for symbol.
Bool res=FALSE;
U8 **st2;
CHashSrcSym *tmph;
if (IsRaw) {
if ((tmph=HashFind(st,Fs->hash_table,HTG_SRC_SYM)) && tmph->src_link)
res=EdLiteFileLine(tmph->src_link,edf_dof_flags);
} else {
st2=MStrPrint("MN:%s",st);
res=Ed(st2,edf_dof_flags);
Free(st2);
}
return res;
}
+502
View File
@@ -0,0 +1,502 @@
U0 JobDel(CJob *tmpc)
{//Free one cmd node.
Free(tmpc->aux_str);
Free(tmpc);
}
U0 JobQueDel(CJob *head)
{
CJob *tmpc=head->next,*tmpc1;
while (tmpc!=head) {
tmpc1=tmpc->next;
QueRem(tmpc);
JobDel(tmpc);
tmpc=tmpc1;
}
}
U0 JobCtrlInit(CJobCtrl *ctrl)
{
QueInit(&ctrl->next_waiting);
QueInit(&ctrl->next_done);
ctrl->flags=0;
}
U0 TaskRstAwaitingMsg(CTask *task=NULL)
{//Pop-ups get parent messages so wake-up our pop-ups if we got a msg.
if (!task) task=Fs;
PUSHFD
CLI
do {
if (TaskValidate(task))
LBtr(&task->task_flags,TASKf_AWAITING_MSG);
else
break;
} while (task=task->popup_task);
POPFD
}
CJob *TaskExe(CTask *srv,CTask *master,U8 *data,I64 flags)
{//Queues a request to compile and execute src code text.
CJob *res;
if (!data || !TaskValidate(srv) || master && !TaskValidate(master) ||
srv->popup_task && !Bt(&srv->task_flags,TASKf_FILTER_INPUT))
return NULL;
res=ACAlloc(sizeof(CJob));
res->master_task=master;
res->job_code=JOBT_EXE_STR;
res->flags=flags;
res->aux_str=AStrNew(data);
res->ctrl=&srv->srv_ctrl;
PUSHFD
CLI
while (LBts(&srv->srv_ctrl.flags,JOBCf_LOCKED))
PAUSE
if (!TaskValidate(srv)) {
LBtr(&srv->srv_ctrl.flags,JOBCf_LOCKED);
POPFD
JobDel(res);
return NULL;
} else {
LBtr(&srv->task_flags,TASKf_IDLE);
TaskRstAwaitingMsg(srv);
QueIns(res,srv->srv_ctrl.last_waiting);
LBtr(&srv->srv_ctrl.flags,JOBCf_LOCKED);
if (Bt(&flags,JOBf_WAKE_MASTER)) {
Suspend(master);
Yield;
}
}
POPFD
return res;
}
CJob *TaskText(CTask *srv,CTask *master,U8 *data,I64 flags)
{//Post StdIn text to servant task. Tell who the master task is.
CJob *res;
CTask *task;
if (!data || !TaskValidate(srv) || master && !TaskValidate(master) ||
srv->popup_task && !Bt(&srv->task_flags,TASKf_FILTER_INPUT))
return NULL;
res=ACAlloc(sizeof(CJob));
res->master_task=master; //in case somebody cares
res->job_code=JOBT_TEXT_INPUT;
res->flags=flags;
res->aux_str=AStrNew(data);
PUSHFD
task=srv->last_input_filter_task;
if (Bt(&flags,JOBf_HIGHEST_PRIORITY) || task==srv) {
if (task!=srv)
TaskWait(srv);
task=Spawn(&InputFilterTask,NULL,"Input Filter",,srv);
CLI
task->next_input_filter_task=srv->next_input_filter_task;
task->last_input_filter_task=srv;
srv->next_input_filter_task=task;
task->next_input_filter_task->last_input_filter_task=task;
} else {
CLI
task=srv->next_input_filter_task;
}
res->ctrl=&task->srv_ctrl;
while (LBts(&task->srv_ctrl.flags,JOBCf_LOCKED))
PAUSE
if (!TaskValidate(task)) {
JobDel(res);
res=NULL;
} else {
LBtr(&task->task_flags,TASKf_IDLE);
TaskRstAwaitingMsg(task);
QueIns(res,task->srv_ctrl.last_waiting);
LBtr(&task->srv_ctrl.flags,JOBCf_LOCKED);
}
POPFD
return res;
}
CJob *TaskMsg(CTask *_srv,CTask *master,
I64 msg_code,I64 arg1,I64 arg2,I64 flags)
{//Post message to servant task. Tell who the master task is.
//See $LK,"flags",A="MN:JOBf_WAKE_MASTER"$ and $LK,"msg_code",A="MN:MSG_CMD"$.
CJob *tmpc1,*tmpc;
CTask *srv=_srv;
if (!TaskValidate(srv) || master && !TaskValidate(master)||
srv->popup_task && !Bt(&srv->task_flags,TASKf_FILTER_INPUT))
return NULL;
tmpc=ACAlloc(sizeof(CJob));
tmpc->master_task=master;
tmpc->job_code=JOBT_MSG;
tmpc->msg_code=AbsI64(msg_code); //negative means do a down and up
tmpc->aux1=arg1;
tmpc->aux2=arg2;
tmpc->flags=flags;
PUSHFD
if (Bt(&sys_semas[SEMA_RECORD_MACRO],0) &&
srv!=sys_macro_task && msg_code==MSG_KEY_DOWN) {
tmpc1=AMAllocIdent(tmpc);
CLI
QueIns(tmpc1,sys_macro_head.last);
}
CLI
while (Bt(&srv->task_flags,TASKf_FILTER_INPUT) &&
!Bt(&flags,JOBf_DONT_FILTER))
srv=srv->next_input_filter_task;
tmpc->ctrl=&srv->srv_ctrl;
while (LBts(&srv->srv_ctrl.flags,JOBCf_LOCKED))
PAUSE
if (!TaskValidate(srv)) {
JobDel(tmpc);
tmpc=NULL;
} else {
LBtr(&srv->task_flags,TASKf_IDLE);
TaskRstAwaitingMsg(srv);
QueIns(tmpc,srv->srv_ctrl.last_waiting);
LBtr(&srv->srv_ctrl.flags,JOBCf_LOCKED);
}
POPFD
if (msg_code<0) //Down-Up
TaskMsg(_srv,master,-msg_code+1,arg1,arg2,flags);
return tmpc;
}
Bool JobResScan(CJob *rqst=NULL,I64 *_res=NULL)
{//Check rqst complete, return with or without.
CJobCtrl *ctrl;
CJob *tmpc,*tmpc1;
if (!rqst || Bt(&rqst->flags,JOBf_DONE)) {
if (!rqst || rqst->master_task)
ctrl=&Fs->srv_ctrl;
else
ctrl=rqst->ctrl;
PUSHFD
CLI
while (LBts(&ctrl->flags,JOBCf_LOCKED))
PAUSE
tmpc1=&ctrl->next_done;
tmpc=tmpc1->next;
while (tmpc!=tmpc1) {
if (!rqst || rqst==tmpc) {
QueRem(tmpc);
LBtr(&ctrl->flags,JOBCf_LOCKED);
POPFD
if (_res)
*_res=tmpc->res;
JobDel(tmpc);
return TRUE;
}
tmpc=tmpc->next;
}
LBtr(&ctrl->flags,JOBCf_LOCKED);
POPFD
}
if (_res)
*_res=0;
return FALSE;
}
I64 JobResGet(CJob *rqst=NULL)
{//See $LK,"::/Demo/MultiCore/Lock.HC"$
I64 res;
CJob *tmpc1;
if (!rqst) {
tmpc1=&Fs->srv_ctrl.next_done;
while (tmpc1==tmpc1->next) {
LBts(&Fs->task_flags,TASKf_IDLE);
Yield;
}
} else {
while (!Bt(&rqst->flags,JOBf_DONE)) {
LBts(&Fs->task_flags,TASKf_IDLE);
Yield;
}
}
LBtr(&Fs->task_flags,TASKf_IDLE);
//Could get taken by someone else.
JobResScan(rqst,&res);
return res;
}
U0 TaskWait(CTask *task=NULL,Bool cmd_line_pmt=FALSE)
{//Wait for idle.
CTask *task1;
CJob *tmpc1;
if (!task) task=Fs;
if (TaskValidate(task)) {
PUSHFD
CLI
while (TRUE) {
task1=task->last_input_filter_task;
tmpc1=&task1->srv_ctrl.next_waiting;
if (task1==Fs || !TaskValidate(task1) ||
tmpc1==tmpc1->next && Bt(&task1->task_flags,TASKf_IDLE) &&
(!cmd_line_pmt || Bt(&task1->task_flags,TASKf_CMD_LINE_PMT)))
break;
Yield;
}
POPFD
}
}
U0 PostMsg(CTask *task,I64 msg_code,I64 arg1,I64 arg2,I64 flags=0)
{//Post message to a task and return immediately. See $LK,"msg_code",A="MN:MSG_CMD"$.
if (TaskValidate(task)) {
if (Bt(&task->task_flags,TASKf_INPUT_FILTER_TASK))
TaskMsg(task->last_input_filter_task,NULL,msg_code,arg1,arg2,
flags|1<<JOBf_DONT_FILTER);
else
TaskMsg(task,NULL,msg_code,arg1,arg2,flags);
}
}
U0 PostMsgWait(CTask *task,I64 msg_code,I64 arg1,I64 arg2,I64 flags=0)
{//Post message to a task and wait until task is idle.See $LK,"msg_code",A="MN:MSG_CMD"$.
PostMsg(task,msg_code,arg1,arg2,flags);
TaskWait(task);
}
U0 Msg(I64 msg_code,I64 arg1,I64 arg2,I64 flags=0)
{//Post message to current task and return immediately.
//See $LK,"msg_code",A="MN:MSG_CMD"$.
PostMsg(Fs,msg_code,arg1,arg2,flags);
}
#define JOB_DONE 0
#define JOB_CONT 1
#define JOB_EXIT 2
I64 JobRunOne(I64 run_flags,CJobCtrl *ctrl)
{//Called with ctrl->flags,JOBCf_LOCKED.
CJob *tmpc=ctrl->next_waiting;
CTask *master;
I64 res,flags=tmpc->flags,old_flags=GetRFlags;
if (Bt(&flags,JOBf_EXIT_ON_COMPLETE))
res=JOB_EXIT;
else
res=JOB_CONT;
switch (tmpc->job_code) {
case JOBT_SPAWN_TASK:
QueRem(tmpc);
LBts(&tmpc->flags,JOBf_DISPATCHED);
LBtr(&ctrl->flags,JOBCf_LOCKED);
if (tmpc->aux_str)
tmpc->spawned_task=Spawn(tmpc->addr,tmpc->fun_arg,
tmpc->aux_str,,tmpc->aux1,tmpc->aux2,tmpc->flags);
else
tmpc->spawned_task=Spawn(tmpc->addr,tmpc->fun_arg,
"Unnamed",,tmpc->aux1,tmpc->aux2,tmpc->flags);
break;
case JOBT_CALL:
QueRem(tmpc);
LBts(&tmpc->flags,JOBf_DISPATCHED);
LBtr(&ctrl->flags,JOBCf_LOCKED);
SetRFlags(run_flags);
LBtr(&Fs->task_flags,TASKf_IDLE);
try
tmpc->res=(*tmpc->addr)(tmpc->fun_arg);
catch
Fs->catch_except=TRUE;
SetRFlags(old_flags);
break;
case JOBT_EXE_STR:
QueRem(tmpc);
LBts(&tmpc->flags,JOBf_DISPATCHED);
LBtr(&ctrl->flags,JOBCf_LOCKED);
SetRFlags(run_flags);
LBtr(&Fs->task_flags,TASKf_IDLE);
try
tmpc->res=ExePrint("%s",tmpc->aux_str);
catch
Fs->catch_except=TRUE;
SetRFlags(old_flags);
break;
default:
res=JOB_DONE;
}
if (res) {
if (master=tmpc->master_task) {
if (!Bt(&flags,JOBf_FREE_ON_COMPLETE)) {
CLI
while (LBts(&master->srv_ctrl.flags,JOBCf_LOCKED))
PAUSE
QueIns(tmpc,master->srv_ctrl.last_done);
LBts(&tmpc->flags,JOBf_DONE);
LBtr(&master->srv_ctrl.flags,JOBCf_LOCKED);
SetRFlags(old_flags);
}
if (Bt(&flags,JOBf_FOCUS_MASTER) &&
!Bt(&master->win_inhibit,WIf_SELF_FOCUS))
sys_focus_task=master;
if (Bt(&flags,JOBf_WAKE_MASTER))
Suspend(master,FALSE);
}
if (Bt(&flags,JOBf_FREE_ON_COMPLETE))
JobDel(tmpc);
else if (!master) {
CLI
while (LBts(&ctrl->flags,JOBCf_LOCKED))
Yield;
QueIns(tmpc,ctrl->last_done);
LBts(&tmpc->flags,JOBf_DONE);
LBtr(&ctrl->flags,JOBCf_LOCKED);
SetRFlags(old_flags);
}
}
return res;
}
I64 JobsHndlr(I64 run_flags,CTask *task=NULL)
{//Handle all waiting cmds and return.
I64 cnt=0,old_flags=GetRFlags;
if (!task) task=Fs;
while (TRUE) {
CLI
while (LBts(&task->srv_ctrl.flags,JOBCf_LOCKED))
PAUSE
if (task->srv_ctrl.next_waiting!=&task->srv_ctrl)
switch (JobRunOne(run_flags,&task->srv_ctrl)) {
case JOB_CONT:
cnt++;
break;
case JOB_EXIT:
Exit;
case JOB_DONE:
goto jh_done;
}
else
goto jh_done;
}
jh_done:
LBtr(&task->srv_ctrl.flags,JOBCf_LOCKED);
SetRFlags(old_flags);
return cnt;
}
I64 PopUp(U8 *buf,CTask *parent=NULL,CTask **_pu_task=NULL)
{//Execute code in $LK,"PopUp",A="MN:PopUp"$ task.
I64 res;
CJob *tmpc;
CTask *task=Spawn(&SrvCmdLine,NULL,"Servant",,parent);
if (!parent) {
TaskExe(task,parent,buf,1<<JOBf_EXIT_ON_COMPLETE|1<<JOBf_FREE_ON_COMPLETE);
if (_pu_task) *_pu_task=task;
return 0;
} else {
Fs->popup_task=task;
tmpc=TaskExe(task,parent,buf,1<<JOBf_WAKE_MASTER|1<<JOBf_FOCUS_MASTER);
if (_pu_task) *_pu_task=task;
JobResScan(tmpc,&res);
Fs->popup_task=NULL;
Kill(task);
if (_pu_task) *_pu_task=NULL;
return res;
}
}
I64 PopUpPrint(U8 *fmt,...)
{//Execute code in $LK,"PopUp",A="MN:PopUp"$ task.
U8 *buf=StrPrintJoin(NULL,fmt,argc,argv);
I64 res;
res=PopUp(buf,Fs);
Free(buf);
return res;
}
I64 Adam(U8 *fmt,...)
{//Make adam_task execute code.
I64 res;
U8 *buf=StrPrintJoin(NULL,fmt,argc,argv);
CJob *tmpc;
if (Fs==adam_task) {
tmpc=TaskExe(adam_task,Fs,buf,0);
JobsHndlr(GetRFlags);
} else {
TaskWait(adam_task);
tmpc=TaskExe(adam_task,Fs,buf,1<<JOBf_WAKE_MASTER);
}
JobResScan(tmpc,&res);
Free(buf);
return res;
}
U0 AdamLog(U8 *fmt,...)
{//Display text in adam_task.
U8 *buf=StrPrintJoin(NULL,fmt,argc,argv);
if (Fs==adam_task)
"%s",buf;
else if (!IsSingleUser)
Adam("\"%%s\",%d;",buf);
Free(buf);
}
U0 AdamErr(U8 *fmt,...)
{//Display red blinking Err text in adam_task.
U8 *buf=StrPrintJoin(NULL,fmt,argc,argv),
*st=MStrPrint(ST_ERR_ST "%s",buf);
if (Fs==adam_task)
"%s",st;
else if (!IsSingleUser)
Adam("\"%%s\",%d;",st);
Free(st);
Free(buf);
}
U0 XTalk(CTask *task,U8 *fmt,...)
{//Sends text to other task. See $LK,"::/Misc/OSTestSuite.HC"$.
U8 *buf=StrPrintJoin(NULL,fmt,argc,argv),*st=AStrNew(buf),
*st2=MStrPrint("\"%%s\",%d;Free(%d);",st,st);
TaskText(task,NULL,st2,0);
Free(st2);
Free(buf);
}
U0 XTalkWait(CTask *task,U8 *fmt,...)
{//Send text to other task and wait for it to idle.
U8 *buf=StrPrintJoin(NULL,fmt,argc,argv),*st=AStrNew(buf),
*st2=MStrPrint("\"%%s\",%d;Free(%d);",st,st);
TaskText(task,NULL,st2,0);
Free(st2);
Free(buf);
TaskWait(task);
}
U0 InStr(U8 *fmt,...)
{//Send InFile code to self.
U8 *buf=StrPrintJoin(NULL,fmt,argc,argv);
if (Bt(&Fs->task_flags,TASKf_INPUT_FILTER_TASK))
ExePrint("%s",buf);
else
TaskText(Fs,NULL,buf,1<<JOBf_HIGHEST_PRIORITY);
Free(buf);
}
U0 InFile(U8 *filename)
{//Send InFile code file to self.
U8 *name=DftExt(filename,"IN.Z");
InStr("Cd(\"%C:%s\");;#include \"%s\"",
Drv2Let(Fs->cur_dv),Fs->cur_dir,name);
Free(name);
}
U0 In(U8 *fmt,...)
{//Send text to own input buffer. See $LK,"::/Demo/AcctExample/TOS/TOSDistro.HC"$.
U8 *buf=StrPrintJoin(NULL,fmt,argc,argv),*st=AStrNew(buf);
InStr("\"%%s\",%d;Free(%d);",st,st);
Free(buf);
}
U0 XTalkStr(CTask *task,U8 *fmt,...)
{//Send InFile code to other task.
U8 *buf=StrPrintJoin(NULL,fmt,argc,argv);
TaskText(task,NULL,buf,0);
Free(buf);
}
U0 XTalkStrWait(CTask *task,U8 *fmt,...)
{//Send InFile code to other task and wait for it to idle.
U8 *buf=StrPrintJoin(NULL,fmt,argc,argv);
TaskText(task,NULL,buf,0);
Free(buf);
TaskWait(task);
}
+173
View File
@@ -0,0 +1,173 @@
//This is run in a $LK,"#exe",A="FF:::/Kernel/Kernel.PRJ,KCfg"${}.
U8 *kernel_cfg_options="MemInit\0HeapInit\0VarInit\0StaffMode\0"
"HomeDir\0NoMP\0TextMode\0DontProbe\0AutoMountIDE\0DbgDistro\0Help\0";
#define CFG_MEM_INIT 0
#define CFG_HEAP_INIT 1
#define CFG_VAR_INIT 2
#define CFG_STAFF_MODE 3
#define CFG_HOME_DIR 4
#define CFG_NO_MP 5
#define CFG_TEXT_MODE 6
#define CFG_DONT_PROBE 7
#define CFG_AUTO_MOUNT_IDE 8
#define CFG_DBG_DISTRO 9
#define CFG_OPTIONS_NUM 10
#define CFG_HELP 10
class CKCfg
{
U8 *dsk_cache_size_exp;
CDoc *add_dev;
U8 *dbg_distro_file,*dbg_distro_start;
U8 *home_dir;
Bool opts[CFG_OPTIONS_NUM];
U8 mem_init_val,heap_init_val,var_init_val,
boot_drv_let,auto_mount_ide_hd_let,auto_mount_ide_cd_let;
};
CDoc *KCfgAddDev(CKCfg *c)
{
I64 ch;
CDoc *doc=DocNew;
"\n\nIn anticipation of the drives you will\n"
"define shortly, enter the drive letter\n"
"of the drive with the account directory.\n"
"\n($$PURPLE$$<ENTER>$$FG$$ for cur drv) Boot Drv:";
ch=Let2Let(GetChar);
if ('A'<=ch<='Z')
c->boot_drv_let=ch;
else
c->boot_drv_let=Drv2Let(Fs->cur_dv);
"\n\n$$BK,1$$$$PURPLE$$Mount drives so they will be present when "
"you boot.$$FG$$$$BK,0$$\n";
Mount2(c->boot_drv_let,doc,FALSE);
return doc;
}
U0 KCfgOptions(CKCfg *c)
{
I64 i;
U8 *st=NULL,*st2,*st3;
Bool state;
do {
Free(st);
for (i=0;i<CFG_OPTIONS_NUM;i++)
if (i==CFG_HOME_DIR)
"$$PURPLE$$%13tz$$FG$$:\"%s\"\n",i,kernel_cfg_options,c->home_dir;
else
"$$PURPLE$$%13tz$$FG$$:%Z\n",i,kernel_cfg_options,c->opts[i],"ST_OFF_ON";
"\nType '$$PURPLE$$Help$$FG$$' for help.\n";
st=GetStr("Option ($$PURPLE$$<ENTER>$$FG$$ when done):","");
i=LstMatch(st,kernel_cfg_options,LMF_IGNORE_CASE);
if (i==CFG_HELP)
"\n"
"$$PURPLE$$MemInit$$FG$$ Initializes memory above 0x100000 "
"to a val at boot.\n"
"$$PURPLE$$HeapInit$$FG$$ Initializes MAlloc() memory to a val.\n"
"$$PURPLE$$VarInit$$FG$$ Initializes glbl var memory to a val.\n"
"$$PURPLE$$HomeDir$$FG$$ Set home dir.\n"
"$$PURPLE$$NoMP$$FG$$ No multicore.\n"
"$$PURPLE$$TextMode$$FG$$ Text Mode (requires hard reboot).\n"
"$$PURPLE$$DontProbe$$FG$$ Just prompt CD/DVD ports, don't probe.\n"
"$$PURPLE$$AutoMountIDE$$FG$$ AutoMount IDE drives to 'C' and 'T'.\n"
"$$PURPLE$$DbgDistro$$FG$$ Include RAM Drv in Kernel.BIN.\n"
"\n";
else
if (0<=i<CFG_OPTIONS_NUM) {
state=c->opts[i]=!c->opts[i];
switch (i) {
case CFG_MEM_INIT:
if (state)
c->mem_init_val=GetI64("Val (0-255):",255,0,255);
break;
case CFG_HEAP_INIT:
if (state)
c->heap_init_val=GetI64("Val (0-255):",255,0,255);
break;
case CFG_VAR_INIT:
if (state)
c->var_init_val=GetI64("Val (0-255):",255,0,255);
break;
case CFG_HOME_DIR:
st2=GetStr("Home Dir(\"%s\"):",c->home_dir);
if (!*st2)
st2=StrNew("::/Home");
else if (st2[1]!=':') {
st3=MStrPrint("::%s",st2);
Free(st2);
st2=st3;
}
Free(c->home_dir);
c->home_dir=st2;
if (StrCmp(c->home_dir,"::/Home"))
c->opts[i]=TRUE;
else
c->opts[i]=FALSE;
break;
case CFG_AUTO_MOUNT_IDE:
if (state) {
"First HD Drive Let:";
c->auto_mount_ide_hd_let=Let2Let(GetChar);
if (!('A'<=c->auto_mount_ide_hd_let<='Z'))
c->auto_mount_ide_hd_let=0;
'\n';
if (c->auto_mount_ide_hd_let)
"First HD Drive:%C\n",c->auto_mount_ide_hd_let;
else
"First HD Drive:%C\n",'C';
"First CD Drive Let:";
c->auto_mount_ide_cd_let=Let2Let(GetChar);
if (!('A'<=c->auto_mount_ide_cd_let<='Z'))
c->auto_mount_ide_cd_let=0;
'\n';
if (c->auto_mount_ide_cd_let)
"First CD Drive:%C\n",c->auto_mount_ide_cd_let;
else
"First CD Drive:%C\n",'T';
} else {
c->auto_mount_ide_hd_let=0;
c->auto_mount_ide_cd_let=0;
}
break;
case CFG_DBG_DISTRO:
Free(c->dbg_distro_file);
c->dbg_distro_file=0;
c->dbg_distro_start=0;
if (state) {
c->dbg_distro_file=GetStr("Dbg Distro File:");
c->dbg_distro_start=GetI64("Dbg Distro Start:");
}
break;
}
}
} while (*st);
Free(st);
}
CKCfg *KCfgNew()
{
CKCfg *c=CAlloc(sizeof(CKCfg));
c->add_dev=KCfgAddDev(c);
c->home_dir=StrNew("::/Home");
c->dsk_cache_size_exp=GetStr(
"Disk Cache Size in Bytes,\n"
"gets rounded-up funny,\n"
"($$PURPLE$$<ENTER>$$FG$$ will use default.):",
"Scale2Mem(0x80000,0x8000000)");
KCfgOptions(c);
return c;
}
U0 KCfgDel(CKCfg *c)
{
DocDel(c->add_dev);
Free(c->dbg_distro_file);
Free(c->home_dir);
Free(c->dsk_cache_size_exp);
Free(c);
}
+323
View File
@@ -0,0 +1,323 @@
U0 LinkedLstDel(U8 **_lst)
{//Free entire linked-list.
U8 **tmpl;
while (_lst) {
tmpl=*_lst;
Free(_lst);
_lst=tmpl;
}
}
U8 *LinkedLstCopy(U8 **_lst,CTask *mem_task=NULL)
{//MAlloc ident copy of entire linked-list.
U8 *res=NULL,**tmpl=&res;
while (_lst) {
tmpl=*tmpl=MAllocIdent(_lst,mem_task);
_lst=*_lst;
}
return res;
}
I64 LinkedLstCnt(U8 **_lst)
{//Count of nodes in linked-list.
I64 res=0;
while (_lst) {
res++;
_lst=*_lst;
}
return res;
}
I64 LinkedLstSize(U8 **_lst)
{//Mem size of all nodes in linked-list.
I64 res=0;
while (_lst) {
res+=MSize2(_lst);
_lst=*_lst;
}
return res;
}
U0 QueDel(CQue *head,Bool querem=FALSE)
{//Free entries in queue, not head.
CQue *tmpq=head->next,*tmpq1;
while (tmpq!=head) {
tmpq1=tmpq->next;
if (querem)
QueRem(tmpq);
Free(tmpq);
tmpq=tmpq1;
}
}
CQue *QueCopy(CQue *head,CTask *mem_task=NULL)
{//MAlloc ident copy of entire queue and head.
CQue *res=MAllocIdent(head,mem_task),*tmpq=head->next,*tmpq1;
QueInit(res);
while (tmpq!=head) {
tmpq1=MAllocIdent(tmpq,mem_task);
QueIns(tmpq1,res->last);
tmpq=tmpq->next;
}
return res;
}
I64 QueCnt(CQue *head)
{//Count of nodes in queue, not head.
CQue *tmpq=head->next;
I64 res=0;
while (tmpq!=head) {
res++;
tmpq=tmpq->next;
}
return res;
}
I64 QueSize(CQue *head)
{//Mem size of all nodes in queue, not head.
CQue *tmpq=head->next;
I64 res=0;
while (tmpq!=head) {
res+=MSize2(tmpq);
tmpq=tmpq->next;
}
return res;
}
CQueVectU8 *QueVectU8New(I64 min_idx=0)
{//Create new queue vecter.
CQueVectU8 *res=MAlloc(sizeof(CQueVectU8));
QueInit(res);
res->total_cnt=res->node_cnt=0;
res->min_idx=min_idx;
return res;
}
U0 QueVectU8Put(CQueVectU8 *v,I64 idx,U8 ch)
{//Put U8 at idx i.
CQueVectU8 *tmpv;
idx-=v->min_idx;
if (idx<0) return;
if (idx<v->total_cnt) {
tmpv=v;
do {
idx-=tmpv->node_cnt;
if (idx<0) {
tmpv->body[idx+tmpv->node_cnt]=ch;
return;
}
tmpv=tmpv->next;
} while (tmpv!=v);
} else
idx-=v->total_cnt;
while (TRUE) {
tmpv=v->last;
if (tmpv->node_cnt>=QUE_VECT_U8_CNT) {
tmpv=MAlloc(sizeof(CQueVectU8));
tmpv->node_cnt=0;
QueIns(tmpv,v->last);
}
if (idx--) {
tmpv->body[tmpv->node_cnt++]=0;
v->total_cnt++;
} else {
tmpv->body[tmpv->node_cnt++]=ch;
v->total_cnt++;
break;
}
}
}
U0 QueVectU8Del(CQueVectU8 *v)
{//Free entire queue vector.
if (v) {
QueDel(v);
Free(v);
}
}
I64 QueVectU8Get(CQueVectU8 *v,I64 idx)
{//Get U8 at idx i.
CQueVectU8 *tmpv;
idx-=v->min_idx;
if (!(0<=idx<v->total_cnt)) return 0;
tmpv=v;
do {
idx-=tmpv->node_cnt;
if (idx<0)
return tmpv->body[idx+tmpv->node_cnt];
tmpv=tmpv->next;
} while (tmpv!=v);
return 0;
}
CFifoU8 *FifoU8New(I64 size,CTask *mem_task=NULL)
{//Create new fifo.
CFifoU8 *f;
if (!mem_task) mem_task=Fs;
f=MAlloc(sizeof(CFifoU8),mem_task);
f->buf=MAlloc(size,mem_task);
f->mask=size-1;
f->in_ptr=0;
f->out_ptr=0;
return f;
}
U0 FifoU8Del(CFifoU8 *f)
{//Free fifo.
Free(f->buf);
Free(f);
}
Bool FifoU8Ins(CFifoU8 *f,U8 b)
{//Insert U8 into fifo.
I64 new_in_ptr;
PUSHFD
CLI
new_in_ptr=(f->in_ptr+1)&f->mask;
if (new_in_ptr==f->out_ptr) {
POPFD
return FALSE;
} else {
f->buf[f->in_ptr]=b;
f->in_ptr=new_in_ptr;
POPFD
return TRUE;
}
}
Bool FifoU8Rem(CFifoU8 *f,U8 *_b)
{//Remove U8 from fifo.
PUSHFD
CLI
if (f->in_ptr==f->out_ptr) {
POPFD
return FALSE;
} else {
*_b=f->buf[f->out_ptr];
f->out_ptr=(f->out_ptr+1)&f->mask;
POPFD
return TRUE;
}
}
Bool FifoU8Peek(CFifoU8 *f,U8 *_b)
{//Peek at front of fifo and don't remove.
PUSHFD
CLI
if (f->in_ptr==f->out_ptr) {
POPFD
return FALSE;
} else {
*_b=f->buf[f->out_ptr];
POPFD
return TRUE;
}
}
U0 FifoU8Flush(CFifoU8 *f)
{//Flush fifo getting rid of all U8's.
PUSHFD
CLI
f->out_ptr=f->in_ptr;
POPFD
}
I64 FifoU8Cnt(CFifoU8 *f)
{//Count of U8's in fifo.
I64 res;
PUSHFD
CLI
if (f->out_ptr>f->in_ptr)
res=f->mask+1-(f->out_ptr-f->in_ptr);
else
res=f->in_ptr-f->out_ptr;
POPFD
return res;
}
CFifoI64 *FifoI64New(I64 size,CTask *mem_task=NULL)
{//Create new fifo.
CFifoI64 *f;
if (!mem_task) mem_task=Fs;
f=MAlloc(sizeof(CFifoI64),mem_task);
f->buf=MAlloc(size*sizeof(I64),mem_task);
f->mask=size-1;
f->in_ptr=0;
f->out_ptr=0;
return f;
}
U0 FifoI64Del(CFifoI64 *f)
{//Free fifo.
Free(f->buf);
Free(f);
}
Bool FifoI64Ins(CFifoI64 *f,I64 q)
{//Insert I64 into fifo.
I64 new_in_ptr;
PUSHFD
CLI
new_in_ptr=(f->in_ptr+1)&f->mask;
if (new_in_ptr==f->out_ptr) {
POPFD
return FALSE;
} else {
f->buf[f->in_ptr]=q;
f->in_ptr=new_in_ptr;
POPFD
return TRUE;
}
}
Bool FifoI64Rem(CFifoI64 *f,I64 *_q)
{//Remove I64 from fifo.
PUSHFD
CLI
if (f->in_ptr==f->out_ptr) {
POPFD
return FALSE;
} else {
*_q=f->buf[f->out_ptr];
f->out_ptr=(f->out_ptr+1)&f->mask;
POPFD
return TRUE;
}
}
Bool FifoI64Peek(CFifoI64 *f,I64 *_q)
{//Peek at front of fifo and don't remove.
PUSHFD
CLI
if (f->in_ptr==f->out_ptr) {
POPFD
return FALSE;
} else {
*_q=f->buf[f->out_ptr];
POPFD
return TRUE;
}
}
U0 FifoI64Flush(CFifoI64 *f)
{//Flush fifo getting rid of all I64's.
PUSHFD
CLI
f->out_ptr=f->in_ptr;
POPFD
}
I64 FifoI64Cnt(CFifoI64 *f)
{//Count of I64's in fifo.
I64 res;
PUSHFD
CLI
if (f->out_ptr>f->in_ptr)
res=f->mask+1-(f->out_ptr-f->in_ptr);
else
res=f->in_ptr-f->out_ptr;
POPFD
return res;
}
+196
View File
@@ -0,0 +1,196 @@
//See $LK,"::/Doc/TimeDate.DD"$
U16 mon_start_days1[12]={
0,31,59,90,120,151,181,212,243,273,304,334};
U16 mon_start_days2[12]={
0,31,60,91,121,152,182,213,244,274,305,335};
I64 YearStartDate(I64 year)
{//32-bit day since AD 0, given year number.
I64 y1=year-1,yd4000=y1/4000,yd400=y1/400,yd100=y1/100,yd4=y1/4;
return year*365+yd4-yd100+yd400-yd4000;
}
CDate Struct2Date(CDateStruct *_ds)
{//Cvt CDateStruct to CDate.
CDate cdt;
I64 i1,i2;
i1=YearStartDate(_ds->year);
i2=YearStartDate(_ds->year+1);
if (i2-i1==365)
i1+=mon_start_days1[_ds->mon-1];
else
i1+=mon_start_days2[_ds->mon-1];
cdt.date=i1+_ds->day_of_mon-1;
cdt.time=(_ds->sec10000+100*(_ds->sec100+100*(_ds->sec
+60*(_ds->min+60*_ds->hour))))<<21/(15*15*3*625);
return cdt;
}
I64 DayOfWeek(I64 i)
{//Day of week, given 32-bit day since AD 0.
i+=CDATE_BASE_DAY_OF_WEEK;
if (i>=0)
return i % 7;
else
return 6-(6-i)%7;
}
U0 Date2Struct(CDateStruct *_ds,CDate cdt)
{//Cvt CDate to CDateStruct.
I64 i,k,date=cdt.date;
_ds->day_of_week=DayOfWeek(date);
_ds->year=(date+1)*100000/CDATE_YEAR_DAYS_INT;
i=YearStartDate(_ds->year);
while (i>date) {
_ds->year--;
i=YearStartDate(_ds->year);
}
date-=i;
if (YearStartDate(_ds->year+1)-i==365) {
k=0;
while (date>=mon_start_days1[k+1] && k<11)
k++;
date-=mon_start_days1[k];
} else {
k=0;
while (date>=mon_start_days2[k+1] && k<11)
k++;
date-=mon_start_days2[k];
}
_ds->mon=k+1;
_ds->day_of_mon=date+1;
k=(625*15*15*3*cdt.time)>>21+1;
_ds->sec10000=ModU64(&k,100);
_ds->sec100=ModU64(&k,100);
_ds->sec=ModU64(&k,60);
_ds->min=ModU64(&k,60);
_ds->hour =k;
}
I64 FirstDayOfMon(I64 i)
{//First day of month, given 32-bit day since AD 0.
CDateStruct ds;
CDate cdt=0;
cdt.date=i;
Date2Struct(&ds,cdt);
ds.day_of_mon=1;
cdt=Struct2Date(&ds);
return cdt.date;
}
I64 LastDayOfMon(I64 i)
{//Last day of month, given 32-bit day since AD 0.
CDateStruct ds;
CDate cdt=0;
cdt.date=i;
Date2Struct(&ds,cdt);
ds.mon++;
if (ds.mon==13) {
ds.mon=0;
ds.year++;
}
ds.day_of_mon=1;
cdt=Struct2Date(&ds);
return cdt.date-1;
}
I64 FirstDayOfYear(I64 i)
{//First day of year, given 32-bit day since AD 0.
CDateStruct ds;
CDate cdt=0;
cdt.date=i;
Date2Struct(&ds,cdt);
ds.day_of_mon=1;
ds.mon=1;
cdt=Struct2Date(&ds);
return cdt.date;
}
I64 LastDayOfYear(I64 i)
{//Last day of year, given 32-bit day since AD 0.
CDateStruct ds;
CDate cdt=0;
cdt.date=i;
Date2Struct(&ds,cdt);
ds.day_of_mon=1;
ds.mon=1;
ds.year++;
cdt=Struct2Date(&ds);
return cdt.date-1;
}
I64 Bcd2Bin(U64 b)
{
I64 i,res=0;
for (i=0;i<16;i++) {
res=res*10+b>>60;
b<<=4;
}
return res;
}
U0 NowDateTimeStruct(CDateStruct *_ds)
{
I64 i;
U8 *b=_ds;
Bool is_bcd;
MemSet(_ds,0,sizeof(CDateStruct));
PUSHFD
CLI
while (LBts(&sys_semas[SEMA_SYS_DATE],0))
PAUSE
OutU8(0x70,0x0A);
do {
while (InU8(0x71) & 0x80)
PAUSE
OutU8(0x70,0);
b[2]=InU8(0x71);
OutU8(0x70,2);
b[3]=InU8(0x71);
OutU8(0x70,4);
b[4]=InU8(0x71);
OutU8(0x70,6);
b[5]=InU8(0x71);
OutU8(0x70,7);
b[6]=InU8(0x71);
OutU8(0x70,8);
b[7]=InU8(0x71);
OutU8(0x70,9);
b[8]=InU8(0x71);
OutU8(0x70,0x0A);
} while (InU8(0x71) & 0x80);
OutU8(0x70,0x0B);
if (InU8(0x71) & 4)
is_bcd=FALSE;
else
is_bcd=TRUE;
LBtr(&sys_semas[SEMA_SYS_DATE],0);
POPFD
if (is_bcd)
for (i=2;i<9;i++)
b[i]=Bcd2Bin(b[i]);
if (_ds->year>255) _ds->year=255;
_ds->year+=2000;
if (_ds->mon>12) _ds->mon=12;
if (_ds->day_of_mon>31) _ds->day_of_mon=31;
if (_ds->day_of_week>6) _ds->day_of_week=6;
if (_ds->hour>23) _ds->hour=23;
if (_ds->min>59) _ds->min=59;
if (_ds->sec>59) _ds->sec=59;
}
CDate Now()
{//Current datetime.
CDateStruct ds;
NowDateTimeStruct(&ds);
return Struct2Date(&ds)-local_time_offset;
}
+652
View File
@@ -0,0 +1,652 @@
Bool ChkPtr(U8 *ptr)
{//Check if addr is valid ptr.
if (mem_heap_base<=ptr<=mem_mapped_space) {
if (*MemPageTable(ptr)&1)
return TRUE;
else
return FALSE;
} else if (ptr<mem_boot_base)
return FALSE;
else if (ptr<VGAM_GRAPHICS)
return TRUE;
else
return FALSE;
}
Bool ChkCodePtr(U8 *ptr)
{//Check if addr is valid code addr.
if (mem_heap_base<=ptr<=mem_heap_limit) {
if (*MemPageTable(ptr)&1)
return TRUE;
else
return FALSE;
} else if (ptr<mem_boot_base)
return FALSE;
else if (ptr<VGAM_GRAPHICS)
return TRUE;
else
return FALSE;
}
Bool ChkOnStk(U8 *ptr,CTask *task=NULL)
{//Check if addr is valid stk addr.
Bool res=FALSE;
PUSHFD
CLI
if (task) {
if (&task->stk->stk_base<=ptr<=
(&task->stk->stk_base)(U8 *)+task->stk->stk_size)
res=TRUE;
} else if (mem_heap_base<=ptr<=mem_heap_limit)
res=TRUE;
POPFD
return res;
}
I64 UnusedStk(CTask *task=NULL)
{//Count of usused bytes in task's stk.
I64 res;
if (!task) task=Fs;
PUSHFD
CLI
if (task==Fs)
res=GetRSP()(U8 *)-(&task->stk->stk_base)(U8 *);
else
res=task->rsp(U8 *)-(&task->stk->stk_base)(U8 *);
POPFD
return res;
}
U8 *Caller(I64 num=1)
{//Returns the addr of the fun which called this one,
//or the caller of the caller, etc.
U8 **rbp=GetRBP,**ptr;
while (num--) {
if (rbp>=*rbp)
return NULL;
rbp=*rbp;
if (!ChkOnStk(rbp,Fs))
return NULL;
}
ptr=rbp+1;
return *ptr;
}
U8 *TaskCaller(CTask *task=NULL,I64 num=0,Bool saved_context=FALSE)
{//Fetches addr of Nth caller on task's stk.
U8 **ptr,**rbp,**rsp;
if (!task) task=Fs;
if (!saved_context && task==Fs)
return Caller(num+1);
if (!TaskValidate(task))
return NULL;
rbp=task->rbp;
rsp=task->rsp;
if (num) {
while (ChkOnStk(rbp,task)) {
ptr=rbp+1;
if (! --num)
return *ptr;
if (rbp>=*rbp)
break;
rbp=*rbp;
}
return NULL;
} else {
if (task->rip==_RET)
return *rsp;
else
return task->rip;
}
}
#define STK_REP_LEN 32
U0 StkRep(CTask *task=NULL)
{//Reports whats on the stk.
I64 i,j,addr,
**rbp,**rsp,*my_rsp[STK_REP_LEN];
CHashTable *old_hash=Fs->hash_table;
if (!task) task=Fs;
if (!TaskValidate(task))
return;
PUSHFD
CLI
if (task==Fs) {
rbp=GetRBP;
rsp=rbp+3;
rbp=*rbp;
} else {
rsp=task->rsp;
rbp=task->rbp;
}
if (task->rip==_RET)
addr=*rsp;
else
addr=task->rip;
MemCpy(my_rsp,rsp,STK_REP_LEN*sizeof(U8 *));
POPFD
Fs->hash_table=task->hash_table;
for (i=0;i<STK_REP_LEN;i++) {
"%08X [RSP+%04X]: %016X ",rsp+i,
i*sizeof(U8 *),my_rsp[i];
while (TRUE) {
if (!(&task->stk->stk_base<=rbp<
(&task->stk->stk_base)(U8 *)+task->stk->stk_size))
break;
j=rbp-rsp;
if (j>=i)
break;
addr=my_rsp[j+1];
if (rbp>=my_rsp[j])
break;
rbp=my_rsp[j];
}
if (my_rsp[i]==addr)
"$$RED$$";
"%P$$FG$$\n",my_rsp[i];
}
'\n';
Fs->hash_table=old_hash;
}
U0 CallerRep(U8 **rbp=NULL,CTask *task=NULL)
{//Prints a report of calling routines.
I64 **ptr;
if (!task) task=Fs;
if (!rbp) {
if (task==Fs)
rbp=GetRBP;
else
rbp=task->rbp;
}
"CallerRep:\n";
while (ChkOnStk(rbp,task)) {
ptr=rbp+1;
"%08X:%08tX:%P\n",ptr,*ptr,*ptr;
if (rbp>=*rbp)
break;
rbp=*rbp;
}
}
U0 D(U8 *addr,I64 cnt=0x80,Bool show_offset=TRUE)
{//Dump mem, showing offsets.
//See $LK,"DocD",A="MN:DocD"$() for a live dump.
I64 i,j,ch;
U8 *ptr=addr;
while (cnt) {
if (show_offset)
"%08X ",ptr-addr;
else
"%010X ",ptr;
if (cnt>16)
j=16;
else
j=cnt;
for (i=0;i<j;i++)
"%02X ",ptr[i];
for (;i<16;i++)
" ";
for (i=0;i<j;i++) {
ch=ptr[i];
if (ch<CH_SHIFT_SPACE || ch==CH_BACKSPACE)
ch='.';
'' ch;
if (ch=='$$')
'' ch;
}
'\n';
cnt-=j;
ptr+=j;
}
}
U0 Dm(U8 *addr,I64 cnt=0x80)
{//Show mem addr, not offsets.
D(addr,cnt,FALSE);
}
U0 Da(U8 **addr,I64 cnt=0x10)
{//Dump mem, showing symbolic addresses.
while (cnt-->0) {
"%08X:%08X,%P\n",addr,*addr,*addr;
addr++;
}
}
U0 RawPrint(I64 mS=100,U8 *fmt,...)
{//Print using $LK,"Raw",A="MN:Raw"$ scrn output for a length of time.
//$BK,1$Your heap must be good.$BK,0$
U8 *buf=StrPrintJoin(NULL,fmt,argc,argv);
Bool old_raw,old_input_filter;
PUSHFD
CLI
old_raw=Raw(ON);
old_input_filter=LBtr(&Fs->task_flags,TASKf_INPUT_FILTER_TASK);
"%s",buf;
Busy(mS<<10);
POPFD
LBEqu(&Fs->task_flags,TASKf_INPUT_FILTER_TASK,old_input_filter);
Raw(old_raw);
Free(buf);
}
U0 RawD(I64 mS=100,U8 *addr,I64 cnt=0x80)
{//Dumps a block of mem using $LK,"Raw",A="MN:Raw"$
//scrn output for a fixed length
//of time.
Bool old_raw,old_input_filter;
PUSHFD
CLI
old_raw=Raw(ON);
old_input_filter=LBtr(&Fs->task_flags,TASKf_INPUT_FILTER_TASK);
D(addr,cnt);
Busy(mS<<10);
POPFD
LBEqu(&Fs->task_flags,TASKf_INPUT_FILTER_TASK,old_input_filter);
Raw(old_raw);
}
U0 RawDm(I64 mS=100,U8 *addr,I64 cnt=0x80)
{//Dumps a block of mem using $LK,"Raw",A="MN:Raw"$
//scrn output for a fixed length
//of time.
Bool old_raw,old_input_filter;
PUSHFD
CLI
old_raw=Raw(ON);
old_input_filter=LBtr(&Fs->task_flags,TASKf_INPUT_FILTER_TASK);
Dm(addr,cnt);
Busy(mS<<10);
POPFD
LBEqu(&Fs->task_flags,TASKf_INPUT_FILTER_TASK,old_input_filter);
Raw(old_raw);
}
I64 *TaskRegAddr(CTask *task,I64 reg_num)
{
switch (reg_num) {
case REG_RAX: return &task->rax;
case REG_RCX: return &task->rcx;
case REG_RDX: return &task->rdx;
case REG_RBX: return &task->rbx;
case REG_RSP: return &task->rsp;
case REG_RBP: return &task->rbp;
case REG_RSI: return &task->rsi;
case REG_RDI: return &task->rdi;
case 8 : return &task->r8;
case 9 : return &task->r9;
case 10: return &task->r10;
case 11: return &task->r11;
case 12: return &task->r12;
case 13: return &task->r13;
case 14: return &task->r14;
case 15: return &task->r15;
}
return NULL;
}
#define RAWDR_COL 40
U0 RawDr(CTask *task=NULL)
{
I64 i,j,old_col=text.raw_col;
Bool old_raw=Raw(ON);
U8 buf[200];
if (!task) task=Fs;
for (i=0;i<16;i++) {
text.raw_col=i*text.cols+RAWDR_COL;
"º%3Z:%016X\n",i,"ST_U64_REGS",*TaskRegAddr(task,i);
}
text.raw_col=i++*text.cols+RAWDR_COL;
"ºRIP:%016X\n",task->rip;
text.raw_col=i++*text.cols+RAWDR_COL;
"º%-*tp\n",text.cols-(RAWDR_COL+1)-1,Fs->rip;
text.raw_col=i++*text.cols+RAWDR_COL;
'º';
if (Bt(&sys_run_level,RLf_COMPILER)) {
j=Fs->rip;
Ui(buf,&j,,,TRUE);
"%s",buf;
} else
'\n';
text.raw_col=i*text.cols+RAWDR_COL;
'È';
for (j=0;j<text.cols-RAWDR_COL-1;j++)
'Í';
text.raw_col=old_col;
Raw(old_raw);
}
U0 Dr(CTask *task=NULL)
{//Dump regs
I64 i;
if (!task) task=Fs;
for (i=0;i<16;i++)
"%3Z:%016X\n",i,"ST_U64_REGS",*TaskRegAddr(task,i);
"RIP:%016X\n",task->rip;
}
U8 *SysGetStr2(I64)
{
U8 buf[512];
GetS(buf,512,FALSE);
return StrNew(buf);
}
CBpt *BptFind(U8 *needle_addr,CTask *haystack_task=NULL,Bool rem=FALSE)
{
CBpt *res=NULL,*tmpb,*tmpb1,*tmpb2;
if (!haystack_task) haystack_task=Fs;
PUSHFD
CLI
tmpb1=&haystack_task->bpt_lst;
tmpb=haystack_task->bpt_lst;
while (tmpb) {
tmpb2=tmpb->next;
if (tmpb->addr==needle_addr) {
res=tmpb;
if (rem)
tmpb1->next=tmpb2;
else
tmpb1=&tmpb->next;
} else
tmpb1=&tmpb->next;
tmpb=tmpb2;
}
POPFD
return res;
}
Bool BptS(U8 *addr,CTask *task=NULL,Bool live=TRUE)
{//Set breakpoint.
CBpt *tmpb;
Bool res=TRUE;
if (!task) task=Fs;
PUSHFD
CLI
if (!(tmpb=BptFind(addr,task,FALSE))) {
tmpb=CAlloc(sizeof(CBpt),task);
tmpb->addr=addr;
tmpb->val=*addr;
res=FALSE;
tmpb->next=task->bpt_lst;
task->bpt_lst=tmpb;
if (task==Fs && live)
*addr=OC_BPT;
}
POPFD
return res;
}
Bool BptR(U8 *addr,CTask *task=NULL,Bool live=TRUE,Bool rem=TRUE)
{//Rem breakpoint.
CBpt *tmpb;
Bool res=FALSE;
if (!task) task=Fs;
PUSHFD
CLI
if (tmpb=BptFind(addr,task,rem)) {
if (task==Fs && live)
*tmpb->addr=tmpb->val;
res=TRUE;
if (rem)
Free(tmpb);
}
POPFD
return res;
}
Bool B(U8 *addr,CTask *task=NULL,Bool live=TRUE)
{//Toggle breakpoint.
//Return: TRUE if removed.
Bool res=FALSE;
PUSHFD
CLI
if (BptFind(addr,task,FALSE)) {
BptR(addr,task,live,TRUE);
res=TRUE;
} else
BptS(addr,task,live);
POPFD
return res;
}
I64 B2(CTask *task=NULL,Bool live=TRUE)
{//Rem all breakpoints.
//Return: cnt of removed.
I64 res=0;
CBpt *tmpb,*tmpb1;
if (!task) task=Fs;
PUSHFD
CLI
tmpb=task->bpt_lst;
task->bpt_lst=NULL;
while (tmpb) {
tmpb1=tmpb->next;
if (task==Fs && live)
*tmpb->addr=tmpb->val;
Free(tmpb);
tmpb=tmpb1;
res++;
}
POPFD
return res;
}
U0 G(U8 *ip=INVALID_PTR,CTask *task=NULL)
{//Go
if (!task) task=Fs;
if (ip!=INVALID_PTR) task->rip=ip;
if (BptFind(task->rip,task))
"\nDo one of the following, first:\n"
">S;\t\t\t//Single step\n"
">B2;\t\t\t//Clear all break points\n"
">G2;\t\t\t//Clear all break points and Go\n\n"
"After resuming, <CTRL-ALT-n> next focus task\n"
"After resuming, <CTRL-ALT-v> flushes scrn VGA cache\n";
else {
LBtr(&task->task_flags,TASKf_DISABLE_BPTS);
LBtr(&task->rflags,RFLAGf_TRAP);//No single step
Suspend(task,FALSE);
if (task==Fs) {
if (IsDbgMode && task->next_cc!=&task->next_cc) {
"Exit Dbg\n";
Btr(&task->last_cc->flags,CCf_PMT);
}
} else
Exit;
}
}
U0 G2(U8 *ip=INVALID_PTR,CTask *task=NULL)
{//Rem all breakpoints and Go.
if (!task) task=Fs;
B2(task);
if (ext[EXT_WIN_FOCUS])
CallExtNum(EXT_WIN_FOCUS,dbg.focus_task);
VGAFlush;
G(ip,task);
}
public U0 S(U8 *ip=INVALID_PTR,CTask *task=NULL) //Single-step.
{//Single step.
if (!task) task=Fs;
PUSHFD
CLI
if (ip!=INVALID_PTR) task->rip=ip;
LBts(&task->task_flags,TASKf_DISABLE_BPTS);
LBts(&task->rflags,RFLAGf_TRAP);
Suspend(task,FALSE);
if (task==Fs) {
if (IsDbgMode) {
if (task->next_cc!=&task->next_cc)
Btr(&task->last_cc->flags,CCf_PMT);
}
} else
Exit;
POPFD
}
U0 DbgHelp()
{
"\n"
"The cmd line is basically the same as normal. Here are some common\n"
"debugging commands.\n\n"
">EdLite(\"FileName\");\t\t//Edit file.\n"
">D(0x100000);\t\t\t//Dump page tables.\n"
">Dm(0x100000);\t\t\t//Dump page tables.\n"
">Dm(Fs,sizeof(CTask));\t\t//Dump current task record.\n"
">ClassRep(Fs,\"CTask\",1);\t//Dump current task record.\n"
">ClassRep(Fs,,1);\t\t//(It knows lastclass.)\n"
">CallerRep;\t\t\t//Stack trace report.\n"
">Da(_RSP);\t\t\t//Dump stk.\n"
">Dr;\t\t\t\t//Dump Regs.\n"
">1+2*3+&Print;\t\t\t//Show calculation res.\n"
">*(0x70000)(I64 *)=0x123456789;\t//Assign value to 0x70000-0x70007.\n"
">_RAX=0x1234;\t\t\t//Set RAX to 0x1234.\n"
">_RIP=&Break;\t\t//Set RIP.\n"
">I64 i;\t\t\t\t//Declare variable.\n"
">i=_RCX+_RDX;\t\t\t//Assign to variable.\n"
">U(&Print+0x8);\t\t\t//Unassemble Print.\n"
">Uf(\"Print\");\t\t\t//Unassembler function \"Print\".\n"
">Man(\"Print\");\t\t\t//Edit Src for \"Print\".\n"
">E(_RIP);\t\t\t//Edit Src Code.\n"
">Fix;\t\t\t\t//Edit Last Err Src Code.\n"
">B(&Main+0x20);\t\t\t//Toggle break point.\n"
">B2;\t\t\t\t//Clear all break points.\n"
">S;\t\t\t\t//Single step.\n"
">G;\t\t\t\t//Resume execution.\n"
">G2;\t\t\t\t//B2;VGAFlush;WinFocus;G;\n"
">Exit;\t\t\t\t//Exit (kill) task.\n\n"
"After resuming, <CTRL-ALT-n> next focus task.\n"
"After resuming, <CTRL-ALT-v> flushes scrn VGA cache.\n\n";
}
U0 Dbg2()
{
Bool old_win_inhibit,old_waiting_msg,old_single;
I64 i,old_getstr2;
U8 buf[200];
if (dbg.panic) {
if (IsRaw) {
i=Fs->rip;
Ui(buf,&i);
"%s",buf;
} else
U(Fs->rip,1);
} else
dbg.panic=TRUE;
old_waiting_msg=LBtr(&Fs->task_flags,TASKf_AWAITING_MSG);
old_win_inhibit=Fs->win_inhibit;
Fs->win_inhibit=WIG_USER_TASK_DFT;
sys_focus_task=Fs;
kbd.scan_code=0;
old_getstr2=fp_getstr2;
fp_getstr2=&SysGetStr2;
old_single=SingleUser(OFF);
while (!ms_hard.install_attempts)
Yield;
SingleUser(old_single);
UserTaskCont;
fp_getstr2=old_getstr2;
Fs->win_inhibit=old_win_inhibit;
LBEqu(&Fs->task_flags,TASKf_AWAITING_MSG,old_waiting_msg);
}
U0 Fault3(I64 fault_num,I64 fault_err_code)
{
no_warn fault_err_code;
PUSHFD
CLI
if (Gs->num && dbg.mp_crash) {
mp_cnt=1;
dbg.mp_crash->cpu_num=Gs->num;
dbg.mp_crash->task=Fs;
dbg.mp_crash->rip=Fs->rip;
dbg.mp_crash->msg=dbg.msg;
dbg.mp_crash->msg_num=dbg.msg_num;
MPInt(I_MP_CRASH,0);
SysHlt;
}
"\n\tTempleOS Debugger\n\n"
">Help;\t//For help.\n\n";
Beep(62,TRUE);
if (fault_num==I_DBG) {
if (dbg.msg) {
"\n!!! %s",dbg.msg;
if (dbg.msg_num)
"%016X",dbg.msg_num;
" !!!\n\n";
}
}
if (dbg.panic)
CallerRep;
Dbg2;
POPFD
}
U0 Fault2(I64 fault_num,I64 fault_err_code)
{//Called from $LK,"Fault2",A="FF:::/Kernel/KInts.HC,Fault2"$.
//$BK,1$Be careful not to swap-out and ruin the saved context$BK,0$
Bool was_raw,was_single_user,was_silent,was_in_dbg;
I64 i,old_raw_flags=text.raw_flags;
was_single_user=SingleUser(ON);
if (!IsDbgMode)
dbg.focus_task=sys_focus_task;
sys_focus_task=NULL;
if (fault_num==I_BPT)
Fs->rip--;
if (Fs->dbg_task)
CallExtNum(EXT_DBG_RESUME,fault_num,fault_err_code);
else {
was_raw=Raw(ON);
was_silent=Silent(OFF);
text.raw_flags|=RWF_SHOW_DOLLAR|RWF_SCROLL;
"Task \"";
"%s",Fs->task_title;
"\"\n";
"Fault:0x%02X %Z\t\tErr Code:%08X\n",
fault_num,fault_num,"ST_INT_NAMES",fault_err_code;
was_in_dbg=DbgMode(ON);
"RIP:%08X",Fs->rip; //Sometimes crashes on %p, so do this first
":%p RSP:%08X\n",Fs->rip,Fs->rsp;
if (fault_num==I_PAGE_FAULT) {
MOV_RAX_CR2
i=GetRAX;
"Fault Addr:%08X:%p\n",i,i;
}
Fault3(fault_num,fault_err_code);
DbgMode(was_in_dbg);
Silent(was_silent);
Raw(was_raw);
text.raw_flags=old_raw_flags;
}
SingleUser(was_single_user);
if (LBtr(&Fs->task_flags,TASKf_KILL_AFTER_DBG))
Exit;
}
U0 Panic(U8 *msg=NULL,I64 msg_num=0,Bool panic=TRUE)
{//Enter the debugger with panic?
PUSHFD
CLI
dbg.msg=msg;
dbg.msg_num=msg_num;
dbg.panic=panic;
INT I_DBG
POPFD
}
U0 Dbg(U8 *msg=NULL,I64 msg_num=0)
{//Enter debugger, no panic.
Panic(msg,msg_num,FALSE);
}
+218
View File
@@ -0,0 +1,218 @@
CHashDefineStr *DefineLoad(U8 *dname,U8 *st)
{//Create DEFINE hash entry with string.
CHashDefineStr *tmph=CAlloc(sizeof(CHashDefineStr));
tmph->type=HTT_DEFINE_STR;
tmph->str=StrNew(dname);
tmph->data=StrNew(st);
tmph->cnt=-1;
tmph->src_link=MStrPrint("AD:0x%X",Caller);
HashAdd(tmph,Fs->hash_table);
return tmph;
}
CHashDefineStr *DefineLstLoad(U8 *dname,U8 *lst)
{//Create DEFINE list. Not efficient, but handy.
I64 cnt=0;
U8 *ptr,**idx;
CHashDefineStr *tmph=CAlloc(sizeof(CHashDefineStr));
tmph->type=HTT_DEFINE_STR;
tmph->str=StrNew(dname);
tmph->src_link=MStrPrint("AD:0x%X",Caller);
ptr=lst;
while (*ptr) {
if (*ptr!='@')
cnt++;
while (*ptr++);
}
tmph->data=MAlloc(ptr+1-lst);
MemCpy(tmph->data,lst,ptr+1-lst);
tmph->cnt=cnt;
idx=tmph->sub_idx=MAlloc(cnt*sizeof(U8 *));
ptr=lst;
while (*ptr) {
if (*ptr!='@')
*idx++=ptr;
while (*ptr++);
}
HashAdd(tmph,Fs->hash_table);
return tmph;
}
U0 UndefinedDefine(U8 *dname)
{
ST_ERR_ST "Undefined Define: '%s'.\n",dname;
throw('UndefDef');
}
U8 *Define(U8 *dname)
{//Look for DEFINE named in hash table, return ptr string.
CHashDefineStr *tmph;
if (tmph=HashFind(dname,Fs->hash_table,HTT_DEFINE_STR))
return tmph->data;
else if (dname)
UndefinedDefine(dname);
else
return NULL;
}
U8 *DefineSub(I64 sub,U8 *dname)
{//Return DEFINE list entry indexed by number.
CHashDefineStr *tmph;
if (tmph=HashFind(dname,Fs->hash_table,HTT_DEFINE_STR)) {
if (0<=sub<tmph->cnt)
return tmph->sub_idx[sub];
else
return NULL;
} else if (dname)
UndefinedDefine(dname);
else
return NULL;
}
I64 DefineCnt(U8 *dname)
{//Return cnt of entries in define list.
CHashDefineStr *tmph;
if (tmph=HashFind(dname,Fs->hash_table,HTT_DEFINE_STR))
return tmph->cnt;
else if (dname)
UndefinedDefine(dname);
else
return -1;
}
I64 DefineMatch(U8 *needle,U8 *haystack_lst_dname,I64 flags=0)
{//Find match for string in define list.
return LstMatch(needle,Define(haystack_lst_dname),flags);
}
U0 DefinePrint(U8 *dname,U8 *src,...)
{//Create DEFINE entry with $LK,"Print",A="FI:::/Doc/Print.DD"$()ed string.
U8 *buf=StrPrintJoin(NULL,src,argc,argv);
DefineLoad(dname,buf);
Free(buf);
}
U0 SysDefinesLoad()
{
DefineLstLoad("ST_OFF_ON","Off\0On\0");
DefineLstLoad("ST_HTT_TYPES","ExportSysSym\0ImportSysSym\0DefineStr\0GlbVar\0"
"Class\0IntType\0Funct\0Word\0DictWord\0KeyWord\0AsmKeyWord\0OpCode\0"
"Reg\0File\0Module\0HelpFile\0Frame Ptr\0 \0 \0 \0 \0 \0 \0Private\0"
"Public\0Export\0Import\0Imm\0Goto\0Res\0Unres\0Local\0");
DefineLstLoad("ST_DAYS_OF_WEEK","Sunday\0Monday\0Tuesday\0Wednesday\0"
"Thursday\0Friday\0Saturday\0");
DefineLstLoad("ST_MONTHS","January\0February\0March\0April\0May\0"
"June\0July\0August\0September\0October\0November\0December\0");
DefineLstLoad("ST_FILE_ATTRS","R\0H\0S\0V\0D\0A\0 \0 \0X\0T\0Z\0C\0F\0");
DefineLstLoad("ST_FILE_UTIL_FLAGS","r\0d\0i\0a\0c\0R\0p\0m\0x\0s\0"
"D\0F\0T\0$$\0S\0A\0J\0G\0Z\0O\0P\0f\0l\0lb\0la\0");
DefineLstLoad("ST_BLKDEV_TYPES",
"NULL\0RAM\0ATA\0FILE_READ\0FILE_WRITE\0ATAPI\0");
DefineLstLoad("ST_DRV_TYPES",
"NULL\0REDSEA\0FAT32\0ISO9660\0ISO13490\0ISO13346\0NTFS\0UNKNOWN\0");
DefineLstLoad("ST_COLORS","BLACK\0BLUE\0GREEN\0CYAN\0"
"RED\0PURPLE\0BROWN\0LTGRAY\0DKGRAY\0LTBLUE\0LTGREEN\0"
"LTCYAN\0LTRED\0LTPURPLE\0YELLOW\0WHITE\0");
DefineLstLoad("ST_INT_NAMES","Divide Error\0SingleStep\0NMI\0Breakpoint\0"
"Overflow\0BOUND Range Exceeded\0Invalid Opcode\0No Math Coprocessor\0"
"Double Fault\0Coprocessor Segment Fault\0Invalid TASK\0"
"Segment Not Present\0Stk Segment Fault\0General Protection\0"
"Page Fault\0 \0Math Fault\0Alignment Check\0Machine Check\0"
"SIMD Exception\0 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0"
" \0 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0MP Crash\0Wake\0Dbg\0");
}
U8 *Color2Str(U8 *buf,CColorROPU32 c)
{//$LK,"CColorROPU32",A="MN:CColorROPU32"$ with flags to $LK,"DCLighting",A="MN:DCLighting"$ str.
*buf=0;
if (c.c0.rop&ROPBF_TWO_SIDED)
CatPrint(buf,"TWO|");
if (c.c0.rop&ROPBF_HALF_RANGE_COLOR)
CatPrint(buf,"HALF|");
if (0<=c.c0.color<16)
CatPrint(buf,DefineSub(c.c0.color,"ST_COLORS"));
else if (c.c0.color==TRANSPARENT)
CatPrint(buf,"TRANSPARENT");
else
CatPrint(buf,"INVALID");
if (c&ROPF_DITHER) {
CatPrint(buf,"/");
if (c.c1.rop&ROPBF_TWO_SIDED)
CatPrint(buf,"TWO|");
if (c.c1.rop&ROPBF_HALF_RANGE_COLOR)
CatPrint(buf,"HALF|");
if (0<=c.c1.color<16)
CatPrint(buf,DefineSub(c.c1.color,"ST_COLORS"));
else if (c.c1.color==TRANSPARENT)
CatPrint(buf,"TRANSPARENT");
else
CatPrint(buf,"INVALID");
}
return buf;
}
U8 *str2color_lst="/,)}>";
CColorROPU16 Str2ColorU16(U8 *st)
{//$LK,"DCLighting",A="MN:DCLighting"$ color str with flags to $LK,"CColorROPU16",A="MN:CColorROPU16"$.
CColorROPU16 res=COLOR_INVALID;
I64 i;
U8 *ptr,*ptr2,*st2;
if (!st) return COLOR_INVALID;
while (TRUE) {
if (!*st||StrOcc(str2color_lst,*st))
return res;
if (Bt(char_bmp_alpha,*st)) {
ptr=st;
while (Bt(char_bmp_alpha_numeric,*ptr))
ptr++;
st2=ptr2=MAlloc(ptr-st+1);
while (st<ptr)
*ptr2++=*st++;
*ptr2++=0;
if (!StrICmp(st2,"TWO"))
res.rop|=ROPBF_TWO_SIDED;
else if (!StrICmp(st2,"HALF"))
res.rop|=ROPBF_HALF_RANGE_COLOR;
else if ((i=DefineMatch(st2,"ST_COLORS",LMF_IGNORE_CASE))>=0)
res.color=i;
else if (!StrICmp(st2,"TRANSPARENT"))
res.color=TRANSPARENT;
else {
Free(st2);
return COLOR_INVALID;
}
Free(st2);
} else if (*st=='+'||*st=='|'||Bt(char_bmp_white_space,*st))
st++;
else if ('0'<=*st<='9') {
i=Str2I64(st,10,&ptr);
if (0<=i<=0xFF) {
res.color=i;
st=ptr;
} else
return COLOR_INVALID;
} else
return COLOR_INVALID;
}
}
CColorROPU32 Str2ColorU32(U8 *st)
{//$LK,"DCLighting",A="MN:DCLighting"$ color str with flags to $LK,"CColorROPU32",A="MN:CColorROPU32"$.
U8 *st2;
CColorROPU32 res=0;
if (!st) return COLOR_INVALID;
st2=MAlloc(StrLen(st)+1);
StrFirstRem(st,str2color_lst,st2);
res.c0=Str2ColorU16(st2);
if (*st) {
res.c1=Str2ColorU16(st);
res|=ROPF_DITHER;
}
if (res.c0.color==COLOR_INVALID||res.c1.color==COLOR_INVALID)
return COLOR_INVALID;
else
return res;
}
+237
View File
@@ -0,0 +1,237 @@
U0 SysGlblsInit()
{
I64 i,j;
CRAXRBCRCXRDX ee;
CPUId(0x1,&ee);
sys_cache_line_width=ee.rbx.u8[1]*8;
sys_focus_task=Fs;
QueInit(&sys_macro_head);
blkdev.dft_iso_filename =AStrNew(DFT_ISO_FILENAME);
blkdev.dft_iso_c_filename =AStrNew(DFT_ISO_C_FILENAME);
blkdev.tmp_filename =AStrNew("~/Tmp.DD.Z");
blkdev.dvd_boot_is_good=TRUE;
#exe {
if (!kernel_cfg->auto_mount_ide_hd_let)
kernel_cfg->auto_mount_ide_hd_let='C';
if (!kernel_cfg->auto_mount_ide_cd_let)
kernel_cfg->auto_mount_ide_cd_let='T';
StreamPrint("blkdev.first_hd_drv_let=%d;",
kernel_cfg->auto_mount_ide_hd_let);
StreamPrint("blkdev.first_dvd_drv_let=%d;",
kernel_cfg->auto_mount_ide_cd_let);
}
DbgMode(ON);
rev_bits_table=CAlloc(256);
set_bits_table=CAlloc(256);
for (i=0;i<256;i++)
for (j=0;j<8;j++) {
if (Bt(&i,7-j)) LBts(rev_bits_table+i,j);
if (Bt(&i,j)) set_bits_table[i]++;
}
ext=CAlloc(EXT_EXTS_NUM*sizeof(U8 *));
fp_getstr2=&SysGetStr2;
KeyDevInit;
#exe {
StreamPrint("blkdev.boot_drv_let='%C';",kernel_cfg->boot_drv_let);
StreamPrint("#exe{Option(OPTf_WARN_PAREN,OFF);}");
StreamPrint("DskCacheInit(%s);",kernel_cfg->dsk_cache_size_exp);
StreamPrint("#exe{Option(OPTf_WARN_PAREN,ON);}");
};
pow10_I64=CAlloc(sizeof(F64)*(308+308+1));
for (i=-308;i<309;i++)
pow10_I64[i+309]=Pow10(i);
snd.ona=ONA_REST;
QueInit(&snd.record_head);
snd.record_head.time=tS;
ProgressBarsRst;
QueInit(&dev.pci_head);
dev.mem64_ptr=mem_mapped_space;
dbg.fun_seg_cache=CAlloc(FUN_SEG_CACHE_SIZE*sizeof(CFunSegCache));
dbg.int_fault_code=IntFaultHndlrsNew;
}
U0 SysGrInit()
{
text.font=sys_font_std;
text.aux_font=sys_font_cyrillic;
text.vga_alias =dev.uncached_alias+VGAM_GRAPHICS;
text.vga_text_alias =dev.uncached_alias+VGAM_TEXT;
if (!Bt(&sys_run_level,RLf_VGA)) { //if text mode
text.cols=80;
text.rows=25;
MemSet(text.vga_text_alias,0,text.rows*text.cols<<1);
text.border_chars[2] (I64)='ÄͳºÚÉ¿»';
text.border_chars[10](U32)='ÀÈÙ¼';
} else { //if 640x480 16 color
text.cols=GR_WIDTH/FONT_WIDTH;
text.rows=GR_HEIGHT/FONT_HEIGHT;
OutU8(VGAP_IDX,VGAR_MAP_MASK);
OutU8(VGAP_DATA,0x0F);
MemSet(text.vga_alias,0,GR_WIDTH*GR_HEIGHT>>3);
text.raw_scrn_image=CAlloc(GR_WIDTH*GR_HEIGHT/8);
text.border_chars[2] (I64)=0x0908070605040302;
text.border_chars[10](U32)=0x0D0C0B0A;
}
}
U0 TimersInit()
{
I64 i,*_q;
U32 *_d;
OutU8(0x43,0x34);
OutU8(0x40,SYS_TIMER0_PERIOD);
OutU8(0x40,SYS_TIMER0_PERIOD>>8);
//High Precision Event Timer
if (PCIReadU16(0,31,0,0)==0x8086) {//Intel?
//D31 F0, cfg 0xF0=RCBA of PCI-LPC Bridge
_d=PCIReadU32(0,31,0,0xF0)(U8 *)&~0x3FFF+0x3404; //HPET cfg
//7 enable
//1:0 HPET is at 0xFED00000,0xFED01000, 0xFED02000 or 0xFED03000.
*_d=*_d&3|0x80;
}
_q=dev.uncached_alias+HPET_GCAP_ID;
i=*_q; //i.u32[1]= period in femtoS (10e-15)
if (100000<i.u32[1]<1000000000) {
cnts.HPET_freq =1000000000000000/i.u32[1];
cnts.HPET_kHz_freq=1000000000000/i.u32[1];
_q=dev.uncached_alias+HPET_GEN_CONF;
*_q|=1; //Enable counting
cnts.HPET_initial=HPET;
} else {
cnts.HPET_freq=0;
cnts.HPET_kHz_freq=0;
cnts.HPET_initial=0;
}
}
U0 Reboot()
{//Hardware reset.
CLI
if (mp_cnt>1)
MPHalt;
*0x472(U16 *)=0;
OutU8(0x70,0x8F);
OutU8(0x71,0x00);
OutU8(0x70,0x00);
OutU8(0x92,InU8(0x92)|1);
SysHlt;
}
U0 KMain()
{//Continued from $LK,"KStart64.HC",A="FF:::/Kernel/KStart64.HC,I32 &KMain"$
CBlkDev *bd;
OutU8(0x61,InU8(0x61)&~3); //Snd;
adam_task=Fs;
BlkPoolsInit;
SysGlblsInit;
Mem32DevInit;
UncachedAliasAlloc;
LoadKernel;
SysGrInit;
StrCpy(Fs->task_name,"Adam Task CPU00");
StrCpy(Fs->task_title,Fs->task_name);
Fs->title_src=TTS_TASK_NAME;
Fs->win_right=text.cols-2;
Fs->win_top++;
TaskDerivedValsUpdate;
SysDefinesLoad;
Core0Init;
IntInit1;
//Before this point use $LK,"Snd",A="MN:Snd"$() and $LK,"Busy",A="MN:Busy"$()
//to debug. After this point, use $LK,"RawPrint",A="MN:RawPrint"$()
LBts(&sys_run_level,RLf_RAW);
"TempleOS V%5.3f\t%D %T\n\n",
sys_os_version,sys_compile_time,sys_compile_time;
TimersInit;
if (BIOSTotalMem<ToI64(0.95*MEM_MIN_MEG*0x100000))
RawPrint(4000,"!!! Requires $TX,"512Meg",D="DD_MEM_MIN_MEG"$ of RAM Memory !!!");
IntsInit;
"Enable IRQ's\n";
SetRFlags(RFLAGG_NORMAL);
Busy(2000);
IntInit2;
LBts(&sys_run_level,RLf_INTERRUPTS);
TimeStampFreqCal;
BlkDevsInitAll;
"ChgDsk(':');\n";
ChgDsk(':');
#exe {
StreamPrint("HomeSet(\"%s\");\n"
"blkdev.ins_base0=%d;blkdev.ins_base1=%d;blkdev.ins_unit =%d;\n",
kernel_cfg->home_dir,
blkdev.ins_base0,blkdev.ins_base1,blkdev.ins_unit);
}
Gs->idle_task->cur_dv=blkdev.let_to_drv[*blkdev.home_dir-'A'];
DrvRep;
if (blkdev.dvd_boot_is_good) {
bd=Let2BlkDev(':');
if (bd->type==BDT_ATAPI) {
blkdev.ins_base0=bd->base0;
blkdev.ins_base1=bd->base1;
blkdev.ins_unit =bd->unit;
}
}
LBts(&sys_run_level,RLf_BLKDEV);
#exe {
if (!kernel_cfg->opts[CFG_NO_MP])
StreamPrint("\"MultiCore Start\\n\\n\";"
"Core0StartMP;"
"LBts(&sys_run_level,RLf_MP);");
};
KbdMsInit;
MsInit;
KbdInit;
Spawn(&MsHardDrvrInstall);
"Loading Compiler\n";
Cd("/Compiler");
Load("Compiler",LDF_SILENT);
LBts(&sys_run_level,RLf_COMPILER);
DbgMode(OFF);
cnts.time_stamp_freq_initial=TimeStampFreqCal;
Cd("/");
try ExeFile("StartOS"); //Continues $LK,"/StartOS.HC",A="FL:/StartOS.HC,1"$
catch {
Raw(ON);
Silent(OFF);
GetOutOfDollar;
PutExcept;
Dbg;
}
LBts(&sys_run_level,RLf_ADAM_SERVER);
SrvTaskCont; //Never to return
}
asm { ALIGN 16,OC_NOP
SYS_KERNEL_END::
#exe {
if (kernel_cfg->opts[CFG_DBG_DISTRO])
StreamPrint("DU8 0x%X-(SYS_KERNEL_END-SYS_KERNEL+"
"BOOT_RAM_BASE+sizeof(CBinFile)) DUP (0);"
"BINFILE \"%s\";",kernel_cfg->dbg_distro_start,
kernel_cfg->dbg_distro_file);
};
}
+149
View File
@@ -0,0 +1,149 @@
asm {
#assert !((REGG_LOCAL_NON_PTR_VARS|REGG_LOCAL_VARS)&~0xFCC0)
_TEST_EXCEPT::
XOR RAX,RAX
MOV RAX,FS:U64 CTask.last_except[RAX]
MOV RBP,U64 CExcept.rbp[RAX]
MOV RSI,U64 CExcept.rsi[RAX]
MOV RDI,U64 CExcept.rdi[RAX]
MOV R10,U64 CExcept.r10[RAX]
MOV R11,U64 CExcept.r11[RAX]
MOV R12,U64 CExcept.r12[RAX]
MOV R13,U64 CExcept.r13[RAX]
MOV R14,U64 CExcept.r14[RAX]
MOV R15,U64 CExcept.r15[RAX]
PUSH U64 CExcept.rflags[RAX]
POPFD
JMP U64 CExcept.hndlr_catch[RAX]
_TAKE_EXCEPT::
XOR RAX,RAX
MOV RAX,FS:U64 CTask.last_except[RAX]
MOV RSP,U64 CExcept.rsp[RAX]
JMP U64 CExcept.hndlr_untry[RAX]
_SAVE_EXCEPT_REGS::
PUSH RBP
MOV RBP,RSP
MOV RAX,U64 SF_ARG1[RBP]
MOV U64 CExcept.rsi[RAX],RSI
MOV U64 CExcept.rdi[RAX],RDI
MOV U64 CExcept.r10[RAX],R10
MOV U64 CExcept.r11[RAX],R11
MOV U64 CExcept.r12[RAX],R12
MOV U64 CExcept.r13[RAX],R13
MOV U64 CExcept.r14[RAX],R14
MOV U64 CExcept.r15[RAX],R15
POP RBP
RET1 8
}
_extern _TEST_EXCEPT U0 TestExcept();
_extern _TAKE_EXCEPT U0 TakeExcept();
_extern _SAVE_EXCEPT_REGS U0 SaveExceptRegs(CExcept *t);
U0 PutExcept(Bool catch_it=TRUE)
{//Print exception msg and catch exception.
"Except:%c:",Fs->except_ch;
"%P:%P:%P:%P:%P:%P\n",Fs->except_callers[0],Fs->except_callers[1],
Fs->except_callers[2],Fs->except_callers[3],Fs->except_callers[4],
Fs->except_callers[5],Fs->except_callers[6],Fs->except_callers[7];
Fs->catch_except=catch_it;
}
#exe {Option(OPTf_NO_REG_VAR,ON);};
class CTryStk
{
I64 rbp;
I64 ret_rip;
I64 arg1;
I64 arg2;
};
U0 SysTry(U8 *catch_start,U8 *untry_start)
{
I64 *rbp=GetRBP;
CExcept *tmpt=MAlloc(sizeof(CExcept));
tmpt->hndlr_catch=catch_start;
tmpt->hndlr_untry=untry_start;
tmpt->rsp=rbp(U8 *)+sizeof(CTryStk);
tmpt->rbp=*rbp;
tmpt->rflags=GetRFlags;
SaveExceptRegs(tmpt);
QueIns(tmpt,Fs->last_except);
}
U0 SysUntry()
{
CExcept *tmpt=Fs->last_except;
QueRem(tmpt);
Free(tmpt);
}
U0 throw(I64 ch=0,Bool no_log=FALSE)
{//ch can be up to 8 chars like $LK,"PutChars",A="MN:PutChars"$().
//In the catcher, fetch ch from Fs->except_ch.
CExcept *tmpt=Fs->last_except;
Bool was_raw;
I64 i;
Fs->except_ch=ch;
for (i=0;i<TASK_EXCEPT_CALLERS;i++)
Fs->except_callers[i]=Caller(i+1);
Fs->except_rbp=GetRBP;
Fs->catch_except=FALSE;
if (!no_log)
AdamLog("Except:%c:%p:%p:%p:%p:%p:%p\n",ch,Fs->except_callers[0],
Fs->except_callers[1],Fs->except_callers[2],Fs->except_callers[3],
Fs->except_callers[4],Fs->except_callers[5],Fs->except_callers[6],
Fs->except_callers[7]);
while (Fs->next_except!=&Fs->next_except) {
TestExcept;
if (Fs->catch_except)
TakeExcept;
SetRBP(Fs->except_rbp);
tmpt=Fs->last_except;
QueRem(tmpt);
Free(tmpt);
}
was_raw=Raw(ON);
PutExcept(FALSE);
Panic("Unhandled Exception");
Raw(was_raw);
}
#exe {Option(OPTf_NO_REG_VAR,OFF);};
U0 Break()
{//Send <CTRL-ALT-c>.
if (Bt(&Fs->task_flags,TASKf_BREAK_TO_SHIFT_ESC))
Msg(MSG_KEY_DOWN,CH_SHIFT_ESC,0x20100000201);
else {
Fs->wake_jiffy=0;
TaskRstAwaitingMsg;
DrvsRelease();
BlkDevsRelease();
FlushMsgs;
throw('Break');
}
}
Bool BreakLock(CTask *task=NULL)
{//Disables <CTRL-ALT-c>.
if (!task) task=Fs;
return !LBts(&task->task_flags,TASKf_BREAK_LOCKED);
}
Bool BreakUnlock(CTask *task=NULL)
{//Reenables <CTRL-ALT-c> and issues any pending breaks.
Bool res;
if (!task) task=Fs;
res=LBtr(&task->task_flags,TASKf_BREAK_LOCKED);
if (LBtr(&task->task_flags,TASKf_PENDING_BREAK)) {
if (task==Fs)
Break;
else
task->rip=&Break;
}
return res;
}
+109
View File
@@ -0,0 +1,109 @@
/*
If you are sure a fun won't be called
before import is resolved, you can use
"import". Otherwise, use a fun pointer
var and check it before calling.
*/
import U8 *DocSave(CDoc *doc,I64 *_size=NULL);
import Bool DocUnlock(CDoc *doc);
import Bool Ed(U8 *link_st,I64 edf_dof_flags=0);
extern U0 AdamErr(U8 *fmt,...);
extern U0 AdamLog(U8 *fmt,...);
extern I64 BIOSTotalMem();
extern I64 BlkDevAdd(CBlkDev *bd,I64 prt_num=I64_MIN,
Bool whole_drv,Bool make_free);
extern CBlkDev *BlkDevChk(CBlkDev *bd,Bool except=TRUE);
extern Bool BlkDevLock(CBlkDev *bd);
extern CBlkDev *BlkDevNextFreeSlot(U8 first_drv_let,I64 type);
extern Bool BlkDevUnlock(CBlkDev *bd,Bool rst=FALSE);
extern U0 BlkDevsRelease();
extern U8 *Caller(I64 num=1);
extern U8 *CatPrint(U8 *_dst,U8 *fmt,...);
extern Bool Cd(U8 *dirname=NULL,Bool make_dirs=FALSE);
extern U0 DbgHelp();
extern U8 *Define(U8 *dname);
extern I64 DefineMatch(U8 *needle,U8 *haystack_lst_dname,I64 flags=0);
extern U8 *DefineSub(I64 sub,U8 *dname);
extern I64 Del(U8 *files_find_mask,Bool make_mask=FALSE,
Bool del_dir=FALSE,Bool print_msg=TRUE);
extern U8 *DftExt(U8 *filename,U8 *extension);
extern Bool Drv(U8 drv_let);
extern U8 Drv2Let(CDrv *dv=NULL);
extern U0 DrvBlkDevDel(CBlkDev *bd);
extern CDrv *DrvChk(CDrv *dv,Bool except=TRUE);
extern U8 DrvTextAttrGet(U8 drv_let=0);
extern Bool DrvTypeSet(U8 drv_let,I64 type=FSt_REDSEA);
extern U0 DrvsRelease();
extern U0 DskCacheInvalidate(CDrv *dv);
extern U0 Exit();
extern I64 FAT32AllocClusters(CDrv *dv,I64 c,I64 cnt);
extern I64 FAT32AllocContiguousClusters(CDrv *dv,I64 cnt);
extern Bool FAT32DirNew(CDrv *dv,U8 *cur_dir,CDirEntry *tmpde,
Bool free_old_chain);
extern Bool FAT32FileFind(CDrv *dv,I64 cur_dir_cluster,U8 *name,
CDirEntry *_res,I64 fuf_flags=0);
extern U0 FAT32Init(CDrv *dv);
extern U0 FClose(CFile *f);
extern CFile *FOpen(U8 *filename,U8 *flags,I64 cnt=0);
extern Bool FRBlks(CFile *f,U8 *buf,I64 blk=FFB_NEXT_BLK,I64 cnt=1);
extern Bool FWBlks(CFile *f,U8 *buf,I64 blk=FFB_NEXT_BLK,I64 cnt=1);
extern U8 *FileExtRem(U8 *src,U8 *dst=NULL);
extern Bool FileFind(U8 *filename,CDirEntry *_de=NULL,I64 fuf_flags=0);
extern U8 *FileNameAbs(U8 *_filename,I64 fuf_flags=0);
extern U8 *FileRead(U8 *filename,I64 *_size=NULL,I64 *_attr=NULL);
extern I64 FileWrite(U8 *filename,U8 *fbuf,I64 size,CDate cdt=0,I64 attr=0);
extern I64 FlushMsgs(CTask *task=NULL);
extern I64 GetChar(I64 *_scan_code=NULL,Bool echo=TRUE,Bool raw_cursor=FALSE);
extern I64 GetS(U8 *buf,I64 size,Bool allow_ext=TRUE);
extern CHeapCtrl *HeapCtrlInit(CHeapCtrl *hc=NULL,
CTask *task=NULL,CBlkPool *bp);
extern Bool ISO1FileFind(CDrv *dv,I64 cur_dir_cluster,U8 *name,
CDirEntry *_res,I64 fuf_flags=0);
extern Bool ISOInit(CDrv *dv,I64 blk);
extern Bool IsDbgMode();
extern Bool IsDir(U8 *dir_name);
extern Bool IsRaw();
extern U0 JobCtrlInit(CJobCtrl *ctrl);
extern U0 JobDel(CJob *tmpc);
extern U0 JobQueDel(CJob *head);
extern I64 JobsHndlr(I64 run_flags,CTask *task=NULL);
extern CBlkDev *Let2BlkDev(U8 drv_let=0,Bool except=TRUE);
extern I64 Let2BlkDevType(U8 drv_let);
extern CDrv *Let2Drv(U8 drv_let=0,Bool except=TRUE);
extern U8 Let2Let(U8 drv_let=0);
extern U0 MPInt(U8 num,I64 cpu_num=1);
extern U8 *MStrPrint(U8 *fmt,...);
extern Bool MkDir(U8 *filename,I64 entry_cnt=0);
extern U0 MsHardSet(I64 x,I64 y,I64 z,I64 l,I64 r);
extern U0 Msg(I64 msg_code,I64 arg1,I64 arg2,I64 flags=0);
extern U0 Panic(U8 *msg=NULL,I64 msg_num=0,Bool panic=TRUE);
extern I64 PopUp(U8 *buf,CTask *parent=NULL,CTask **_pu_task=NULL);
extern U0 Print(U8 *fmt,...);
extern U0 PutChars(U64 ch);
extern U0 PutS(U8 *st); //Use $LK,"Print",A="MN:Print"$()
extern Bool RBlks(CDrv *dv,U8 *buf, I64 blk, I64 cnt);
extern I64 RedSeaAllocClusters(CDrv *dv,I64 cnt);
extern Bool RedSeaDirNew(CDrv *dv,U8 *cur_dir,CDirEntry *tmpde,
Bool free_old_chain);
extern Bool RedSeaFileFind(CDrv *dv,I64 cur_dir_cluster,U8 *name,
CDirEntry *_res,I64 fuf_flags=0);
extern U0 RedSeaFmt(U8 drv_let,Bool quick=TRUE);
extern U0 RedSeaFreeFreeLst(CDrv *dv);
extern U0 RedSeaInit(CDrv *dv);
extern Bool RedSeaValidate(U8 drv_let);
extern CTask *SpawnQue(U0 (*fp_addr)(U8 *data),U8 *data=NULL,
U8 *task_name=NULL,I64 target_cpu,CTask *parent=NULL, //NULL means adam
I64 stk_size=0,I64 flags=1<<JOBf_ADD_TO_QUE);
extern U8 *StrPrint(U8 *dst,U8 *fmt,...);
extern U0 StrPrintFunSeg(U8 *buf,I64 addr,I64 field_len,I64 flags);
extern Bool Suspend(CTask *task=NULL,Bool state=TRUE);
extern CJob *TaskMsg(CTask *_srv,CTask *master,
I64 msg_code,I64 arg1,I64 arg2,I64 flags);
extern U0 TaskRstAwaitingMsg(CTask *task=NULL);
extern Bool TaskValidate(CTask *task);
extern U0 TaskWait(CTask *task=NULL,Bool cmd_line_pmt=FALSE);
extern CTask *User(U8 *fmt=NULL,...);
extern U0 UserTaskCont();
extern Bool WBlks(CDrv *dv,U8 *buf, I64 blk, I64 cnt);
extern U0 XTalk(CTask *task,U8 *fmt,...);
extern U0 throw(I64 ch=0,Bool no_log=FALSE);
+35
View File
@@ -0,0 +1,35 @@
//Compiler initializes glbls in AOT bin modules to zero.
//$LK,"Globals Set to Zero Here",A="FF:::/Compiler/PrsStmt.HC,Init AOT glbl to zero"$.
CJob sys_macro_head;
CTask *sys_macro_task;
CDoc *sys_clipboard_doc;
CTask *adam_task;
I64 sys_num_spawned_tasks;
CTask *sys_winmgr_task,*sys_task_being_scrn_updated;
U8 *rev_bits_table, //Table with U8 bits revd
*set_bits_table; //Table with count of set bits in a U8
CDate local_time_offset;
F64 *pow10_I64,
sys_os_version=5.020;
CAutoCompleteDictGlbls acd;
CAutoCompleteGlbls ac;
CBlkDevGlbls blkdev;
CCntsGlbls cnts={1,0,2676302000,2676302,2676302000,0,0,0,FALSE};
CDbgGlbls dbg;
CDevGlbls dev;
CGridGlbls ms_grid; //See $LK,"::/Demo/Graphics/Grid.HC"$.
CMsStateGlbls ms,ms_last;
CKbdStateGlbls kbd;
CKeyDevGlbls keydev;
CMsHardStateGlbls ms_hard,ms_hard_last;
CSndGlbls snd;
CTextGlbls text;
U8 *(*fp_getstr2)(I64 flags=0);
U0 (*fp_update_ctrls)(CTask *task);
CDoc *(*fp_doc_put)(CTask *task=NULL);
U0 (*fp_set_std_palette)();
+265
View File
@@ -0,0 +1,265 @@
asm {
//************************************
SYS_HASH_STR::
// IN: RSI=Addr of string
// OUT: RAX
XOR RAX,RAX
TEST RSI,RSI
JZ @@15
PUSH RSI
PUSH RBX
XOR RBX,RBX
JMP @@10
@@05: SHL1 RBX
ADC RBX,RAX
@@10: LODSB
TEST AL,AL
JNZ @@05
MOV RAX,RBX
SHR RBX,16
ADC RAX,RBX
POP RBX
POP RSI
@@15: RET
//************************************
SYS_HASH_SINGLE_TABLE_FIND1::
// IN: RAX=HASHED STRING VAL
// RSI=STR
// RBX=TYPE MASK
// RDI=TABLE
// RCX=INSTANCE, NOT ZERO
// OUT: RAX=ENTRY OR ZERO NOT FOUND
// RDX=POINTER TO POINTER TO ENTRY
// RCX IF NOT FOUND ENOUGH, DECREMENTED BY NUM MATCHES
// ZERO FLAG SET NOT FOUND
MOV RCX,1
SYS_HASH_SINGLE_TABLE_FIND::
TEST RCX,RCX
JNZ @@05
XOR RAX,RAX
RET
@@05: AND RAX,U64 CHashTable.mask[RDI]
MOV RDX,U64 CHashTable.body[RDI]
LEA RDX,U64 [RDX+RAX*8]
@@10: MOV RAX,U64 [RDX]
TEST RAX,RAX
JNZ @@15
RET
@@15: TEST U32 CHash.type[RAX],EBX
JZ @@30
PUSH RAX
PUSH RDI
PUSH RSI
MOV RDI,U64 CHash.str[RAX]
@@20: LODSB
CMP U8 [RDI],AL
JNE @@25
INC RDI
TEST AL,AL
JNZ @@20
POP RSI
POP RDI
POP RAX
LOOP @@30
INC U32 CHash.use_cnt[RAX]
TEST RAX,RAX
RET
@@25: POP RSI
POP RDI
POP RAX
@@30: LEA RDX,U64 CHash.next[RAX]
JMP @@10
//************************************
SYS_HASH_FIND1::
// IN: RSI=STR
// RBX=TYPE MASK
// RDI=TABLE
// RCX=INSTANCE NUM
// OUT: RAX=ENTRY OR ZERO NOT FOUND
// ZERO FLAG SET NOT FOUND
MOV RCX,1
SYS_HASH_FIND::
PUSH RDI
CALL SYS_HASH_STR
@@05: PUSH RAX
CALL SYS_HASH_SINGLE_TABLE_FIND
JNZ @@15
POP RAX
@@10: MOV RDI,U64 CHashTable.next[RDI]
TEST RDI,RDI
JNZ @@05
POP RDI
XOR RAX,RAX
RET
@@15: ADD RSP,8
POP RDI
TEST RAX,RAX
RET
//************************************
SYS_HASH_BUCKET_FIND::
// IN: RSI=STR
// RDI=TABLE
// OUT: RAX=BUCKET
PUSH RDX
CALL SYS_HASH_STR
AND RAX,U64 CHashTable.mask[RDI]
MOV RDX,U64 CHashTable.body[RDI]
LEA RAX,U64 [RDX+RAX*8]
POP RDX
RET
_HASH_STR::
PUSH RBP
MOV RBP,RSP
PUSH RSI
MOV RSI,U64 SF_ARG1[RBP]
CALL SYS_HASH_STR
POP RSI
POP RBP
RET1 8
_HASH_FIND::
PUSH RBP
MOV RBP,RSP
PUSH RSI
PUSH RDI
MOV RSI,U64 SF_ARG1[RBP]
MOV RDI,U64 SF_ARG2[RBP]
MOV RBX,U64 SF_ARG3[RBP]
MOV RCX,U64 SF_ARG4[RBP]
CALL SYS_HASH_FIND
POP RDI
POP RSI
POP RBP
RET1 32
_HASH_SINGLE_TABLE_FIND::
PUSH RBP
MOV RBP,RSP
PUSH RSI
PUSH RDI
MOV RSI,U64 SF_ARG1[RBP]
MOV RDI,U64 SF_ARG2[RBP]
MOV RBX,U64 SF_ARG3[RBP]
MOV RCX,U64 SF_ARG4[RBP]
CALL SYS_HASH_STR
CALL SYS_HASH_SINGLE_TABLE_FIND
POP RDI
POP RSI
POP RBP
RET1 32
_HASH_BUCKET_FIND::
PUSH RBP
MOV RBP,RSP
PUSH RSI
PUSH RDI
MOV RSI,U64 SF_ARG1[RBP]
MOV RDI,U64 SF_ARG2[RBP]
CALL SYS_HASH_BUCKET_FIND
POP RDI
POP RSI
POP RBP
RET1 16
_HASH_ADD::
PUSH RBP
MOV RBP,RSP
PUSH RSI
PUSH RDI
MOV RCX,U64 SF_ARG1[RBP]
MOV RSI,U64 CHash.str[RCX]
MOV RDI,U64 SF_ARG2[RBP]
CALL SYS_HASH_BUCKET_FIND
MOV RCX,U64 SF_ARG1[RBP]
PUSHFD
CLI
MOV RBX,U64 [RAX]
MOV U64 CHash.next[RCX],RBX
MOV U64 [RAX],RCX
POPFD
POP RDI
POP RSI
POP RBP
RET1 16
_HASH_ADD_AFTER::
PUSH RBP
MOV RBP,RSP
PUSH RDI
MOV RCX,U64 SF_ARG1[RBP]
MOV RDI,U64 SF_ARG3[RBP]
PUSHFD
CLI
MOV RAX,SF_ARG2[RBP]
MOV RBX,U64 [RAX]
MOV U64 CHash.next[RCX],RBX
MOV U64 [RAX],RCX
POPFD
POP RDI
POP RBP
RET1 24
_HASH_REM_DEL::
PUSH RBP
MOV RBP,RSP
PUSH RSI
PUSH RDI
MOV RCX,U64 SF_ARG1[RBP]
TEST RCX,RCX
JZ @@10
MOV RSI,U64 CHash.str[RCX]
XOR RBX,RBX
MOV EBX,U32 CHash.type[RCX]
AND EBX,~HTG_FLAGS_MASK&0xFFFFFFFF
MOV RDI,U64 SF_ARG2[RBP]
MOV RCX,U64 SF_ARG3[RBP]
CALL SYS_HASH_STR
PUSHFD
CLI
CALL SYS_HASH_SINGLE_TABLE_FIND
JZ @@05
CMP RAX,U64 SF_ARG1[RBP]
JNE @@05
MOV RBX,U64 CHash.next[RAX]
MOV U64 [RDX],RBX
POPFD
PUSH_C_REGS
PUSH RAX
CALL &HashDel
POP_C_REGS
POP RDI
POP RSI
MOV RAX,1
POP RBP
RET1 24
@@05: POPFD
@@10: POP RDI
POP RSI
XOR RAX,RAX
POP RBP
RET1 24
}
_extern _HASH_STR I64 HashStr(U8 *st); //Hash a string.
_extern _HASH_FIND CHash *HashFind(U8 *needle_str,CHashTable *haystack_table,
I64 mask,I64 instance=1);//Find string in hash table.
_extern _HASH_SINGLE_TABLE_FIND CHash *HashSingleTableFind(U8 *needle_str,
CHashTable *haystack_table,
I64 mask,I64 instance=1);//Find string in single hash table.
_extern _HASH_BUCKET_FIND CHash **HashBucketFind(U8 *needle_str,
CHashTable *haystack_table); //Find hash bucket.
_extern _HASH_ADD U0 HashAdd(CHash *tmph,
CHashTable *table); //Add entry to hash table.
_extern _HASH_REM_DEL Bool HashRemDel(CHash *tmph,CHashTable *table,
I64 instance=1);//Remove hash entry and del. Instance must match.
+250
View File
@@ -0,0 +1,250 @@
I64 HashTypeNum(CHash *tmph)
{//Return bit num of hash type, limited to just types.
if (tmph)
return Bsf(tmph->type&HTG_TYPE_MASK);
else
return -1;
}
I64 HashVal(CHash *tmph)
{//Returns most likely desired value.
switch [HashTypeNum(tmph)] {
case HTt_EXPORT_SYS_SYM:
return tmph(CHashExport *)->val;
case HTt_IMPORT_SYS_SYM:
return tmph(CHashImport *)->module_base;
case HTt_DEFINE_STR:
case HTt_CLASS:
case HTt_INTERNAL_TYPE:
case HTt_WORD:
case HTt_DICT_WORD:
case HTt_OPCODE:
case HTt_HELP_FILE:
return tmph;
case HTt_GLBL_VAR:
if (tmph(CHashGlblVar *)->flags&GVF_EXTERN)
return &tmph(CHashGlblVar *)->data_addr;
else
return tmph(CHashGlblVar *)->data_addr;
case HTt_FUN:
if (Bt(&tmph(CHashFun *)->flags,Cf_EXTERN))
return tmph;
else
return tmph(CHashFun *)->exe_addr;
case HTt_REG:
return tmph(CHashReg *)->reg_num|tmph(CHashReg *)->reg_type<<8;
case HTt_KEYWORD:
case HTt_ASM_KEYWORD:
case HTt_MODULE:
case HTt_FILE:
case HTt_FRAME_PTR:
return tmph(CHashGeneric *)->user_data0;
case -1: //nobound switch
case HTt_TYPES_NUM: //nobound switch
default:
return 0;
}
}
CHashTable *HashTableNew(I64 size,CTask *mem_task=NULL)
{//New hash table, power-of-two in size.
CHashTable *table;
table=CAlloc(sizeof(CHashTable),mem_task);
table->body=CAlloc(size<<3,mem_task);
table->mask=size-1;
return table;
}
U0 HashDel(CHashSrcSym *tmph)
{//Free a std TempleOS system hash entry.
if (!tmph) return;
if (!(tmph->type&HTT_DICT_WORD))
Free(tmph->str);
if (tmph->type & HTG_SRC_SYM) {
Free(tmph->src_link);
Free(tmph->idx);
Free(tmph->import_name);
LinkedLstDel(tmph->ie_lst);
if (tmph->type & (HTT_FUN | HTT_EXPORT_SYS_SYM))
Free(tmph->dbg_info);
if (tmph->type & (HTT_FUN | HTT_CLASS))
//Assumes code not on heap, so doesn't Free.
//$LK,"ClassMemberLstDel",A="MN:ClassMemberLstDel"$() is an import to the Kernel module
ClassMemberLstDel(tmph);
else if (tmph->type&HTT_DEFINE_STR)
Free(tmph(CHashDefineStr *)->data);
else if (tmph->type & HTT_GLBL_VAR) {
if (!(tmph(CHashGlblVar *)->flags&GVF_ALIAS))
Free(tmph(CHashGlblVar *)->data_addr);
LinkedLstDel(tmph(CHashGlblVar *)->dim.next);
if (tmph(CHashGlblVar *)->fun_ptr)
HashDel(tmph(CHashGlblVar *)->fun_ptr
-tmph(CHashGlblVar *)->fun_ptr->ptr_stars_cnt);
}
} else if (tmph->type & HTT_FILE)
Free(tmph(CHashGeneric *)->user_data0);
Free(tmph);
}
U0 HashTableDel(CHashTable *table)
{//Free std system hash table, calling $LK,"HashDel",A="MN:HashDel"$() on entries.
I64 i;
CHashSrcSym *tmph,*tmph1;
if (!table) return;
for (i=0;i<=table->mask;i++) {
tmph=table->body[i];
while (tmph) {
tmph1=tmph->next;
HashDel(tmph);
tmph=tmph1;
}
}
Free(table->body);
Free(table);
}
I64 HashTablePurge(CHashTable *table)
{//Eliminate ExportSysSyms that have been usurped.
I64 i,res=0;
CHashSrcSym *tmph,*tmph1,*tmph2;
if (!table) return 0;
PUSHFD
CLI //Precaution
for (i=0;i<=table->mask;i++) {
tmph=table->body[i];
while (tmph) {
tmph1=tmph->next; //We delete only older ones
if (tmph->type&(HTT_FUN|HTT_GLBL_VAR)) {
tmph2=tmph->next; //Older always later in chain
while (tmph2) {
if ((tmph2->type&HTT_EXPORT_SYS_SYM ||
tmph2->type&HTG_TYPE_MASK==HTT_INVALID) &&
!StrCmp(tmph2->str,tmph->str)) {
if (tmph2->type&HTG_TYPE_MASK==HTT_INVALID)
tmph2->type=HTT_KEYWORD;//Won't delete HTT_INVALID
HashRemDel(tmph2,table);
res++;
break;
}
tmph2=tmph2->next;
}
}
tmph=tmph1;
}
}
POPFD
return res;
}
CHashGeneric *HashGenericAdd(U8 *name,I64 type,
I64 u0=0,I64 u1=0,I64 u2=0,CTask *task=NULL)
{//Add any type to task hash_table, 3 user_data values.
if (!task) task=Fs;
CHashGeneric *res=CAlloc(sizeof(CHashGeneric),task);
res->type=type;
res->user_data0=u0;
res->user_data1=u1;
res->user_data2=u2;
res->str=StrNew(name,task);
HashAdd(res,task->hash_table);
return res;
}
U0 HashSrcFileSet(CCmpCtrl *cc,CHashSrcSym *h,I64 line_num_offset=0)
{//Set $LK,"CHashSrcSym",A="MN:CHashSrcSym"$ link and help_index by cur cc pos.
CLexFile *tmpf=cc->lex_include_stk;
I64 line_num=tmpf->line_num+line_num_offset;
if (line_num<1) line_num=1;
Free(h->src_link);
h->src_link=MStrPrint("FL:%s,%d",tmpf->full_name,line_num);
if (Bt(&cc->opts,OPTf_KEEP_PRIVATE))
h->type|=HTF_PRIVATE;
Free(h->idx);
if (cc->cur_help_idx && *cc->cur_help_idx)
h->idx=StrNew(cc->cur_help_idx);
else
h->idx=NULL;
}
CHashGeneric *HashPublic(U8 *st,I64 mask,Bool val=TRUE)
{//Mark a hash entry as public and $LK,"HashSrcFileSet",A="MN:HashSrcFileSet"$().
CHashGeneric *res;
if (res=HashFind(st,Fs->hash_table,mask)) {
if (val)
res->type|=HTF_PUBLIC;
else
res->type&=~HTF_PUBLIC;
if (res->type&HTG_SRC_SYM)
HashSrcFileSet(Fs->last_cc,res);
return res;
} else
return NULL;
}
I64 HashLstAdd(U8 *lst,I64 type,CHashTable *table)
{//Add a list to a hash table.
I64 i=0;
CHashGeneric *tmph;
if (lst) {
while (*lst) {
if (*lst=='@')
lst++;
else
i++;
tmph=CAlloc(sizeof(CHashGeneric));
tmph->user_data0=i-1;
tmph->str=StrNew(lst);
tmph->type=type;
HashAdd(tmph,table);
while (*lst++);
}
}
return i;
}
I64 HashDefineLstAdd(U8 *dname,I64 type,CHashTable *table)
{//Add define list to a hash table. See $LK,"::/Adam/DolDoc/DocInit.HC",A="FF:::/Adam/DolDoc/DocInit.HC,HashDefineLstAdd"$.
CHashDefineStr *tmph;
if (tmph=HashFind(dname,Fs->hash_table,HTT_DEFINE_STR))
return HashLstAdd(tmph->data,type,table);
else
return 0;
}
I64 FramePtr(U8 *name,CTask *task=NULL)
{//Find entry in task->hash_table, Return user_data.
CHashGeneric *tmph;
if (!task) task=Fs;
if (tmph=HashFind(name,task->hash_table,HTT_FRAME_PTR))
return tmph->user_data0;
else
return 0;
}
CHashGeneric *FramePtrAdd(U8 *name,I64 val=0,CTask *task=NULL)
{//Add named value to task->hash_table.
return HashGenericAdd(name,HTT_FRAME_PTR,val,0,0,task);
}
I64 FramePtrSet(U8 *name,I64 val,CTask *task=NULL)
{//Find hash entry in task->hash_table. Change user_data0.
CHashGeneric *tmph;
if (!task) task=Fs;
if (tmph=HashFind(name,task->hash_table,HTT_FRAME_PTR))
return LXchgI64(&tmph->user_data0,val);
else
return 0;
}
I64 FramePtrDel(U8 *name,CTask *task=NULL)
{//Remove entry and delete.
CHashGeneric *tmph;
I64 res=0;
if (!task) task=Fs;
if (tmph=HashFind(name,task->hash_table,HTT_FRAME_PTR)) {
res=tmph->user_data0;
HashRemDel(tmph,task->hash_table);
}
return res;
}
+215
View File
@@ -0,0 +1,215 @@
asm {
INT_MP_CRASH_ADDR:: //Forward reference to work around compiler
DU32 &IntMPCrash;
INT_WAKE::
PUSH RDX
PUSH RAX
MOV EAX,&dev
MOV EDX,U32 LAPIC_EOI
MOV RAX,U64 CDevGlbls.uncached_alias[RAX]
MOV U32 [RAX+RDX],0
POP RAX
POP RDX
IRET
IRQ_TIMER:: //I_TIMER
CALL TASK_CONTEXT_SAVE
CLD
MOV RAX,U64 [RSP]
MOV U64 CTask.rip[RSI],RAX
MOV RAX,U64 16[RSP]
MOV U64 CTask.rflags[RSI],RAX
MOV RAX,U64 24[RSP]
MOV U64 CTask.rsp[RSI],RAX
XOR RAX,RAX
MOV RDI,U64 GS:CCPU.addr[RAX]
LOCK
INC U64 CCPU.total_jiffies[RDI]
BT U64 CTask.task_flags[RSI],TASKf_IDLE
JNC @@05
LOCK
INC U64 CCPU.idle_pt_hits[RDI]
@@05: MOV RAX,U64 CCPU.profiler_timer_irq[RDI]
TEST RAX,RAX
JZ @@10
PUSH RSI
CALL RAX //See $LK,"ProfTimerInt",A="MN:ProfTimerInt"$().
JMP @@15
@@10: ADD RSP,8
@@15: CLI
MOV RAX,U64 CCPU.num[RDI]
TEST RAX,RAX
JZ @@20
MOV EAX,&dev
MOV EDX,U32 LAPIC_EOI
MOV RAX,U64 CDevGlbls.uncached_alias[RAX]
MOV U32 [RAX+RDX],0
JMP @@25
@@20: CALL &IntCore0TimerHndlr //Only Core 0 calls this.
@@25: XOR RAX,RAX
CMP RSI,U64 GS:CCPU.idle_task[RAX]
JE I32 RESTORE_SETH_TASK_IF_READY
JMP I32 RESTORE_RSI_TASK
//************************************
INT_FAULT::
PUSH RBX
PUSH RAX
MOV BL,U8 16[RSP] //We pushed fault_num $LK,"IntFaultHndlrsNew",A="MN:IntFaultHndlrsNew"$().
XOR RAX,RAX
MOV FS:U8 CTask.fault_num[RAX],BL
POP RAX
POP RBX
ADD RSP,8 //Pop fault_num
CALL TASK_CONTEXT_SAVE
XOR RDX,RDX
MOV U64 CTask.fault_err_code[RSI],RDX
MOV EDX,U32 CTask.fault_num[RSI]
BT U64 [INT_FAULT_ERR_CODE_BITMAP],RDX
JNC @@1
POP U64 CTask.fault_err_code[RSI]
@@1: MOV RAX,U64 [RSP]
MOV U64 CTask.rip[RSI],RAX
MOV RAX,U64 16[RSP]
MOV U64 CTask.rflags[RSI],RAX
MOV RSP,U64 24[RSP]
MOV U64 CTask.rsp[RSI],RSP
MOV RBP,CTask.rbp[RSI]
PUSH U64 CTask.fault_err_code[RSI]
PUSH U64 CTask.fault_num[RSI]
MOV RSI,CTask.rsi[RSI]
CALL &Fault2 //See $LK,"Fault2",A="FF:::/Kernel/KDbg.HC,Fault2"$
JMP I32 RESTORE_FS_TASK
INT_FAULT_ERR_CODE_BITMAP::
DU32 0x00027D00,0,0,0,0,0,0,0;
}
U8 *IntEntryGet(I64 irq)
{//Get interrupt vector.
U8 *res;
I64 *src;
src=dev.idt(U8 *)+irq*16;
res(I64).u16[0]=*src(U16 *);
src(U8 *)+=6;
res(I64).u16[1]=*src(U16 *)++;
res(I64).u32[1]=*src(U32 *);
return res;
}
U8 *IntEntrySet(I64 irq,U0 (*fp_new_hndlr)(),I64 type=IDTET_IRQ,I64 dpl=0)
{//Set interrupt vector. See $LK,"IDTET_IRQ",A="MN:IDTET_IRQ"$.
//See $LK,"::/Demo/Lectures/InterruptDemo.HC"$.
//See $LK,"::/Demo/MultiCore/Interrupts.HC"$.
I64 fp=fp_new_hndlr;
U8 *res,*dst;
PUSHFD
CLI
res=IntEntryGet(irq);
dst=dev.idt(U8 *)+irq*16;
*dst(U16 *)++=fp.u16[0];
*dst(U16 *)++=offset(CGDT.cs64);
*dst(U16 *)++=0x8000+type<<8+dpl<<13;
*dst(U16 *)++=fp.u16[1];
*dst(U32 *)++=fp.u32[1];
*dst(U32 *)=0;
POPFD
return res;
}
U0 IntsInit()
{//Init 8259
OutU8(0x20,0x11); //IW1
OutU8(0xA0,0x11); //IW1
OutU8(0x21,0x20); //IW2
OutU8(0xA1,0x28); //IW2
OutU8(0x21,0x04); //IW3
OutU8(0xA1,0x02); //IW3
OutU8(0x21,0x0D); //IW4
OutU8(0xA1,0x09); //IW4
OutU8(0x21,0xFA); //Mask all but IRQ0 (timer) and IRQ2 Cascade.
OutU8(0xA1,0xFF);
}
interrupt U0 IntNop()
{//Make unplanned IRQs stop by all means!
OutU8(0xA0,0x20);
OutU8(0x20,0x20);
*(dev.uncached_alias+LAPIC_EOI)(U32 *)=0;
}
interrupt U0 IntDivZero()
{
if (Gs->num) {
mp_cnt=1;
dbg.mp_crash->cpu_num=Gs->num;
dbg.mp_crash->task=Fs;
MOV RAX,U64 8[RBP] //Get RIP off of stk.
dbg.mp_crash->rip=GetRAX;
dbg.mp_crash->msg="Div Zero";
dbg.mp_crash->msg_num=0;
MPInt(I_MP_CRASH,0);
SysHlt;
}
throw('DivZero');
}
U8 *IntFaultHndlrsNew()
{
I64 i;
U8 *res=MAlloc(256*7,Fs->code_heap),*dst=res;
for (i=0;i<256;i++) {
*dst++=0x6A; //PUSH I8 xx
*dst(I8 *)++=i;
*dst++=0xE9; //JMP I32 xxxxxxxx
*dst(I32 *)=INT_FAULT-dst-4;
dst+=4;
}
return res;
}
U0 IntInit1()
{//Interrupt descriptor table part1.
I64 i;
CSysLimitBase tmp_ptr;
if (!Gs->num) {//Gs cur $LK,"CCPU",A="MN:CCPU"$ struct
dev.idt=CAlloc(16*256);
for (i=0;i<256;i++)
IntEntrySet(i,&IntNop);
}
tmp_ptr.limit=256*16-1;
tmp_ptr.base =dev.idt;
SetRAX(&tmp_ptr);
LIDT U64 [RAX]
}
U0 IntInit2()
{//Interrupt descriptor table part2: Core 0 Only.
I64 i;
PUSHFD
CLI
IntEntrySet(I_DIV_ZERO,&IntDivZero);
for (i=1;i<0x20;i++)
IntEntrySet(i,&dbg.int_fault_code[7*i]);
/*In theory, we use the PIC mask reg to insure we don't get
anything but keyboard, mouse and timer IRQs. In practice, I've
gotten IRQ 0x27, perhaps because I didn't initialize the APIC.
I go ahead and ACK PIC in $LK,"IntNop",A="MN:IntNop"$().
I have no idea why I got a IRQ 0x27.
*/
IntEntrySet(I_NMI,_SYS_HLT);
IntEntrySet(I_TIMER,IRQ_TIMER);
IntEntrySet(I_MP_CRASH,*INT_MP_CRASH_ADDR(U32 *));
IntEntrySet(I_WAKE,INT_WAKE);
IntEntrySet(I_DBG,&dbg.int_fault_code[7*I_DBG]);
POPFD
}
+250
View File
@@ -0,0 +1,250 @@
U0 LoadOneImport(U8 **_src,U8 *module_base,I64 ld_flags)
{
U8 *src=*_src,*ptr2,*st_ptr;
I64 i,etype;
CHashExport *tmpex=NULL;
CHashImport *tmpiss;
Bool first=TRUE;
while (etype=*src++) {
i=*src(U32 *)++;
st_ptr=src;
src+=StrLen(st_ptr)+1;
if (*st_ptr) {
if (!first) {
*_src=st_ptr-5;
return;
} else {
first=FALSE;
if (!(tmpex=HashFind(st_ptr,
Fs->hash_table,HTG_ALL-HTT_IMPORT_SYS_SYM))) {
if (!(ld_flags & LDF_SILENT))
"Unresolved Reference:%s\n",st_ptr;
tmpiss=CAlloc(sizeof(CHashImport));
tmpiss->str=StrNew(st_ptr);
tmpiss->type=HTT_IMPORT_SYS_SYM;
tmpiss->module_header_entry=st_ptr-5;
tmpiss->module_base=module_base;
HashAdd(tmpiss,Fs->hash_table);
}
}
}
if (tmpex) {
ptr2=module_base+i;
if (tmpex->type & HTT_FUN)
i=tmpex(CHashFun *)->exe_addr;
else if (tmpex->type & HTT_GLBL_VAR)
i=tmpex(CHashGlblVar *)->data_addr;
else
i=tmpex->val;
switch (etype) {
case IET_REL_I8: *ptr2(U8 *) =i-ptr2-1; break;
case IET_IMM_U8: *ptr2(U8 *) =i; break;
case IET_REL_I16: *ptr2(U16 *)=i-ptr2-2; break;
case IET_IMM_U16: *ptr2(U16 *)=i; break;
case IET_REL_I32: *ptr2(U32 *)=i-ptr2-4; break;
case IET_IMM_U32: *ptr2(U32 *)=i; break;
case IET_REL_I64: *ptr2(I64 *)=i-ptr2-8; break;
case IET_IMM_I64: *ptr2(I64 *)=i; break;
}
}
}
*_src=src-1;
}
U0 SysSymImportsResolve(U8 *st_ptr,I64 ld_flags)
{
CHashImport *tmpiss;
U8 *ptr;
while (tmpiss=HashSingleTableFind(st_ptr,
Fs->hash_table,HTT_IMPORT_SYS_SYM)) {
ptr=tmpiss->module_header_entry;
LoadOneImport(&ptr,tmpiss->module_base,ld_flags);
tmpiss->type=HTT_INVALID;
}
}
U0 LoadPass1(U8 *src,U8 *module_base,I64 ld_flags)
{
U8 *ptr2,*ptr3,*st_ptr;
I64 i,j,cnt,etype;
CHashExport *tmpex=NULL;
while (etype=*src++) {
i=*src(U32 *)++;
st_ptr=src;
src+=StrLen(st_ptr)+1;
switch (etype) {
case IET_REL32_EXPORT:
case IET_IMM32_EXPORT:
case IET_REL64_EXPORT:
case IET_IMM64_EXPORT:
tmpex=CAlloc(sizeof(CHashExport));
tmpex->str=StrNew(st_ptr);
tmpex->type=HTT_EXPORT_SYS_SYM|HTF_IMM;
if (etype==IET_IMM32_EXPORT||etype==IET_IMM64_EXPORT)
tmpex->val=i;
else
tmpex->val=i+module_base;
HashAdd(tmpex,Fs->hash_table);
SysSymImportsResolve(st_ptr,ld_flags);
break;
case IET_REL_I0...IET_IMM_I64:
src=st_ptr-5;
LoadOneImport(&src,module_base,ld_flags);
break;
case IET_ABS_ADDR:
if (ld_flags & LDF_NO_ABSS)
src+=i*sizeof(U32);
else {
cnt=i;
for (j=0;j<cnt;j++) {
ptr2=module_base+*src(U32 *)++;
*ptr2(U32 *)+=module_base;
}
}
break;
start:
case IET_CODE_HEAP:
ptr3=MAlloc(*src(I32 *)++,Fs->code_heap);
break;
case IET_ZEROED_CODE_HEAP:
ptr3=CAlloc(*src(I32 *)++,Fs->code_heap);
break;
end:
if (*st_ptr) {
tmpex=CAlloc(sizeof(CHashExport));
tmpex->str=StrNew(st_ptr);
tmpex->type=HTT_EXPORT_SYS_SYM|HTF_IMM;
tmpex->val=ptr3;
HashAdd(tmpex,Fs->hash_table);
}
cnt=i;
for (j=0;j<cnt;j++) {
ptr2=module_base+*src(U32 *)++;
*ptr2(I32 *)+=ptr3;
}
break;
start:
case IET_DATA_HEAP:
ptr3=MAlloc(*src(I64 *)++);
break;
case IET_ZEROED_DATA_HEAP:
ptr3=CAlloc(*src(I64 *)++);
break;
end:
if (*st_ptr) {
tmpex=CAlloc(sizeof(CHashExport));
tmpex->str=StrNew(st_ptr);
tmpex->type=HTT_EXPORT_SYS_SYM|HTF_IMM;
tmpex->val=ptr3;
HashAdd(tmpex,Fs->hash_table);
}
cnt=i;
for (j=0;j<cnt;j++) {
ptr2=module_base+*src(U32 *)++;
*ptr2(I64 *)+=ptr3;
}
break;
}
}
}
U0 LoadPass2(U8 *src,U8 *module_base,I64)
{
U8 *st_ptr;
I64 i,etype;
while (etype=*src++) {
i=*src(U32 *)++;
st_ptr=src;
src+=StrLen(st_ptr)+1;
switch (etype) {
case IET_MAIN:
Call(i+module_base);
break;
case IET_ABS_ADDR:
src+=sizeof(U32)*i;
break;
case IET_CODE_HEAP:
case IET_ZEROED_CODE_HEAP:
src+=4+sizeof(U32)*i;
break;
case IET_DATA_HEAP:
case IET_ZEROED_DATA_HEAP:
src+=8+sizeof(U32)*i;
break;
}
}
}
CBinFile *Load(U8 *filename,I64 ld_flags=0,CBinFile *bfh_addr=INVALID_PTR)
{//Load a .BIN file module into memory.
//bfh_addr==INVALID_PTR means don't care what load addr.
U8 *fbuf,*module_base,*absname;
I64 size,module_align,misalignment;
CBinFile *bfh;
fbuf=DftExt(filename,"BIN.Z");
if (!(bfh=FileRead(fbuf,&size))) {
Free(fbuf);
return NULL;
}
//See $LK,"Patch Table Generation",A="FF:::/Compiler/CMain.HC,IET_ABS_ADDR"$
module_align=1<<bfh->module_align_bits;
if (!module_align || bfh->bin_signature!=BIN_SIGNATURE_VAL) {
Free(bfh);
Free(fbuf);
throw('BinModul');
}
if (bfh_addr==INVALID_PTR) {
if (bfh->module_org==INVALID_PTR) {
misalignment=module_align-sizeof(CBinFile);
if (misalignment<0)
misalignment&=module_align-1;
if (Fs->code_heap!=Fs->data_heap) {
if (module_align<16)
module_align=16;
bfh_addr=MAllocAligned(size,module_align,Fs->code_heap,misalignment);
} else if (module_align>8)
bfh_addr=MAllocAligned(size,module_align,,misalignment);
else {//Less than 2Gig system memory
bfh_addr=bfh;
goto lo_skip; //File is already in code heap area, don't copy.
}
} else
bfh_addr=bfh->module_org;
}
MemCpy(bfh_addr,bfh,size);
Free(bfh);
lo_skip:
module_base=bfh_addr(U8 *)+sizeof(CBinFile);
absname=FileNameAbs(fbuf);
Free(fbuf);
fbuf=StrNew(absname);
FileExtRem(fbuf);
if (fbuf[1]==':' && StrLen(fbuf)>2)
HashGenericAdd(fbuf+2,HTT_MODULE|HTF_PUBLIC,bfh_addr);
LoadPass1(bfh_addr(U8 *)+bfh_addr->patch_table_offset,module_base,ld_flags);
if (!(ld_flags&LDF_JUST_LOAD))
LoadPass2(bfh_addr(U8 *)+bfh_addr->patch_table_offset,module_base,ld_flags);
Free(absname);
Free(fbuf);
return bfh_addr;
}
U0 LoadKernel()
{
HashGenericAdd(KERNEL_MODULE_NAME,HTT_MODULE|HTF_PUBLIC,
mem_boot_base-sizeof(CBinFile));
//Abs patches done here $LK,"CPatchTableAbsAddr",A="FF:D:/Kernel/KStart32.HC,CPatchTableAbsAddr"$.
LoadPass1(sys_boot_patch_table_base,mem_boot_base,LDF_NO_ABSS|LDF_SILENT);
//No main routines
// LoadPass2(sys_boot_patch_table_base,mem_boot_base,0);
}
+648
View File
@@ -0,0 +1,648 @@
asm {
//************************************
_D3_NORM::
PUSH RBP
MOV RBP,RSP
MOV RDX,U64 SF_ARG1[RBP]
FLD U64 [RDX]
FMUL ST0,ST0
FLD U64 8[RDX]
FMUL ST0,ST0
FADDP ST1,ST0
FLD U64 16[RDX]
FMUL ST0,ST0
FADDP ST1,ST0
FSQRT
FSTP U64 SF_ARG1[RBP]
MOV RAX,U64 SF_ARG1[RBP]
POP RBP
RET1 8
//************************************
_D3_NORM_SQR::
PUSH RBP
MOV RBP,RSP
MOV RDX,U64 SF_ARG1[RBP]
FLD U64 [RDX]
FMUL ST0,ST0
FLD U64 8[RDX]
FMUL ST0,ST0
FADDP ST1,ST0
FLD U64 16[RDX]
FMUL ST0,ST0
FADDP ST1,ST0
FSTP U64 SF_ARG1[RBP]
MOV RAX,U64 SF_ARG1[RBP]
POP RBP
RET1 8
//************************************
_D3_DIST::
PUSH RBP
MOV RBP,RSP
MOV RDX,U64 SF_ARG1[RBP]
MOV RBX,U64 SF_ARG2[RBP]
FLD U64 [RDX]
FSUB ST0,U64 [RBX]
FMUL ST0,ST0
FLD U64 8[RDX]
FSUB ST0,U64 8[RBX]
FMUL ST0,ST0
FADDP ST1,ST0
FLD U64 16[RDX]
FSUB ST0,U64 16[RBX]
FMUL ST0,ST0
FADDP ST1,ST0
FSQRT
FSTP U64 SF_ARG1[RBP]
MOV RAX,U64 SF_ARG1[RBP]
POP RBP
RET1 16
//************************************
_D3_DIST_SQR::
PUSH RBP
MOV RBP,RSP
MOV RDX,U64 SF_ARG1[RBP]
MOV RBX,U64 SF_ARG2[RBP]
FLD U64 [RDX]
FSUB ST0,U64 [RBX]
FMUL ST0,ST0
FLD U64 8[RDX]
FSUB ST0,U64 8[RBX]
FMUL ST0,ST0
FADDP ST1,ST0
FLD U64 16[RDX]
FSUB ST0,U64 16[RBX]
FMUL ST0,ST0
FADDP ST1,ST0
FSTP U64 SF_ARG1[RBP]
MOV RAX,U64 SF_ARG1[RBP]
POP RBP
RET1 16
//************************************
_D3_CROSS::
PUSH RBP
MOV RBP,RSP
MOV RAX,U64 SF_ARG1[RBP]
MOV RDX,U64 SF_ARG2[RBP]
MOV RBX,U64 SF_ARG3[RBP]
FLD U64 8[RDX]
FMUL ST0,U64 16[RBX]
FLD U64 16[RDX]
FMUL ST0,U64 8[RBX]
FSUBP ST1,ST0
FSTP U64 [RAX]
FLD U64 [RDX]
FMUL ST0,U64 16[RBX]
FLD U64 16[RDX]
FMUL ST0,U64 [RBX]
FSUBRP ST1,ST0
FSTP U64 8[RAX]
FLD U64 [RDX]
FMUL ST0,U64 8[RBX]
FLD U64 8[RDX]
FMUL ST0,U64 [RBX]
FSUBP ST1,ST0
FSTP U64 16[RAX]
POP RBP
RET1 24
//************************************
_D3_DOT::
PUSH RBP
MOV RBP,RSP
MOV RDX,U64 SF_ARG1[RBP]
MOV RBX,U64 SF_ARG2[RBP]
FLD U64 [RDX]
FMUL ST0,U64 [RBX]
FLD U64 8[RDX]
FMUL ST0,U64 8[RBX]
FADDP ST1,ST0
FLD U64 16[RDX]
FMUL ST0,U64 16[RBX]
FADDP ST1,ST0
FSTP U64 SF_ARG1[RBP]
MOV RAX,U64 SF_ARG1[RBP]
POP RBP
RET1 16
//************************************
_D3_ADD::
PUSH RBP
MOV RBP,RSP
MOV RAX,U64 SF_ARG1[RBP]
MOV RDX,U64 SF_ARG2[RBP]
MOV RBX,U64 SF_ARG3[RBP]
FLD U64 [RDX]
FADD ST0,U64 [RBX]
FSTP U64 [RAX]
FLD U64 8[RDX]
FADD ST0,U64 8[RBX]
FSTP U64 8[RAX]
FLD U64 16[RDX]
FADD ST0,U64 16[RBX]
FSTP U64 16[RAX]
POP RBP
RET1 24
//************************************
_D3_SUB::
PUSH RBP
MOV RBP,RSP
MOV RAX,U64 SF_ARG1[RBP]
MOV RDX,U64 SF_ARG2[RBP]
MOV RBX,U64 SF_ARG3[RBP]
FLD U64 [RDX]
FSUB ST0,U64 [RBX]
FSTP U64 [RAX]
FLD U64 8[RDX]
FSUB ST0,U64 8[RBX]
FSTP U64 8[RAX]
FLD U64 16[RDX]
FSUB ST0,U64 16[RBX]
FSTP U64 16[RAX]
POP RBP
RET1 24
//************************************
_D3_MUL::
PUSH RBP
MOV RBP,RSP
MOV RAX,U64 SF_ARG1[RBP]
MOV RBX,U64 SF_ARG3[RBP]
FLD U64 SF_ARG2[RBP]
FLD ST0
FMUL ST0,U64 [RBX]
FSTP U64 [RAX]
FLD ST0
FMUL ST0,U64 8[RBX]
FSTP U64 8[RAX]
FMUL ST0,U64 16[RBX]
FSTP U64 16[RAX]
POP RBP
RET1 24
//************************************
_D3_DIV::
PUSH RBP
MOV RBP,RSP
MOV RAX,U64 SF_ARG1[RBP]
MOV RBX,U64 SF_ARG2[RBP]
FLD U64 SF_ARG3[RBP]
FLD ST0
FDIVR ST0,U64 [RBX]
FSTP U64 [RAX]
FLD ST0
FDIVR ST0,U64 8[RBX]
FSTP U64 8[RAX]
FDIVR ST0,U64 16[RBX]
FSTP U64 16[RAX]
POP RBP
RET1 24
//************************************
_D3_ZERO::
PUSH RBP
MOV RBP,RSP
MOV RAX,U64 SF_ARG1[RBP]
XOR RDX,RDX
MOV U64 [RAX],RDX
MOV U64 8[RAX],RDX
MOV U64 16[RAX],RDX
POP RBP
RET1 8
//************************************
_D3_COPY::
PUSH RBP
MOV RBP,RSP
MOV RAX,U64 SF_ARG1[RBP]
MOV RBX,U64 SF_ARG2[RBP]
MOV RDX,U64 [RBX]
MOV U64 [RAX],RDX
MOV RDX,U64 8[RBX]
MOV U64 8[RAX],RDX
MOV RDX,U64 16[RBX]
MOV U64 16[RAX],RDX
POP RBP
RET1 16
//************************************
_D3_EQU::
PUSH RBP
MOV RBP,RSP
MOV RAX,U64 SF_ARG1[RBP]
MOV RDX,U64 SF_ARG2[RBP]
MOV U64 [RAX],RDX
MOV RDX,U64 SF_ARG3[RBP]
MOV U64 8[RAX],RDX
MOV RDX,U64 SF_ARG4[RBP]
MOV U64 16[RAX],RDX
POP RBP
RET1 32
//************************************
_D3_ADD_EQU::
PUSH RBP
MOV RBP,RSP
MOV RAX,U64 SF_ARG1[RBP]
MOV RBX,U64 SF_ARG2[RBP]
FLD U64 [RAX]
FADD ST0,U64 [RBX]
FSTP U64 [RAX]
FLD U64 8[RAX]
FADD ST0,U64 8[RBX]
FSTP U64 8[RAX]
FLD U64 16[RAX]
FADD ST0,U64 16[RBX]
FSTP U64 16[RAX]
POP RBP
RET1 16
//************************************
_D3_SUB_EQU::
PUSH RBP
MOV RBP,RSP
MOV RAX,U64 SF_ARG1[RBP]
MOV RBX,U64 SF_ARG2[RBP]
FLD U64 [RAX]
FSUB ST0,U64 [RBX]
FSTP U64 [RAX]
FLD U64 8[RAX]
FSUB ST0,U64 8[RBX]
FSTP U64 8[RAX]
FLD U64 16[RAX]
FSUB ST0,U64 16[RBX]
FSTP U64 16[RAX]
POP RBP
RET1 16
//************************************
_D3_MUL_EQU::
PUSH RBP
MOV RBP,RSP
MOV RAX,U64 SF_ARG1[RBP]
FLD U64 SF_ARG2[RBP]
FLD ST0
FMUL ST0,U64 [RAX]
FSTP U64 [RAX]
FLD ST0
FMUL ST0,U64 8[RAX]
FSTP U64 8[RAX]
FMUL ST0,U64 16[RAX]
FSTP U64 16[RAX]
POP RBP
RET1 16
//************************************
_D3_DIV_EQU::
PUSH RBP
MOV RBP,RSP
MOV RAX,U64 SF_ARG1[RBP]
FLD U64 SF_ARG2[RBP]
FLD ST0
FDIVR ST0,U64 [RAX]
FSTP U64 [RAX]
FLD ST0
FDIVR ST0,U64 8[RAX]
FSTP U64 8[RAX]
FDIVR ST0,U64 16[RAX]
FSTP U64 16[RAX]
POP RBP
RET1 16
//************************************
_D3_UNIT::
PUSH RBP
MOV RBP,RSP
MOV RAX,U64 SF_ARG1[RBP]
FLD U64 [RAX]
FMUL ST0,ST0
FLD U64 8[RAX]
FMUL ST0,ST0
FADDP ST1,ST0
FLD U64 16[RAX]
FMUL ST0,ST0
FADDP ST1,ST0
FSQRT
FST U64 SF_ARG1[RBP]
MOV RBX,SF_ARG1[RBP]
TEST RBX,RBX
JZ @@05
FLD ST0
FDIVR ST0,U64 [RAX]
FSTP U64 [RAX]
FLD ST0
FDIVR ST0,U64 8[RAX]
FSTP U64 8[RAX]
FDIVR ST0,U64 16[RAX]
FSTP U64 16[RAX]
POP RBP
RET1 8
@@05: FFREE ST0
FINCSTP
POP RBP
RET1 8
//************************************
_SQR::
PUSH RBP
MOV RBP,RSP
FLD U64 SF_ARG1[RBP]
FMUL ST0,ST0
FSTP U64 SF_ARG1[RBP]
MOV RAX,U64 SF_ARG1[RBP]
POP RBP
RET1 8
//************************************
_SIGN::
PUSH RBP
MOV RBP,RSP
FLD U64 SF_ARG1[RBP]
FTST
FSTSW
FFREE ST0
FINCSTP
MOV RDX,RAX
XOR RAX,RAX
BT RDX,14
JC @@05
MOV RAX,1.0
BT RDX,8
JNC @@05
MOV RAX,-1.0
@@05: POP RBP
RET1 8
//************************************
_ARG::
PUSH RBP
MOV RBP,RSP
FLD U64 SF_ARG2[RBP]
FLD U64 SF_ARG1[RBP]
@@05: FPATAN
FSTSW
TEST AX,0x400
JNZ @@05
FSTP U64 SF_ARG1[RBP]
MOV RAX,U64 SF_ARG1[RBP]
POP RBP
RET1 16
//************************************
_ROUND::
PUSH RBP
MOV RBP,RSP
SUB RSP,8
FSTCW U16 -8[RBP]
MOV AX,U16 -8[RBP]
MOV U16 -6[RBP],AX
AND AX,~0x0C00
MOV U16 -8[RBP],AX
FLDCW U16 -8[RBP]
FLD U64 SF_ARG1[RBP]
FRNDINT
FSTP U64 SF_ARG1[RBP]
MOV RAX,U64 SF_ARG1[RBP]
FLDCW U16 -6[RBP]
LEAVE
RET1 8
//************************************
_TRUNC::
PUSH RBP
MOV RBP,RSP
SUB RSP,8
FSTCW U16 -8[RBP]
MOV AX,U16 -8[RBP]
MOV U16 -6[RBP],AX
OR AX,0x0C00
MOV U16 -8[RBP],AX
FLDCW U16 -8[RBP]
FLD U64 SF_ARG1[RBP]
FRNDINT
FSTP U64 SF_ARG1[RBP]
MOV RAX,U64 SF_ARG1[RBP]
FLDCW U16 -6[RBP]
LEAVE
RET1 8
//************************************
_FLOOR::
PUSH RBP
MOV RBP,RSP
SUB RSP,8
FSTCW U16 -8[RBP]
MOV AX,U16 -8[RBP]
MOV U16 -6[RBP],AX
AND AX,~0x0C00
OR AX,0x0400
MOV U16 -8[RBP],AX
FLDCW U16 -8[RBP]
FLD U64 SF_ARG1[RBP]
FRNDINT
FSTP U64 SF_ARG1[RBP]
MOV RAX,U64 SF_ARG1[RBP]
FLDCW U16 -6[RBP]
LEAVE
RET1 8
//************************************
_CEIL::
PUSH RBP
MOV RBP,RSP
SUB RSP,8
FSTCW U16 -8[RBP]
MOV AX,U16 -8[RBP]
MOV U16 -6[RBP],AX
AND AX,~0x0C00
OR AX,0x0800
MOV U16 -8[RBP],AX
FLDCW U16 -8[RBP]
FLD U64 SF_ARG1[RBP]
FRNDINT
FSTP U64 SF_ARG1[RBP]
MOV RAX,SF_ARG1[RBP]
FLDCW U16 -6[RBP]
LEAVE
RET1 8
//************************************
SYS_POW::
// RAX=RDX`RAX
PUSH RBP
MOV RBP,RSP
SUB RSP,24
TEST RAX,RAX //To power of zero?
JNZ @@05
MOV RAX,1.0
JMP @@20
@@05: TEST RDX,RDX //zero to a power?
JNZ @@10
XOR RAX,RAX
JMP @@20
@@10: MOV RCX,RAX //RCX=pow
MOV U64 -8[RBP],RDX
MOV U64 -16[RBP],RAX
FSTCW U16 -24[RBP]
MOV AX,U16 -24[RBP]
MOV U16 -22[RBP],AX
OR AX,0x0C00
MOV U16 -24[RBP],AX
FLDCW U16 -24[RBP]
FLD U64 -16[RBP]
FLD U64 -8[RBP]
FABS //base should be pos
FYL2X // y*log2(x)
FST U64 -8[RBP]
FRNDINT
FLD U64 -8[RBP]
FSUBRP ST1,ST0
F2XM1
FLD1
FADDP ST1,ST0
FSTP U64 -16[RBP]
FLD U64 -8[RBP]
FLD U64 -16[RBP]
FSCALE // ST0<<ST1
TEST RDX,RDX //was base neg?
JGE @@15
MOV U64 -16[RBP],RCX
FLD U64 -16[RBP]
FISTTP U64 -16[RBP]
TEST U64 -16[RBP],1
JZ @@15 //was pow odd?
FCHS
@@15: FSTP U64 -8[RBP]
FFREE ST0
FINCSTP
FLDCW U16 -22[RBP]
MOV RAX,U64 -8[RBP]
@@20: LEAVE
RET
//************************************
_POW::
PUSH RBP
MOV RBP,RSP
MOV RAX,U64 SF_ARG2[RBP]
MOV RDX,U64 SF_ARG1[RBP]
CALL SYS_POW
POP RBP
RET1 16
//************************************
_POW10::
PUSH RBP
MOV RBP,RSP
SUB RSP,16
FSTCW U16 -8[RBP]
MOV AX,U16 -8[RBP]
MOV U16 -6[RBP],AX
OR AX,0x0C00
MOV U16 -8[RBP],AX
FLDCW U16 -8[RBP]
FLDL2T
FLD U64 SF_ARG1[RBP]
FMULP ST1,ST0
FST U64 SF_ARG1[RBP]
FRNDINT
FLD U64 SF_ARG1[RBP]
FSUBRP ST1,ST0
F2XM1
FLD1
FADDP ST1,ST0
FSTP U64 -16[RBP]
FLD U64 SF_ARG1[RBP]
FLD U64 -16[RBP]
FSCALE // ST0<<ST1
FSTP U64 -16[RBP]
FFREE ST0
FINCSTP
FLDCW U16 -6[RBP]
MOV RAX,U64 -16[RBP]
LEAVE
RET1 8
//************************************
_EXP::
PUSH RBP
MOV RBP,RSP
SUB RSP,16
FSTCW U16 -8[RBP]
MOV AX,U16 -8[RBP]
MOV U16 -6[RBP],AX
OR AX,0x0C00
MOV U16 -8[RBP],AX
FLDCW U16 -8[RBP]
FLDL2E
FLD U64 SF_ARG1[RBP]
FMULP ST1,ST0
FST U64 SF_ARG1[RBP]
FRNDINT
FLD U64 SF_ARG1[RBP]
FSUBRP ST1,ST0
F2XM1
FLD1
FADDP ST1,ST0
FSTP U64 -16[RBP]
FLD U64 SF_ARG1[RBP]
FLD U64 -16[RBP]
FSCALE // ST0<<ST1
FSTP U64 -16[RBP]
FFREE ST0
FINCSTP
FLDCW U16 -6[RBP]
MOV RAX,U64 -16[RBP]
LEAVE
RET1 8
//************************************
_LOG10::
PUSH RBP
MOV RBP,RSP
FLDLG2
FLD U64 SF_ARG1[RBP]
FYL2X // y*log2(x)
FSTP U64 SF_ARG1[RBP]
MOV RAX,U64 SF_ARG1[RBP]
POP RBP
RET1 8
//************************************
_LOG2::
PUSH RBP
MOV RBP,RSP
FLD1
FLD U64 SF_ARG1[RBP]
FYL2X // y*log2(x)
FSTP U64 SF_ARG1[RBP]
MOV RAX,U64 SF_ARG1[RBP]
POP RBP
RET1 8
//************************************
_LN::
PUSH RBP
MOV RBP,RSP
FLDLN2
FLD U64 SF_ARG1[RBP]
FYL2X // y*log2(x)
FSTP U64 SF_ARG1[RBP]
MOV RAX,U64 SF_ARG1[RBP]
POP RBP
RET1 8
//************************************
_FLDCW::
PUSH RBP
MOV RBP,RSP
FLDCW U16 SF_ARG1[RBP]
POP RBP
RET1 8
//************************************
_FSTCW::
PUSH RBP
MOV RBP,RSP
SUB RSP,8
FSTCW U16 -8[RBP]
MOVZX RAX,U16 -8[RBP]
LEAVE
RET
//************************************
_FSTSW::
XOR RAX,RAX
FSTSW
RET
//************************************
_FCLEX::
FCLEX
RET
}
+157
View File
@@ -0,0 +1,157 @@
F64 Clamp(F64 d,F64 lo,F64 hi)
{//Clamp to F64 [] range.
if (d<lo)
return lo;
if (d>hi)
return hi;
return d;
}
F64 Min(F64 n1,F64 n2)
{//Min of two F64s.
if (n1<=n2)
return n1;
else
return n2;
}
F64 Max(F64 n1,F64 n2)
{//Max of two F64s.
if (n1>=n2)
return n1;
else
return n2;
}
F64 Pow10I64(I64 i)
{//F64 int powers of ten.
if (i>308)
return ì;
else if (i<-308)
return 0.0;
else
return pow10_I64[i+309];
}
U64 FloorU64(U64 num,U64 to)
{//Int multiples of num.
return num-num%to;
}
U64 CeilU64(U64 num,U64 to)
{//Int multiples of num.
num+=to-1;
return num-num%to;
}
I64 RoundI64(I64 num,I64 to)
{//Int multiples of num.
return num-num%to;
}
I64 FloorI64(I64 num,I64 to)
{//Int multiples of num.
if (num>=0)
return num-num%to;
else {
num++;
return num-num%to-to;
}
}
I64 CeilI64(I64 num,I64 to)
{//Int multiples of num.
if (num>=0) {
num+=to-1;
return num-num%to;
} else {
num+=to-1;
return num-num%to-to;
}
}
//See $LK,"::/Doc/Credits.DD"$.
#define LIN_CONGRUE_A 6364136223846793005
#define LIN_CONGRUE_C 1442695040888963407
I16 RandI16()
{//Random I16.
I64 res=Fs->rand_seed;
res=LIN_CONGRUE_A*res^(res&0xFFFFFFFF0000)>>16+LIN_CONGRUE_C;
if (!Bt(&Fs->task_flags,TASKf_NONTIMER_RAND))
res^=GetTSC;
Fs->rand_seed=res;
return res.i16[0];
}
U16 RandU16()
{//Random U16.
I64 res=Fs->rand_seed;
res=LIN_CONGRUE_A*res^(res&0xFFFFFFFF0000)>>16+LIN_CONGRUE_C;
if (!Bt(&Fs->task_flags,TASKf_NONTIMER_RAND))
res^=GetTSC;
Fs->rand_seed=res;
return res.u16[0];
}
I32 RandI32()
{//Random I32.
I64 res=Fs->rand_seed;
res=LIN_CONGRUE_A*res^(res&0xFFFFFFFF0000)>>16+LIN_CONGRUE_C;
if (!Bt(&Fs->task_flags,TASKf_NONTIMER_RAND))
res^=GetTSC;
Fs->rand_seed=res;
return res.i32[0];
}
U32 RandU32()
{//Random U32.
I64 res=Fs->rand_seed;
res=LIN_CONGRUE_A*res^(res&0xFFFFFFFF0000)>>16+LIN_CONGRUE_C;
if (!Bt(&Fs->task_flags,TASKf_NONTIMER_RAND))
res^=GetTSC;
Fs->rand_seed=res;
return res.u32[0];
}
I64 RandI64()
{//Random I64.
I64 res=Fs->rand_seed;
res=LIN_CONGRUE_A*res^(res&0xFFFFFFFF0000)>>16+LIN_CONGRUE_C;
if (!Bt(&Fs->task_flags,TASKf_NONTIMER_RAND))
res^=GetTSC;
Fs->rand_seed=res;
return res;
}
U64 RandU64()
{//Random U64.
I64 res=Fs->rand_seed;
res=LIN_CONGRUE_A*res^(res&0xFFFFFFFF0000)>>16+LIN_CONGRUE_C;
if (!Bt(&Fs->task_flags,TASKf_NONTIMER_RAND))
res^=GetTSC;
Fs->rand_seed=res;
return res;
}
F64 Rand()
{//Random F64.
I64 res=Fs->rand_seed;
res=LIN_CONGRUE_A*res^(res&0xFFFFFFFF0000)>>16+LIN_CONGRUE_C;
if (!Bt(&Fs->task_flags,TASKf_NONTIMER_RAND))
res^=GetTSC;
Fs->rand_seed=res;
return (res&0x3FFFFFFFFFFFFFFF)/ToF64(0x4000000000000000);
}
I64 Seed(I64 seed=0,CTask *task=NULL)
{//Set $LK,"Rand",A="MN:Rand"$() seed. Zero for timer-based.
if (!task) task=Fs;
if (seed) {
LBts(&task->task_flags,TASKf_NONTIMER_RAND);
return task->rand_seed=seed;
} else {
LBtr(&task->task_flags,TASKf_NONTIMER_RAND);
return task->rand_seed^=GetTSC;
}
}
+307
View File
@@ -0,0 +1,307 @@
U0 PortNop()
{//Innoculous (reads IRQ Mask) which should take fixed time
//because it's an ISA-bus standard. It takes 1.0uS-2.0uS.
InU8(0x21);
}
U16 EndianU16(U16 d)
{//Swap big<-->little endian.
I64 res=0;
res.u8[1]=d.u8[0];
res.u8[0]=d.u8[1];
return res;
}
U32 EndianU32(U32 d)
{//Swap big<-->little endian.
I64 res=0;
res.u8[3]=d.u8[0];
res.u8[2]=d.u8[1];
res.u8[1]=d.u8[2];
res.u8[0]=d.u8[3];
return res;
}
I64 EndianI64(I64 d)
{//Swap big<-->little endian.
U64 res;
res.u8[7]=d.u8[0];
res.u8[6]=d.u8[1];
res.u8[5]=d.u8[2];
res.u8[4]=d.u8[3];
res.u8[3]=d.u8[4];
res.u8[2]=d.u8[5];
res.u8[1]=d.u8[6];
res.u8[0]=d.u8[7];
return res;
}
I64 BCnt(I64 d)
{//Count set bits in I64.
I64 res=0,i;
for (i=0;i<8;i++)
res+=set_bits_table[d.u8[i]];
return res;
}
U0 IntCore0TimerHndlr(CTask *)
{//Called from $LK,"IntCore0TimerHndlr",A="FF:::/Kernel/KInts.HC,IntCore0TimerHndlr"$
I64 i;
if (mp_cnt>1)
while (LBts(&sys_semas[SEMA_SYS_TIMER],0))
PAUSE
lock cnts.jiffies++;
cnts.timer+=SYS_TIMER0_PERIOD+1;
LBtr(&sys_semas[SEMA_SYS_TIMER],0);
for (i=1;i<mp_cnt;i++)
MPInt(I_TIMER,i);
OutU8(0x20,0x20); //Acknowledge PIC Interrupt
}
I64 SysTimerRead()
{//System timer count with overflow already handled.
I64 i,res;
PUSHFD
CLI
if (mp_cnt>1)
while (LBts(&sys_semas[SEMA_SYS_TIMER],0))
PAUSE
OutU8(0x43,0); //Latch Timer0
if ((i=InU8(0x40)+InU8(0x40)<<8)==SYS_TIMER0_PERIOD) {
if (InU8(0x20) & 1)
i=-1;
}
res=cnts.timer+SYS_TIMER0_PERIOD-i;
LBtr(&sys_semas[SEMA_SYS_TIMER],0);
POPFD
return res;
}
I64 HPET()
{ //Get high precision event timer.
return *(dev.uncached_alias+HPET_MAIN_CNT)(I64 *);
}
I64 TimeStampFreqCal()
{
static I64 time_stamp_start=0,timer_start=0,HPET_start=0;
I64 i;
if (time_stamp_start) {
PUSHFD
CLI
if (HPET_start) {
cnts.time_stamp_freq=cnts.HPET_freq*(GetTSC-time_stamp_start);
i=HPET-HPET_start;
} else {
cnts.time_stamp_freq=SYS_TIMER_FREQ*(GetTSC-time_stamp_start);
i=SysTimerRead-timer_start;
}
if (!i)
AdamErr("Timer Cal Error");
else {
cnts.time_stamp_freq/=i;
cnts.time_stamp_kHz_freq=cnts.time_stamp_freq/1000;
cnts.time_stamp_calibrated=TRUE;
}
POPFD
}
PUSHFD
CLI
if (cnts.HPET_freq) {
timer_start=0;
HPET_start=HPET;
} else {
timer_start=SysTimerRead;
HPET_start=0;
}
time_stamp_start=GetTSC;
POPFD
return cnts.time_stamp_freq;
}
F64 tS()
{//Time since boot in seconds as a float.
if (cnts.HPET_freq)
return ToF64(HPET-cnts.HPET_initial)/cnts.HPET_freq;
else
return SysTimerRead/ToF64(SYS_TIMER_FREQ);
}
Bool Blink(F64 Hz=2.5)
{//Return TRUE, then FALSE, then TRUE at given frequency.
if (!Hz) return 0;
return ToI64(cnts.jiffies*2*Hz/JIFFY_FREQ)&1;
}
U0 Busy(I64 æS)
{//Loosely timed.
I64 i;
if (cnts.HPET_freq) {
i=HPET+cnts.HPET_freq*æS/1000000;
while (HPET<i);
} else
for (i=0;i<æS;i++)
PortNop;
}
U0 SleepUntil(I64 wake_jiffy)
{//Not for power-saving. It is to make a program pause without hogging the CPU.
Bool old_idle=LBts(&Fs->task_flags,TASKf_IDLE);
Fs->wake_jiffy=wake_jiffy;
Yield;
LBEqu(&Fs->task_flags,TASKf_IDLE,old_idle);
}
U0 Sleep(I64 mS)
{//Not for power-saving. It is to make a program pause without hogging the CPU.
if (!mS)
Yield;
else
SleepUntil(cnts.jiffies+mS*JIFFY_FREQ/1000);
}
F64 Ona2Freq(I8 ona)
{//Ona to freq. Ona=60 is 440.0Hz.
if (ona==ONA_REST)
return 0;
else
return 440.0/32*2.0`(ona/12.0);
}
I8 Freq2Ona(F64 freq)
{//Freq to Ona. 440.0Hz is Ona=60.
if (freq>0)
return ClampI64(12*Log2(32.0/440.0*freq),ONA_REST+1,I8_MAX);
else
return ONA_REST;
}
U0 Snd(I8 ona=ONA_REST)
{//Play freq. Zero means off.
I64 period;
CSndData *d;
if (!Bt(&sys_semas[SEMA_MUTE],0) &&
!LBts(&sys_semas[SEMA_SND],0)) { //Mutex. Just throw-out if in use
if (ona<=ONA_REST) {
snd.ona=ona;
OutU8(0x61,InU8(0x61)&~3);
} else if (ona!=snd.ona) {
snd.ona=ona;
period=ClampI64(SYS_TIMER_FREQ/Ona2Freq(ona),1,U16_MAX);
OutU8(0x43,0xB6);
OutU8(0x42,period);
OutU8(0x42,period.u8[1]);
OutU8(0x61,3|InU8(0x61));
}
if (!IsDbgMode && snd.record) {
d=ACAlloc(sizeof(CSndData));
d->ona=ona;
d->time=tS;
QueIns(d,snd.record_head.last);
}
LBtr(&sys_semas[SEMA_SND],0);
}
}
U0 SndRst()
{//Fix stuck sound.
if (Bt(&sys_semas[SEMA_SND],0)) {
Sleep(1);
if (Bt(&sys_semas[SEMA_SND],0)) {
Sleep(1);
LBtr(&sys_semas[SEMA_SND],0);
}
}
Snd;
}
U0 Beep(I8 ona=62,Bool busy=FALSE)
{//Make beep at given ona freq.
Snd(ona);
if (busy)
Busy(500000);
else
Sleep(500);
Snd;
if (busy)
Busy(200000);
else
Sleep(200);
}
Bool Mute(Bool val)
{//Turn-off sound.
Bool res;
if (val) {
PUSHFD
CLI
Snd;
res=LBts(&sys_semas[SEMA_MUTE],0);
POPFD
} else
res=LBtr(&sys_semas[SEMA_MUTE],0);
return res;
}
Bool IsMute()
{//Return is-mute flag.
return Bt(&sys_semas[SEMA_MUTE],0);
}
Bool Silent(Bool val=ON)
{//Turn-off StdOut console text. (Not sound.)
return LBEqu(&Fs->display_flags,DISPLAYf_SILENT,val);
}
Bool IsSilent()
{//Return StdOut turned-off?
return Bt(&Fs->display_flags,DISPLAYf_SILENT);
}
Bool SysDbg(Bool val)
{//Set SysDbg bit you can use while debugging.
return LBEqu(&sys_semas[SEMA_DEBUG],0,val);
}
Bool IsSysDbg()
{//Return SysDbg bit.
return Bt(&sys_semas[SEMA_DEBUG],0);
}
Bool Raw(Bool val)
{//Set to direct scrn, BLACK & WHITE, non-windowed output mode.
if (!val)
VGAFlush;
return !LBEqu(&Fs->display_flags,DISPLAYf_NOT_RAW,!val);
}
Bool IsRaw()
{//Are we in BLACK & WHITE raw scrn mode?
return !Bt(&Fs->display_flags,DISPLAYf_NOT_RAW);
}
Bool SingleUser(Bool val)
{//Set single-user mode.
return LBEqu(&sys_semas[SEMA_SINGLE_USER],0,val);
}
Bool IsSingleUser()
{//Return single-user mode.
return Bt(&sys_semas[SEMA_SINGLE_USER],0);
}
Bool DbgMode(Bool val)
{//Set dbg-mode.
return LBEqu(&sys_semas[SEMA_DBG_MODE],0,val);
}
Bool IsDbgMode()
{//Return dbg-mode.
return Bt(&sys_semas[SEMA_DBG_MODE],0);
}
U0 ProgressBarsRst(U8 *path=NULL)
{//Reset all progress bars to zero.
CallExtStr("ProgressBarsRegTf",path);
MemSet(sys_progresses,0,sizeof(sys_progresses));
}
+206
View File
@@ -0,0 +1,206 @@
asm {/* See $LK,"::/Doc/Boot.DD"$.
TempleOS starts in real, calls some BIOS
routines, switches to 32 bit, and 64 bit mode
and continues in $LK,"HolyC",A="FI:::/Doc/HolyC.DD"$ at $LK,"KMain",A="MN:KMain"$().
The boot loader jumps here in real-mode (16-bit).
It actually jumps to the $LK,"CBinFile",A="MN:CBinFile"$ header which is
placed just before this by $LK,"the compiler",A="FF:::/Compiler/CMain.HC,16 ALIGN"$.
The header begins with a short jmp to
the start of this file's code which begins
with the following small jump past some data.
This file is first in the Kernel image
because it is #included first. $LK,"Kernel.PRJ",A="FF:::/Kernel/Kernel.PRJ,KStart16:1"$
*/
USE16
SYS_KERNEL:: //This must match $LK,"CKernel",A="MN:CKernel"$.
JMP I16 CORE0_16BIT_INIT
//************************************
// ASM Global vars required for 16-bit start-up
ALIGN 4,OC_NOP
SYS_BOOT_SRC:: DU32 BOOT_SRC_NULL;
SYS_BOOT_BLK:: DU32 0;
SYS_BOOT_PATCH_TABLE_BASE:: DU32 0;
SYS_RUN_LEVEL:: DU32 0;
#exe {StreamPrint("SYS_COMPILE_TIME:: DU64 0x%X;",Now);} //See $LK,"BootDVDProbe",A="MN:BootDVDProbe"$
#assert SYS_COMPILE_TIME+sizeof(CDate)+sizeof(CBinFile)<DVD_BLK_SIZE
MEM_BOOT_BASE:: DU32 0; //Offset from start used by reboot
MEM_E801:: DU16 0,0;
MEM_E820:: DU8 MEM_E820_ENTRIES_NUM*sizeof(CMemE820) DUP (0);
MEM_PHYSICAL_SPACE:: DU64 0;
SYS_GDT_PTR:: DU16 sizeof(CGDT)-1;
DU64 0;
SYS_PCI_BUSES:: DU16 0;
ALIGN 16,OC_NOP
SYS_GDT:: //See $LK,"CGDT",A="MN:CGDT"$
GDT_NULL: DU64 0,0;
GDT_BOOT_DS: DU64 0x00CF92000000FFFF,0; //Gets patched.
GDT_BOOT_CS: DU64 0x00CF9A000000FFFF,0; //Gets patched.
GDT_CS32: DU64 0x00CF9A000000FFFF,0;
GDT_CS64: DU64 0x00209A0000000000,0; //The $LK,"Charter",A="FI:::/Doc/Charter.DD"$ says just ring0.
GDT_CS64_RING3: DU64 0x0020FA0000000000,0; //$LK,"Ring3",A="FI:::/Demo/Lectures/Ring3.HC"$, so you can play with.
GDT_DS: DU64 0x00CF92000000FFFF,0;
GDT_DS_RING3: DU64 0x00CFF2000000FFFF,0;
GDT_TR: DU8 MP_PROCESSORS_NUM*16 DUP(0);
GDT_TR_RING3: DU8 MP_PROCESSORS_NUM*16 DUP(0);
#assert $$-SYS_GDT==sizeof(CGDT)
#assert $$-SYS_KERNEL==sizeof(CKernel)-sizeof(CBinFile)
//************************************
CORE0_16BIT_INIT::
//EAX is $LK,"SYS_BOOT_SRC",A="FF:::/Kernel/KStart16.HC,[SYS_BOOT_SRC]"$. (Val passed from boot blk, $LK,"BootHD",A="FF:::/Adam/Opt/Boot/BootHD.HC,BOOT_SRC_HARDDRV"$, $LK,"BootDVD",A="FF:::/Adam/Opt/Boot/BootDVD.HC,BOOT_SRC_DVD"$, & $LK,"BootRAM",A="FF:::/Adam/Opt/Boot/BootRAM.HC,BOOT_SRC_RAM"$.)
MOV ECX,EAX
MOV AX,(BOOT_RAM_LIMIT-BOOT_STK_SIZE)/16
MOV SS,AX
MOV SP,BOOT_STK_SIZE
PUSH ECX //Will be $LK,"SYS_BOOT_SRC",A="FF:::/Kernel/KStart16.HC,[SYS_BOOT_SRC]"$. See $LK,"BootHD",A="FF:::/Adam/Opt/Boot/BootHD.HC,BOOT_SRC_HARDDRV"$, $LK,"BootDVD",A="FF:::/Adam/Opt/Boot/BootDVD.HC,BOOT_SRC_DVD"$ & $LK,"BootRAM",A="FF:::/Adam/Opt/Boot/BootRAM.HC,BOOT_SRC_RAM"$.
PUSH EBX
CALL U16 GET_RIP
GET_RIP: POP BX
SUB BX,GET_RIP
SHR BX,4
MOV AX,CS
ADD AX,BX
PUSH AX
PUSH U16 @@05
RETF
@@05: STI
MOV AX,CS
MOV DS,AX
MOV U32 [SYS_RUN_LEVEL],RLF_16BIT
MOV AX,0x4F02
MOV BX,0x12 //640x480 16 color
#exe {
if (!kernel_cfg->opts[CFG_TEXT_MODE])
StreamPrint("INT 0x10"); //Enable VGA
};
CMP AX,0x004F
JNE @@10 //Jmp if fail
BTS U32 [SYS_RUN_LEVEL],RLf_VGA
@@10:
//Get mem maps.
MOV AX,0xE801
INT 0x15
MOV U16 [MEM_E801],CX
MOV U16 [MEM_E801+2],DX
MOV CX,MEM_E820_ENTRIES_NUM-1 //Leave one to terminate
XOR EBX,EBX
MOV AX,DS
MOV ES,AX
MOV DI,MEM_E820
@@15: PUSH CX
MOV EAX,0xE820
MOV ECX,sizeof(CMemE820)
MOV EDX,'PAMS'
INT 0x15
JC @@20
CMP EAX,'PAMS'
JNE @@20
TEST EBX,EBX
JZ @@20
ADD DI,sizeof(CMemE820)
POP CX
LOOP @@15
SUB SP,2
@@20: ADD SP,2
//Find how much space to map, start with E801 limit.
XOR EAX,EAX
MOV AX,[MEM_E801+2]
SHL EAX,16
ADD EAX,SYS_16MEG_AREA_LIMIT
XOR EDX,EDX
//Find max of E820 to set mapped space.
MOV SI,MEM_E820
@@25: MOV CL,CMemE820.type[SI]
TEST CL,CL
JZ @@35
MOV EBX,CMemE820.base[SI]
MOV ECX,CMemE820.base+4[SI]
ADD EBX,CMemE820.len[SI]
ADC ECX,CMemE820.len+4[SI]
SUB EBX,EAX
SBB ECX,EDX
JC @@30
MOV EAX,CMemE820.base[SI]
MOV EDX,CMemE820.base+4[SI]
ADD EAX,CMemE820.len[SI]
ADC EDX,CMemE820.len+4[SI]
@@30: ADD SI,sizeof(CMemE820)
JMP @@25
@@35: MOV [MEM_PHYSICAL_SPACE],EAX
MOV [MEM_PHYSICAL_SPACE+4],EDX
//Get PCI Bus Info
MOV U16 [SYS_PCI_BUSES],256
XOR DX,DX
MOV AX,0xB101
INT 0x1A
CMP DX,'PC'
JNE @@40
MOV CH,0
INC CX
MOV U16 [SYS_PCI_BUSES],CX
@@40:
CLI
//Enable A20
IN AL,0x92
OR AL,2
OUT 0x92,AL
POP U32 [SYS_BOOT_BLK]
POP U32 [SYS_BOOT_SRC] //See $LK,"BootHD",A="FF:::/Adam/Opt/Boot/BootHD.HC,BOOT_SRC_HARDDRV"$, $LK,"BootDVD",A="FF:::/Adam/Opt/Boot/BootDVD.HC,BOOT_SRC_DVD"$, & $LK,"BootRAM",A="FF:::/Adam/Opt/Boot/BootRAM.HC,BOOT_SRC_RAM"$.
CLD
XOR EAX,EAX
MOV AX,CS
MOV DS,AX
MOV ES,AX
SHL EAX,4
MOV U32 [MEM_BOOT_BASE],EAX
MOV DX,CS
SUB DX,sizeof(CBinFile)/16
#assert !(sizeof(CBinFile)&15)
MOV GS,DX
MOV EDX,EAX
ADD EDX,U32 GS:[CBinFile.patch_table_offset]
SUB EDX,sizeof(CBinFile)
MOV U32 [SYS_BOOT_PATCH_TABLE_BASE],EDX
ADD U32 [GDT_BOOT_DS+2],EAX
ADD U32 [GDT_BOOT_CS+2],EAX
ADD EAX,I32 SYS_GDT
MOV U32 [SYS_GDT_PTR+CSysLimitBase.base],EAX
LGDT U32 [SYS_GDT_PTR]
MOV EAX,SYS_START_CR0
MOV_CR0_EAX
/* The assembler doesn't support far jumps so
we hand code it. 16-bit code is not important
enough to fully implement in the assembler.
To complete the switch to 32-bit mode, we have to load
the code segment with a far jump.
*/
DU8 0x66,0xEA; //JMP CGDT.boot_cs:CORE0_32BIT_INIT
DU32 CORE0_32BIT_INIT;
DU16 CGDT.boot_cs;
#assert $$+16<=0xFFFF
}
+117
View File
@@ -0,0 +1,117 @@
asm {
USE32
//************************************
// ASM Global vars not required for 16-bit start-up
ALIGN 8,OC_NOP
MEM_HEAP_BASE:: DU64 0;
MEM_HEAP_LIMIT:: DU64 0;
MEM_PAGE_SIZE:: DU64 0;
MEM_MAPPED_SPACE:: DU64 0;
MEM_2MEG_NUM:: DU64 0;
MEM_1GIG_NUM:: DU64 0;
MEM_512GIG_NUM:: DU64 0;
MEM_PML2:: DU64 0;
MEM_PML3:: DU64 0;
MEM_PML4:: DU64 0;
#exe {
StreamPrint(
"SYS_MEM_INIT_FLAG:: DU8 %d;"
"SYS_MEM_INIT_VAL:: DU8 %d;"
"SYS_HEAP_INIT_FLAG:: DU8 %d;"
"SYS_HEAP_INIT_VAL:: DU8 %d;"
"SYS_VAR_INIT_FLAG:: DU8 %d;"
"SYS_VAR_INIT_VAL:: DU8 %d;"
"SYS_STAFF_MODE_FLAG:: DU8 %d;",
kernel_cfg->opts[CFG_MEM_INIT], kernel_cfg->mem_init_val,
kernel_cfg->opts[CFG_HEAP_INIT],kernel_cfg->heap_init_val,
kernel_cfg->opts[CFG_VAR_INIT], kernel_cfg->var_init_val,
kernel_cfg->opts[CFG_STAFF_MODE]);
};
SYS_HEAP_DBG_FLAG:: DU8 _CFG_HEAP_DBG;
ALIGN 8,0
SYS_CTRL_ALT_FLAGS:: DU64 0;
SYS_EXTERN_TABLE:: DU64 0;
SYS_CODE_BP:: DU64 0;
SYS_DATA_BP:: DU64 0;
SYS_PROGRESSES::
SYS_PROGRESS1:: DU64 0;
SYS_PROGRESS1_MAX:: DU64 0;
SYS_PROGRESS1_T0:: DU64 0;
SYS_PROGRESS1_TF:: DU64 0;
SYS_PROGRESS1_DESC:: DU8 PROGRESS_DESC_LEN DUP(0);
SYS_PROGRESS2:: DU64 0;
SYS_PROGRESS2_MAX:: DU64 0;
SYS_PROGRESS2_T0:: DU64 0;
SYS_PROGRESS2_TF:: DU64 0;
SYS_PROGRESS2_DESC:: DU8 PROGRESS_DESC_LEN DUP(0);
SYS_PROGRESS3:: DU64 0;
SYS_PROGRESS3_MAX:: DU64 0;
SYS_PROGRESS3_T0:: DU64 0;
SYS_PROGRESS3_TF:: DU64 0;
SYS_PROGRESS3_DESC:: DU8 PROGRESS_DESC_LEN DUP(0);
SYS_PROGRESS4:: DU64 0;
SYS_PROGRESS4_MAX:: DU64 0;
SYS_PROGRESS4_T0:: DU64 0;
SYS_PROGRESS4_TF:: DU64 0;
SYS_PROGRESS4_DESC:: DU8 PROGRESS_DESC_LEN DUP(0);
#assert $$-SYS_PROGRESSES==sizeof(CProgress)*4
SYS_FOCUS_TASK:: DU64 0;
SYS_CPU_STRUCTS:: DU64 0;
SYS_MP_CNT:: DU64 1;
SYS_MP_CNT_INITIAL:: DU64 1;
SYS_MP_CNT_LOCK:: DU64 1;
ALIGN DFT_CACHE_LINE_WIDTH,OC_NOP
SYS_CACHE_LINE_WIDTH:: DU64 DFT_CACHE_LINE_WIDTH;
DU8 DFT_CACHE_LINE_WIDTH-sizeof(CBinFile)-8 DUP(0);
SYS_SEMAS:: DU8 SEMA_SEMAS_NUM*DFT_CACHE_LINE_WIDTH DUP(0);
//************************************
ALIGN 16,OC_NOP
CORE0_32BIT_INIT:: //Entry point for $LK,"BootRAM",A="MN:BootRAM"$.
PUSH U32 RFLAGG_START
POPFD
MOV EAX,SYS_START_CR0
MOV_CR0_EAX
MOV AX,CGDT.boot_ds //LOAD DS SELECTOR
MOV DS,AX
BTS U32 [SYS_RUN_LEVEL],RLf_32BIT
MOV ESI,U32 [SYS_BOOT_PATCH_TABLE_BASE]
MOV EDI,U32 [MEM_BOOT_BASE]
MOV AX,CGDT.ds
MOV DS,AX
MOV ES,AX
MOV FS,AX
MOV GS,AX
MOV SS,AX
MOV ESP,BOOT_RAM_LIMIT //Tmp Stk
//Patch abs addresses
MOV ECX,U32 CPatchTableAbsAddr.abs_addres_cnt[ESI]
LEA ESI,U32 CPatchTableAbsAddr.abs_addres[ESI]
@@05: LODSD
ADD EAX,EDI
ADD U32 [EAX],EDI
LOOP @@05
DU8 0xEA; //JMP CGDT.cs32:@@10
DU32 @@10;
DU16 CGDT.cs32;
@@10: BTS U32 [SYS_RUN_LEVEL],RLf_PATCHED
CALL SYS_FIND_PCIBIOS_SERVICE_DIR
CALL SYS_FIND_PCI_SERVICES
CALL SYS_INIT_PAGE_TABLES
CALL SYS_INIT_16MEG_SYS_CODE_BP
PUSH U32 0 //Return from next call will be 64-bit
CALL SYS_ENTER_LONG_MODE
//We fall-thou to $LK,"KStart64",A="FL:::/Kernel/KStart64.HC,1"$, next.
}
+100
View File
@@ -0,0 +1,100 @@
asm {
USE64
BTS U32 [SYS_RUN_LEVEL],RLf_64BIT
FNINIT
MOV RAX,SYS_FIXED_AREA+CSysFixedArea.init_fpu_mmx
FXSAVE U64 [RAX]
//Init CPU0 Struct
PUSH SYS_FIXED_AREA+CSysFixedArea.adam
PUSH SYS_FIXED_AREA+CSysFixedArea.boot_cpu
PUSH 0
CALL &CPUStructInit
CALL SET_GS_BASE
//Init Adam HeapCtrl
MOV EDI,U32 SYS_FIXED_AREA+CSysFixedArea.adam_hc
MOV EAX,U32 SYS_FIXED_AREA+CSysFixedArea.sys_code_bp
MOV U64 CHeapCtrl.bp[RDI],RAX
MOV U32 CHeapCtrl.hc_signature[RDI],HEAP_CTRL_SIGNATURE_VAL
LEA RAX,U64 CHeapCtrl.next_um-CMemUsed.next[RDI]
MOV U64 CHeapCtrl.next_um[RDI],RAX
MOV U64 CHeapCtrl.last_um[RDI],RAX
MOV EAX,U32 SYS_FIXED_AREA+CSysFixedArea.adam
MOV U64 CHeapCtrl.mem_task[RDI],RAX
MOV U64 CTask.code_heap[RAX],RDI
MOV U64 CTask.data_heap[RAX],RDI
MOV U32 CTask.task_signature[RAX],TASK_SIGNATURE_VAL
BTS U32 [SYS_RUN_LEVEL],RLf_16MEG_ADAM_HEAP_CTRL
PUSH MEM_ADAM_STK
PUSH U32 SYS_FIXED_AREA+CSysFixedArea.adam
CALL &TaskInit
CALL SET_FS_BASE
MOV RSP,U64 CTask.rsp[RAX]
JMP I32 &KMain
//************************************
USE32
SYS_ENTER_LONG_MODE:: //Switch to long 64-bit mode
MOV_EAX_CR4
OR EAX,0xB0
MOV_CR4_EAX
MOV EAX,[MEM_PML4]
MOV_CR3_EAX
MOV ECX,IA32_EFER
XOR EDX,EDX
MOV EAX,IA32F_LME
WRMSR
MOV_EAX_CR0
BTS EAX,31 //Enable paging (required for 64-bit mode)
MOV_CR0_EAX
DU8 0xEA; //JMP CGDT.cs64:@@05
DU32 @@05;
DU16 CGDT.cs64;
USE64
@@05: MOV AX,CGDT.ds
MOV DS,AX
MOV ES,AX
MOV SS,AX
MOV FS,AX
MOV GS,AX
RET
//************************************
SYS_RAM_REBOOT:: //This gets copied high. $LK,"SYS_RAM_REBOOT",A="FF:::/Adam/Opt/Boot/BootRAM.HC,SYS_RAM_REBOOT:2"$
PUSH U32 CGDT.ds //stk seg
PUSH U32 BOOT_RAM_LIMIT //stk
PUSH U32 0 //flags
PUSH U32 CGDT.cs32
LEA RAX,[@@10]
PUSH RAX
IRET
USE32
@@10: WBINVD
//Disable paging
MOV_EAX_CR0
BTR EAX,31
MOV_CR0_EAX
MOV ECX,IA32_EFER
XOR EDX,EDX
XOR EAX,EAX
WRMSR
MOV EBX,BOOT_SRC_RAM
MOV EAX,I32 CORE0_32BIT_INIT
JMP EAX
SYS_RAM_REBOOT_END::
USE64
}
+545
View File
@@ -0,0 +1,545 @@
U0 Exit()
{//Terminate own task.
if (Fs==sys_focus_task && IsDbgMode) {
LBts(&Fs->task_flags,TASKf_KILL_AFTER_DBG);
G;
} else {
if (sys_staff_mode_flag)
AdamLog("%p:%p:%p:%p:%p:%p\n",Caller(0),Caller(1),Caller(2),Caller(3),
Caller(4),Caller(5),Caller(6),Caller(7));
if (!Gs->num && !IsDbgMode)
SingleUser(OFF);
Fs->rflags=GetRFlags;
Fs->rsp=GetRSP;
Fs->rbp=GetRBP;
Fs->rip=$$;
CLI
LBts(&Fs->task_flags,TASKf_KILL_TASK);
TaskEndNow;
}
}
Bool TaskValidate(CTask *task)
{//return TRUE if task looks valid.
if (!(0<task<=I32_MAX) || task->addr!=task ||
task->task_signature!=TASK_SIGNATURE_VAL)
return FALSE;
else
return TRUE;
}
I64 BirthWait(CTask **_task,I64 task_num=-1)
{//Wait for task valid and not task_num.
while (!TaskValidate(*_task)||(*_task)->task_num==task_num)
Yield;
return (*_task)->task_num;
}
U0 DeathWait(CTask **_task,Bool send_exit=FALSE)
{//Wait for task death.
if (send_exit && TaskValidate(*_task)) {
TaskWait(*_task,TRUE);
XTalk(*_task,"Exit;\n");
}
while (TaskValidate(*_task))
Yield;
}
Bool Kill(CTask *task,Bool wait=TRUE,Bool just_break=FALSE)
{//Terminate other task.
I64 i;
if (TaskValidate(task)) {
if (just_break) {
if (task!=Fs)
Break;
else {//TODO wait
sys_focus_task=task;
LBts(sys_ctrl_alt_flags,CTRL_ALT_C);
return TRUE;
}
} else {
if (task!=sys_winmgr_task) {
for (i=0;i<mp_cnt;i++)
if (task==cpu_structs[i].seth_task)
return FALSE;
LBts(&task->task_flags,TASKf_KILL_TASK);
if (wait) {
do Yield;
while (TaskValidate(task) && Bt(&task->task_flags,TASKf_KILL_TASK));
}
return TRUE;
}
}
}
return FALSE;
}
Bool Suspend(CTask *task=NULL,Bool state=TRUE)
{//Tell scheduler to skip task.
Bool res;
if (!task) task=Fs;
PUSHFD
CLI
if (TaskValidate(task))
res=LBEqu(&task->task_flags,TASKf_SUSPENDED,state);
else
res=FALSE;
POPFD
return res;
}
Bool IsSuspended(CTask *task=NULL)
{//You might use this in a DrawIt() or Animatetask().
if (!task) task=Fs;
if (TaskValidate(task))
return Bt(&task->task_flags,TASKf_SUSPENDED);
else
return FALSE;
}
CTaskStk *TaskStkNew(I64 stk_size,CTask *task)
{
CTaskStk *tmps=MAlloc(stk_size+offset(CTaskStk.stk_base),task);
tmps->next_stk=NULL;
tmps->stk_ptr=NULL;
tmps->stk_size=MSize(tmps)-offset(CTaskStk.stk_base);
return tmps;
}
#exe {Option(OPTf_NO_REG_VAR,ON);};
argpop I64 CallStkGrow(I64 stk_size_threshold,I64 stk_size,
/*argpop*/I64 (*fp_addr)(...),...)
{//Grow stk in call with any fixed num of args.
//See $LK,"::/Demo/StkGrow.HC"$.
CTaskStk *tmps,*tmps2,**_stk;
I64 res,*rsp,*rsp2,*old_stk;
if (UnusedStk>=stk_size_threshold) {
asm {
LEAVE
POP RAX //return addr
ADD RSP,16 //pop threshold,stk_size
POP RBX // *f
ADD RSP,8 //pop ARGC
PUSH RAX
JMP RBX //CALL fp_addr()
};
} else {
tmps2=TaskStkNew(stk_size,Fs);
tmps2->next_stk=tmps=Fs->stk;
rsp2=(&tmps2->stk_base)(U8 *)+tmps2->stk_size;
old_stk=rsp=&argv[argc];
while (argc-->0)
*--rsp2=*--rsp;
_stk=&Fs->stk;
tmps->stk_ptr=rsp=GetRSP;
asm {
IMPORT _FREE; //We are in a function, not at glbl scope.
//The compiler treats these in isolation.
PUSHFD
POP RDX //flags
CLI
MOV RBX,U64 &tmps2[RBP]
MOV RAX,&_stk[RBP]
MOV U64 [RAX],RBX //Fs->stk=tmps2
MOV RSP,U64 &rsp2[RBP]
PUSH RDX
POPFD
CALL U64 &fp_addr[RBP]
MOV U64 &res[RBP],RAX
PUSHFD
POP RDX //flags
CLI
MOV RBX,U64 &tmps[RBP]
MOV RAX,&_stk[RBP]
MOV U64 [RAX],RBX //Fs->stk=tmps
MOV RSP,U64 &rsp[RBP]
PUSH RDX
POPFD
PUSH U64 &tmps2[RBP]
CALL _FREE
MOV RDX,U64 &old_stk[RBP]
MOV RBX,U64 8[RBP]
MOV RAX,U64 &res[RBP]
MOV RBP,U64 [RBP]
MOV RSP,RDX
JMP RBX //return
};
}
return 0; //dummy to get rid of warning
}
;
#exe {Option(OPTf_NO_REG_VAR,OFF);};
I64 TaskInit(CTask *task,I64 stk_size)
{//Returns Fs of task
CTaskStk *tmps;
QueInit(&task->code_heap->next_mem_blk);
task->code_heap->last_mergable=NULL;
if (task->code_heap!=task->data_heap) {
QueInit(&task->data_heap->next_mem_blk);
task->data_heap->last_mergable=NULL;
}
task->addr=task->next_task=task->last_task=
task->next_input_filter_task=task->last_input_filter_task=
task;
task->task_num=sys_num_spawned_tasks++;
task->rflags=RFLAGG_NORMAL;
task->win_inhibit=WIG_TASK_DFT;
task->next_child_task=task->last_child_task=
(&task->next_child_task)(U8 *)-offset(CTask.next_sibling_task);
JobCtrlInit(&task->srv_ctrl);
QueInit(&task->next_cc);
QueInit(&task->next_except);
QueInit(&task->next_ctrl);
QueInit(&task->next_ode);
task->fpu_mmx=MAllocAligned(sizeof(CFPU),0x10,task);
MemCpy(task->fpu_mmx,
SYS_FIXED_AREA+offset(CSysFixedArea.init_fpu_mmx),sizeof(CFPU));
task->hash_table=HashTableNew(TASK_HASH_TABLE_SIZE,task);
if (!stk_size)
stk_size=MEM_DFT_STK;
task->stk=tmps=TaskStkNew(stk_size,task);
task->rsp=(&tmps->stk_base)(U8 *)+tmps->stk_size;
task->text_attr =WHITE<<4+BLUE;
task->border_src =BDS_CONST;
task->border_attr =DrvTextAttrGet(':');
task->title_src =TTS_CONST;
task->win_left =1;
task->win_right =text.cols-2;
task->win_top =13;
task->win_bottom =text.rows-2;
if (blkdev.home_dir) {//Beware Adam $LK,"TaskInit",A="FF:::/Kernel/KStart64.HC,TaskInit"$. I guess ok until $LK,"ChgDsk",A="FF:::/Kernel/KEnd.HC,ChgDsk"$().
task->cur_dv=blkdev.let_to_drv[*blkdev.home_dir-'A'];
task->cur_dir=StrNew(blkdev.home_dir+2,task);
} else
task->cur_dir=StrNew("/Home",task);
Seed(,task);
return task;
}
CTask *Spawn(U0 (*fp_start_addr)(U8 *data),U8 *data=NULL,U8 *task_name=NULL,
I64 target_cpu=-1, //-1 for current CPU. See $LK,"multi-core",A="FI:::/Demo/MultiCore/LoadTest.HC"$.
CTask *parent=NULL, //NULL means adam
I64 stk_size=0, //0=default
I64 flags=1<<JOBf_ADD_TO_QUE)
{//Create task on core running at address.
//Alloc $LK,"CTask",A="MN:CTask"$ structure from code heap so addr will be short.
//Could be alloced off of data heap.
CTask *task;
if (target_cpu>=0)
return SpawnQue(fp_start_addr,data,task_name,target_cpu,
parent,stk_size,flags);
task=CAlloc(sizeof(CTask),adam_task->code_heap);
task->task_signature=TASK_SIGNATURE_VAL;
if (!task_name) task_name="Unnamed Task";
if (!parent) parent=Gs->seth_task;
task->parent_task=parent;
task->gs=parent->gs;
if (sys_code_bp)
task->code_heap=HeapCtrlInit(,task,sys_code_bp);
if (sys_data_bp)
task->data_heap=HeapCtrlInit(,task,sys_data_bp);
else
task->data_heap=task->code_heap;
TaskInit(task,stk_size);
task->rip=fp_start_addr;
task->rsp(U8 *)-=8;
*task->rsp=data;
task->rsp(U8 *)-=8;
*task->rsp=&Exit;
task->hash_table->next=parent->hash_table;
MemCpy(task->task_name,task_name,TASK_NAME_LEN);
StrCpy(task->task_title,task->task_name);
task->title_src=TTS_TASK_NAME;
PUSHFD
CLI
if (Bt(&flags,JOBf_ADD_TO_QUE)) {
TaskQueInsChild(task);
TaskQueIns(task);
}
POPFD
return task;
}
U0 TaskDerivedValsUpdate(CTask *task=NULL,Bool update_z_buf=TRUE)
{//Those things calculated from other variables.
if (!task) task=Fs;
PUSHFD
CLI
while (LBts(&task->task_flags,TASKf_TASK_LOCK))
PAUSE
WinDerivedValsUpdate(task);
if (fp_update_ctrls)
(*fp_update_ctrls)(task);
if (update_z_buf && Bt(&task->display_flags,DISPLAYf_SHOW))
LBts(&sys_semas[SEMA_UPDATE_WIN_Z_BUF],0);
LBtr(&task->task_flags,TASKf_TASK_LOCK);
POPFD
}
I64 ExeCmdLine(CCmpCtrl *cc)
{//Terminal JIT-compile-and-execute loop for CCmpCtrl.
I64 res=0,type,old_title_src=Fs->title_src;
U8 *ptr,*ptr2,*ptr3,*machine_code,*old_task_title=StrNew(Fs->task_title);
F64 t0;
CDocEntry *doc_e;
CDoc *doc;
if (Fs->title_src!=TTS_LOCKED_CONST)
Fs->title_src=TTS_CUR_LEX;
while (cc->token &&
(cc->token!='}' || !(cc->flags & CCF_EXE_BLK)) ) {
if (Fs->title_src==TTS_CUR_LEX) {
ptr2=&Fs->task_title;
ptr3=ptr2+STR_LEN-1;
if (cc->lex_include_stk->flags & LFSF_DOC) {
doc_e=cc->lex_include_stk->cur_entry;
doc=cc->lex_include_stk->doc;
while (doc_e!=doc && ptr2<ptr3) {
switch (doc_e->type_u8) {
case DOCT_TEXT:
ptr=doc_e->tag;
while (*ptr && ptr2<ptr3)
*ptr2++=*ptr++;
break;
case DOCT_TAB:
case DOCT_NEW_LINE:
*ptr2++='.';
break;
}
doc_e=doc_e->next;
}
if (ptr2<ptr3) *ptr2=0;
} else
if ((ptr=cc->lex_include_stk->line_start) && *ptr)
MemCpy(ptr2,ptr,STR_LEN-1);
}
cc->flags&=~CCF_HAS_MISC_DATA;
machine_code=LexStmt2Bin(cc,&type);
if (machine_code!=INVALID_PTR) {
if (!(cc->flags&CCF_JUST_LOAD)) {
t0=tS;
res=Call(machine_code);
Fs->answer=res;
Fs->answer_type=type;
Fs->answer_time=tS-t0;
Fs->new_answer=TRUE;
cc->pmt_line=0;
}
if (!(cc->flags&CCF_HAS_MISC_DATA))
Free(machine_code);
}
}
if (Fs->title_src!=TTS_LOCKED_CONST) {
Fs->title_src=old_title_src;
StrCpy(Fs->task_title,old_task_title);
}
Free(old_task_title);
if (cc->flags&CCF_JUST_LOAD) {
if (cc->error_cnt)
return FALSE;
else
return TRUE;
} else
return res;
}
U0 SrvTaskCont()
{//Act as server task in a loop handling commands.
I64 old_flags=GetRFlags;
FlushMsgs;
while (TRUE) {
CLI
if (JobsHndlr(old_flags) && Fs->title_src==TTS_TASK_NAME)
MemCpy(Fs->task_title,Fs->task_name,TASK_NAME_LEN);
FlushMsgs;
LBts(&Fs->task_flags,TASKf_IDLE);
LBts(&Fs->task_flags,TASKf_AWAITING_MSG);
Yield;
SetRFlags(old_flags);
}
}
U0 UserTaskCont()
{//Terminal key-input-execute loop.
CCmpCtrl *cc;
CDoc *doc;
Bool cont=TRUE;
do {
cc=CmpCtrlNew(,CCF_CMD_LINE|CCF_PMT|CCF_QUESTION_HELP);
QueIns(cc,Fs->last_cc);
try {
Lex(cc);
ExeCmdLine(cc);
cont=Bt(&cc->flags,CCf_PMT);
QueRem(cc);
CmpCtrlDel(cc);
} catch {
if ((doc=Fs->put_doc) && doc->doc_signature==DOC_SIGNATURE_VAL)
DocUnlock(doc);
PutExcept;
}
} while (cont);
}
U0 SrvCmdLine(I64 dummy=0)
{
no_warn dummy;
Fs->win_inhibit=WIG_USER_TASK_DFT;
CallExtStr("SrvStartUp");
SrvTaskCont;
}
U0 UserCmdLine(I64 dummy=0)
{//A user task ends-up calling this.
no_warn dummy;
Fs->win_inhibit=WIG_USER_TASK_DFT;
CallExtStr("UserStartUp");
if (!LBts(&Fs->display_flags,DISPLAYf_SHOW))
Dbg;
UserTaskCont;
}
CTask *User(U8 *fmt=NULL,...)
{//Create user term task.
U8 *st;
CTask *task=Spawn(&UserCmdLine);
TaskWait(task);
if (fmt) {
st=StrPrintJoin(NULL,fmt,argc,argv);
XTalk(task,st);
Free(st);
}
return task;
}
U0 TaskDel(CTask *task)
{//We delay freeing in case lingering ptr to reincarnated.
HeapCtrlDel(task->code_heap);
if (task->data_heap!=task->code_heap)
HeapCtrlDel(task->data_heap);
Free(task);
}
I64 TaskEnd()
{//Called with irq's off.
CTask *task=Fs,*tmpt,*tmpt1;
if (task==sys_task_being_scrn_updated) {
LBts(&task->task_flags,TASKf_KILL_TASK);
return task->next_task;
}
if (task->task_end_cb) {
task->wake_jiffy=0;
LBtr(&task->task_flags,TASKf_KILL_TASK);
TaskRstAwaitingMsg(task);
Suspend(task,FALSE);
task->rip=task->task_end_cb;
task->task_end_cb=NULL;
return task;
}
if (task->parent_task && task->parent_task->popup_task==task) {
task->parent_task->popup_task=NULL;
Kill(task->parent_task,FALSE);
return task->parent_task;
}
DrvsRelease;
BlkDevsRelease;
tmpt1=(&task->next_child_task)(U8 *)-offset(CTask.next_sibling_task);
tmpt=tmpt1->next_sibling_task;
if (tmpt!=tmpt1) {
do {
LBts(&tmpt->task_flags,TASKf_KILL_TASK);
tmpt=tmpt->next_sibling_task;
} while (tmpt!=tmpt1);
return task->next_task;
}
if (LBtr(&task->display_flags,DISPLAYf_SHOW))
LBts(&sys_semas[SEMA_UPDATE_WIN_Z_BUF],0);
while (LBts(&task->task_flags,TASKf_TASK_LOCK))
PAUSE
while (LBts(&task->srv_ctrl.flags,JOBCf_LOCKED))
PAUSE
JobQueDel(&task->srv_ctrl.next_waiting);
JobQueDel(&task->srv_ctrl.next_done);
if (IsRaw)
VGAFlush;
if (sys_focus_task==task) {
if (!Gs->num)
SingleUser(OFF);
sys_focus_task=NULL;
if (fp_set_std_palette)
(*fp_set_std_palette)();
}
//QueRem
task->task_signature(I64)=0;
tmpt =task->next_input_filter_task;
tmpt1=task->last_input_filter_task;
tmpt1->next_input_filter_task=tmpt;
tmpt ->last_input_filter_task=tmpt1;
tmpt =task->next_sibling_task;
tmpt1=task->last_sibling_task;
tmpt1->next_sibling_task=tmpt;
tmpt ->last_sibling_task=tmpt1;
tmpt =task->next_task; //save to return
TaskQueRem(task);
LBtr(&task->srv_ctrl.flags,JOBCf_LOCKED);
LBtr(&task->task_flags,TASKf_TASK_LOCK);
task->wake_jiffy=cnts.jiffies+DYING_JIFFIES;
while (LBts(&Gs->cpu_flags,CPUf_DYING_TASK_QUE))
PAUSE
QueIns(task,Gs->last_dying);
LBtr(&Gs->cpu_flags,CPUf_DYING_TASK_QUE);
return tmpt;
}
U0 TaskKillDying()
{//Delay freeing to prevent asking for trouble with quick reincarnations.
//What if the user is doing this: $LK,"DoTreeCheckers",A="FF:::/Misc/OSTestSuite.HC,DoTreeCheckers"$.
CTaskDying *task,*task1;
if (Gs->kill_jiffy<cnts.jiffies) {//Avoid doing as many lock operations.
while (LBts(&Gs->cpu_flags,CPUf_DYING_TASK_QUE))
PAUSE
task=Gs->next_dying;
while (task!=&Gs->next_dying && task->wake_jiffy<cnts.jiffies) {
task1=task->next;
QueRem(task);
TaskDel(task);
task=task1;
}
LBtr(&Gs->cpu_flags,CPUf_DYING_TASK_QUE);
Gs->kill_jiffy=cnts.jiffies+DYING_JIFFIES;
}
}
+471
View File
@@ -0,0 +1,471 @@
asm {
_MEMSET::
PUSH RBP
MOV RBP,RSP
PUSH RDI
CLD
MOV RDI,U64 SF_ARG1[RBP]
MOV RAX,U64 SF_ARG2[RBP]
MOV RCX,U64 SF_ARG3[RBP]
REP_STOSB
MOV RAX,RDI
POP RDI
POP RBP
RET1 24
_MEMSET_U16::
PUSH RBP
MOV RBP,RSP
PUSH RDI
CLD
MOV RDI,U64 SF_ARG1[RBP]
MOV RAX,U64 SF_ARG2[RBP]
MOV RCX,U64 SF_ARG3[RBP]
REP_STOSW
MOV RAX,RDI
POP RDI
POP RBP
RET1 24
_MEMSET_U32::
PUSH RBP
MOV RBP,RSP
PUSH RDI
CLD
MOV RDI,U64 SF_ARG1[RBP]
MOV RAX,U64 SF_ARG2[RBP]
MOV RCX,U64 SF_ARG3[RBP]
REP_STOSD
MOV RAX,RDI
POP RDI
POP RBP
RET1 24
_MEMSET_I64::
PUSH RBP
MOV RBP,RSP
PUSH RDI
CLD
MOV RDI,U64 SF_ARG1[RBP]
MOV RAX,U64 SF_ARG2[RBP]
MOV RCX,U64 SF_ARG3[RBP]
REP_STOSQ
MOV RAX,RDI
POP RDI
POP RBP
RET1 24
_MEMCPY::
PUSH RBP
MOV RBP,RSP
PUSH RSI
PUSH RDI
CLD
MOV RDI,U64 SF_ARG1[RBP]
MOV RSI,U64 SF_ARG2[RBP]
MOV RCX,U64 SF_ARG3[RBP]
REP_MOVSB
MOV RAX,RDI
POP RDI
POP RSI
POP RBP
RET1 24
_MEMCMP::
PUSH RBP
MOV RBP,RSP
PUSH RSI
PUSH RDI
CLD
MOV RSI,U64 SF_ARG1[RBP]
MOV RDI,U64 SF_ARG2[RBP]
MOV RCX,U64 SF_ARG3[RBP]
XOR RAX,RAX
REPE_CMPSB
JZ @@05
MOV AL,1
JA @@05
MOV RAX,-1
@@05: POP RDI
POP RSI
POP RBP
RET1 24
_BEQU::
PUSH RBP
MOV RBP,RSP
XOR RAX,RAX
MOV RDX,U64 SF_ARG3[RBP]
MOV RBX,U64 SF_ARG1[RBP]
MOV RCX,U64 SF_ARG2[RBP]
TEST RDX,RDX
JZ @@5
BTS U64 [RBX],RCX
JMP @@10
@@5: BTR U64 [RBX],RCX
@@10: ADC AL,0
POP RBP
RET1 24
_LBEQU::
PUSH RBP
MOV RBP,RSP
XOR RAX,RAX
MOV RDX,U64 SF_ARG3[RBP]
MOV RBX,U64 SF_ARG1[RBP]
MOV RCX,U64 SF_ARG2[RBP]
TEST RDX,RDX
JZ @@5
LOCK
BTS U64 [RBX],RCX
JMP @@10
@@5: LOCK
BTR U64 [RBX],RCX
@@10: ADC AL,0
POP RBP
RET1 24
_CLAMP_I64::
PUSH RBP
MOV RBP,RSP
MOV RAX,U64 SF_ARG1[RBP]
MOV RCX,U64 SF_ARG2[RBP]
MOV RDX,U64 SF_ARG3[RBP]
CMP RAX,RCX
CMOVL RAX,RCX
CMP RAX,RDX
CMOVG RAX,RDX
POP RBP
RET1 24
_CLAMP_U64::
PUSH RBP
MOV RBP,RSP
MOV RAX,U64 SF_ARG1[RBP]
MOV RCX,U64 SF_ARG2[RBP]
MOV RDX,U64 SF_ARG3[RBP]
CMP RAX,RCX
CMOVB RAX,RCX
CMP RAX,RDX
CMOVA RAX,RDX
POP RBP
RET1 24
_CALL::
PUSH RBP
MOV RBP,RSP
MOV RAX,U64 SF_ARG1[RBP]
TEST RAX,RAX
JZ @@05
CALL RAX
@@05: POP RBP
RET1 8
_BIT_FIELD_OR_U32::
PUSH RBP
MOV RBP,RSP
MOV RBX,U64 SF_ARG2[RBP]
SHR RBX,3
ADD RBX,U64 SF_ARG1[RBP]
MOV RAX,U64 SF_ARG3[RBP]
MOV RCX,U64 SF_ARG2[RBP]
AND CL,7
SHL RAX,CL
OR U64 [RBX],RAX
POP RBP
RET1 24
_BIT_FIELD_EXT_U32::
PUSH RBP
MOV RBP,RSP
MOV RBX,U64 SF_ARG2[RBP]
MOV RCX,RBX
SHR RBX,3
ADD RBX,U64 SF_ARG1[RBP]
MOV RDX,U64 [RBX]
AND CL,7
SHR RDX,CL
MOV RCX,U64 SF_ARG3[RBP]
MOV RAX,1
SHL RAX,CL
DEC RAX
AND RAX,RDX
POP RBP
RET1 24
_XCHG_I64::
PUSH RBP
MOV RBP,RSP
MOV RDX,U64 SF_ARG1[RBP]
MOV RAX,U64 SF_ARG2[RBP]
XCHG U64 [RDX],RAX
POP RBP
RET1 16
_XCHG_U32::
PUSH RBP
MOV RBP,RSP
MOV RDX,U64 SF_ARG1[RBP]
MOV EAX,U32 SF_ARG2[RBP]
XCHG U32 [RDX],EAX
POP RBP
RET1 16
_XCHG_U16::
PUSH RBP
MOV RBP,RSP
MOV RDX,U64 SF_ARG1[RBP]
MOVZX RAX,U16 SF_ARG2[RBP]
XCHG U16 [RDX],AX
POP RBP
RET1 16
_XCHG_U8::
PUSH RBP
MOV RBP,RSP
MOV RDX,U64 SF_ARG1[RBP]
MOVZX RAX,U8 SF_ARG2[RBP]
XCHG U8 [RDX],AL
POP RBP
RET1 16
_LXCHG_I64::
PUSH RBP
MOV RBP,RSP
MOV RDX,U64 SF_ARG1[RBP]
MOV RAX,U64 SF_ARG2[RBP]
LOCK
XCHG U64 [RDX],RAX
POP RBP
RET1 16
_LXCHG_U32::
PUSH RBP
MOV RBP,RSP
MOV RDX,U64 SF_ARG1[RBP]
MOV EAX,U32 SF_ARG2[RBP]
LOCK
XCHG U32 [RDX],EAX
POP RBP
RET1 16
_LXCHG_U16::
PUSH RBP
MOV RBP,RSP
MOV RDX,U64 SF_ARG1[RBP]
MOVZX RAX,U16 SF_ARG2[RBP]
LOCK
XCHG U16 [RDX],AX
POP RBP
RET1 16
_LXCHG_U8::
PUSH RBP
MOV RBP,RSP
MOV RDX,U64 SF_ARG1[RBP]
MOVZX RAX,U8 SF_ARG2[RBP]
LOCK
XCHG U8 [RDX],AL
POP RBP
RET1 16
_REP_IN_U32::
PUSH RBP
MOV RBP,RSP
PUSH RDI
MOV RDI,U64 SF_ARG1[RBP]
MOV RDX,U64 SF_ARG3[RBP]
MOV RCX,U64 SF_ARG2[RBP]
REP_INSD
POP RDI
POP RBP
RET1 24
_REP_IN_U16::
PUSH RBP
MOV RBP,RSP
PUSH RDI
MOV RDI,U64 SF_ARG1[RBP]
MOV RDX,U64 SF_ARG3[RBP]
MOV RCX,U64 SF_ARG2[RBP]
REP_INSW
POP RDI
POP RBP
RET1 24
_REP_IN_U8::
PUSH RBP
MOV RBP,RSP
PUSH RDI
MOV RDI,U64 SF_ARG1[RBP]
MOV RDX,U64 SF_ARG3[RBP]
MOV RCX,U64 SF_ARG2[RBP]
REP_INSB
POP RDI
POP RBP
RET1 24
_REP_OUT_U32::
PUSH RBP
MOV RBP,RSP
PUSH RSI
MOV RSI,U64 SF_ARG1[RBP]
MOV RDX,U64 SF_ARG3[RBP]
MOV RCX,U64 SF_ARG2[RBP]
REP_OUTSD
POP RSI
POP RBP
RET1 24
_REP_OUT_U16::
PUSH RBP
MOV RBP,RSP
PUSH RSI
MOV RSI,U64 SF_ARG1[RBP]
MOV RDX,U64 SF_ARG3[RBP]
MOV RCX,U64 SF_ARG2[RBP]
REP_OUTSW
POP RSI
POP RBP
RET1 24
_REP_OUT_U8::
PUSH RBP
MOV RBP,RSP
PUSH RSI
MOV RSI,U64 SF_ARG1[RBP]
MOV RDX,U64 SF_ARG3[RBP]
MOV RCX,U64 SF_ARG2[RBP]
REP_OUTSB
POP RSI
POP RBP
RET1 24
_CPUID::
PUSH RBP
MOV RBP,RSP
PUSH RSI
MOV RAX,U64 SF_ARG1[RBP]
CPUID
MOV RSI,U64 SF_ARG2[RBP]
MOV U64 [RSI],RAX
MOV U64 8[RSI],RBX
MOV U64 16[RSI],RCX
MOV U64 24[RSI],RDX
POP RSI
POP RBP
RET1 16
_CALL_IND:: //See $LK,"_LAST_FUN",A="MN:_LAST_FUN"$
PUSH RBP
MOV RBP,RSP
PUSH RSI
PUSH RDI
MOV RDX,U64 SF_ARG1[RBP]
MOV RCX,U64 SF_ARG2[RBP] //argc
LEA RSI,U64 SF_ARG3[RBP] //argv
SHL RCX,3
SUB RSP,RCX
MOV RDI,RSP
REP_MOVSB
TEST RDX,RDX
JZ @@05
CALL RDX
POP RDI
POP RSI
POP RBP
RET
@@05: MOV RCX,U64 SF_ARG2[RBP] //argc
SHL RCX,3
ADD RSP,RCX
XOR RAX,RAX
POP RDI
POP RSI
POP RBP
RET
_CALLEXTNUM::
PUSH RBP
MOV RBP,RSP
PUSH RSI
PUSH RDI
MOV RDX,U64 SF_ARG1[RBP]
MOV RCX,U64 SF_ARG2[RBP] //argc
LEA RSI,U64 SF_ARG3[RBP] //argv
SHL RCX,3
SUB RSP,RCX
MOV RDI,RSP
REP_MOVSB
MOV RAX,U64 [SYS_EXTERN_TABLE]
MOV RAX,U64 [RAX+RDX*8]
TEST RAX,RAX
JZ @@05
CALL RAX
POP RDI
POP RSI
POP RBP
RET
@@05: MOV RCX,U64 SF_ARG2[RBP] //argc
SHL RCX,3
ADD RSP,RCX
POP RDI
POP RSI
POP RBP
RET
_CALLEXTSTR::
PUSH RBP
MOV RBP,RSP
PUSH RSI
PUSH RDI
MOV RCX,U64 SF_ARG2[RBP] //argc
LEA RSI,U64 SF_ARG3[RBP] //argv
SHL RCX,3
SUB RSP,RCX
MOV RDI,RSP
REP_MOVSB
MOV RSI,U64 SF_ARG1[RBP]
MOV RCX,1
XOR RAX,RAX
MOV RDI,U64 FS:CTask.hash_table[RAX]
MOV RBX,HTT_FUN|HTT_EXPORT_SYS_SYM
CALL SYS_HASH_FIND
JZ @@15
TEST U32 CHash.type[RAX],HTT_FUN
JZ @@05
MOV RAX,U64 CHashFun.exe_addr[RAX]
JMP @@10
@@05: MOV RAX,U64 CHashExport.val[RAX]
@@10: TEST RAX,RAX
JZ @@15
CALL RAX
POP RDI
POP RSI
POP RBP
RET
@@15: MOV RCX,U64 SF_ARG2[RBP] //argc
SHL RCX,3
ADD RSP,RCX
POP RDI
POP RSI
POP RBP
RET
SET_GS_BASE::
PUSH RAX
PUSH RCX
PUSH RDX
MOV RDX,RAX
SHR RDX,32
MOV ECX,IA32_GS_BASE
WRMSR
POP RDX
POP RCX
POP RAX
RET
SET_FS_BASE::
PUSH RAX
PUSH RCX
PUSH RDX
MOV RDX,RAX
SHR RDX,32
MOV ECX,IA32_FS_BASE
WRMSR
POP RDX
POP RCX
POP RAX
_RET::
RET
_SET_MSR::
PUSH RBP
MOV RBP,RSP
MOV RAX,SF_ARG2[RBP]
MOV RDX,RAX
SHR RDX,32
MOV RCX,SF_ARG1[RBP]
WRMSR
POP RBP
RET1 16
_SYS_HLT::
CLI
@@05: HLT
JMP @@05
}
File diff suppressed because it is too large. Load diff
+61
View File
@@ -0,0 +1,61 @@
//Compile this by calling $LK,"BootHDIns",A="MN:BootHDIns"$().
//Don't do it directly. See $LK,"Cmp(\"/Kernel/Kernel\")",A="FF:::/Adam/Opt/Boot/BootHDIns.HC,Cmp(\"/Kernel/Kernel\""$.
#exe {
Cd(__DIR__);;
Option(OPTf_WARN_PAREN,ON);
Option(OPTf_WARN_DUP_TYPES,ON);
#include "KCfg"
CKCfg *kernel_cfg;
kernel_cfg=KCfgNew;
};
#include "KernelA.HH"
#include "KStart16"
#include "KStart32"
#include "KStart64"
#include "KMathA"
#include "KUtils"
#exe {Option(OPTf_KEEP_PRIVATE,ON);};
#include "/Compiler/CompilerA.HH"
#exe {Option(OPTf_EXTERNS_TO_IMPORTS,ON);};
#include "/Compiler/CompilerB.HH"
#exe {Option(OPTf_EXTERNS_TO_IMPORTS,OFF);};
#exe {Option(OPTf_KEEP_PRIVATE,OFF);};
#include "KernelB.HH"
#include "KExts"
#include "StrA"
#include "KGlbls"
#include "KMathB"
#include "Sched"
#include "Mem/MakeMem"
#include "FontStd"
#include "FontCyrillic"
#include "StrB"
#include "KHashA"
#include "KInts"
#include "KDataTypes"
#include "Compress"
#include "KHashB"
#include "KLoad"
#include "KDate"
#include "StrPrint"
#include "StrScan"
#include "KDefine"
#include "Display"
#include "KMisc"
#include "KDbg"
#include "KeyDev"
#include "KExcept"
#include "SerialDev/MakeSerialDev"
#include "QSort"
#include "KTask"
#include "Job"
#include "PCIBIOS"
#include "MultiProc"
#include "EdLite"
#include "BlkDev/MakeBlkDev"
#include "FunSeg"
#include "KEnd"
#exe {KCfgDel(kernel_cfg);};
File diff suppressed because it is too large. Load diff
+293
View File
@@ -0,0 +1,293 @@
/* Kernel ASM symbols.
$LK,"KernelB",A="FF:::/Kernel/Kernel.PRJ,KernelB"$ Kernel.PRJ
$LK,"KernelB",A="FF:::/Compiler/Compiler.PRJ,KernelB"$ Compiler.PRJ
$LK,"KernelB",A="FF:::/StartOS.HC,KernelB"$ StartOS.HC
*/
#help_index "Bit"
#help_file "::/Doc/Bit"
public _intern IC_BSF I64 Bsf(
I64 bit_field_val);//Scan fwd from lowest for 1st set. -1 if not found.
public _intern IC_BSR I64 Bsr(
I64 bit_field_val);//Scan rev from highest for 1st set. -1 if not found.
public _intern IC_BT Bool Bt(
U8 *bit_field,I64 bit); //Bit test.
public _intern IC_BTC Bool Btc(
U8 *bit_field,I64 bit); //Bit test and complement (same as xor with 1).
public _intern IC_BTR Bool Btr(
U8 *bit_field,I64 bit); //Bit test and reset to zero.
public _intern IC_BTS Bool Bts(
U8 *bit_field,I64 bit); //Bit test and set to one.
public _intern IC_LBTC Bool LBtc(
U8 *bit_field,I64 bit); //Locked bit test and complement (xor with 1).
public _intern IC_LBTR Bool LBtr(
U8 *bit_field,I64 bit); //Locked bit test and reset to zero.
public _intern IC_LBTS Bool LBts(
U8 *bit_field,I64 bit); //Locked bit test and set to one.
public _extern _BEQU Bool BEqu(
U8 *bit_field,I64 bit,Bool val);//Set bit equ to val.
public _extern _BIT_FIELD_EXT_U32 U32 BFieldExtU32(
U8 *bit_field,I64 bit,I64 size); //Extract U32 from bit field.
public _extern _BIT_FIELD_OR_U32 U0 BFieldOrU32(
U8 *bit_field,I64 bit,U32 pattern); //Or U32 into bit field.
public _extern _LBEQU Bool LBEqu(
U8 *bit_field,I64 bit,Bool val); //Locked Set bit equ to val.
#help_index "Boot"
_extern MEM_BOOT_BASE U32 mem_boot_base;
_extern SYS_BOOT_BLK U32 sys_boot_blk;
_extern SYS_BOOT_PATCH_TABLE_BASE U32 sys_boot_patch_table_base;
_extern SYS_BOOT_SRC U32 sys_boot_src;
_extern SYS_RUN_LEVEL U32 sys_run_level;
#help_index "Call"
public _extern _CALL I64 Call(U8 *machine_code); //Call addr with no args.
public _extern _CALLEXTSTR I64 CallExtStr(
/*argpop*/ U8 *name,...); //Search sym table for fun and pass it args.
//Can have any fixed number of arguments.
public _extern _CALL_IND I64 CallInd(
/*argpop*/I64 (*fp_addr)(...),...); //Call with fixed number of args.
#help_index "Call/System Extern Num"
public _extern SYS_EXTERN_TABLE /*argpop*/
I64 (**ext)(...); //Array of fun ptrs. See $LK,"Extern Num Definitions",A="MN:EXT_EXTS_NUM"$
public _extern _CALLEXTNUM
I64 CallExtNum(I64 num,...); //Call ext num with fixed number of args.
#help_index "Char/Conversion"
public _intern IC_TOUPPER I64 ToUpper(U8 ch); //Cvt char to upper case.
#help_index "Char/Operations"
public _intern IC_STRLEN I64 StrLen(U8 *st); //String length.
#help_index "Data Types/Circular Queue"
#help_file "::/Doc/Que"
public _intern IC_QUE_INIT U0 QueInit(
CQue *head); //Init queue head links.
public _intern IC_QUE_INS U0 QueIns(
CQue *entry,CQue *pred);//Insert item into que after predecessor.
public _intern IC_QUE_INS_REV U0 QueInsRev(
CQue *entry,CQue *succ);//Revd insert into que.
//Ins item into que before successor.
public _intern IC_QUE_REM U0 QueRem(CQue *entry); //Remove item from queue.
#help_index "I/O;Processor/IO Port"
public _intern IC_IN_U16 U16 InU16(I64 port); //Read U16 from I/O port.
public _intern IC_IN_U32 U32 InU32(I64 port); //Read U32 from I/O port.
public _intern IC_IN_U8 U8 InU8(I64 port); //Read U8 from I/O port.
public _intern IC_OUT_U16 U0 OutU16(I64 port, I64 val); //Write U16 to I/O port.
public _intern IC_OUT_U32 U0 OutU32(I64 port, I64 val); //Write U32 to I/O port.
public _intern IC_OUT_U8 U0 OutU8(I64 port, I64 val); //Write U8 to I/O port.
public _extern _REP_IN_U16 U0 RepInU16(
U8 *buf,I64 cnt,I64 port); //Repeated read U16 from I/O port.
public _extern _REP_IN_U32 U0 RepInU32(
U8 *buf,I64 cnt,I64 port); //Repeated read U32 from I/O port.
public _extern _REP_IN_U8 U0 RepInU8(
U8 *buf,I64 cnt,I64 port); //Repeated read U8 from I/O port.
public _extern _REP_OUT_U16 U0 RepOutU16(
U8 *buf,I64 cnt,I64 port); //Repeated write U16 to I/O port.
public _extern _REP_OUT_U32 U0 RepOutU32(
U8 *buf,I64 cnt,I64 port); //Repeated write U32 to I/O port.
public _extern _REP_OUT_U8 U0 RepOutU8(
U8 *buf,I64 cnt,I64 port); //Repeated write U8 to I/O port.
#help_index "Math"
public _intern IC_ATAN F64 ATan(F64 d); //Arc Tan (Inverse Tan).
public _intern IC_ABS F64 Abs(F64 d); //Absolute F64.
public _intern IC_ABS_I64 I64 AbsI64(I64 i); //Absolute I64.
public _intern IC_COS F64 Cos(F64 d); //Cosine.
public _intern IC_MAX_I64 I64 MaxI64(I64 n1,I64 n2); //Max of two I64s.
public _intern IC_MAX_U64 U64 MaxU64(U64 n1,U64 n2); //Max of two U64s.
public _intern IC_MIN_I64 I64 MinI64(I64 n1,I64 n2); //Min of two I64s.
public _intern IC_MIN_U64 U64 MinU64(U64 n1,U64 n2); //Min of two U64s.
public _intern IC_MOD_U64 U64 ModU64(U64 *q,U64 d); //Div and return U64 Modulo.
public _intern IC_SIGN_I64 I64 SignI64(I64 i); //Sign of I64: -1,0,1.
public _intern IC_SIN F64 Sin(F64 d); //Sine.
public _intern IC_SQR F64 Sqr(F64 d); //Square of F64.
public _intern IC_SQR_I64 I64 SqrI64(I64 i); //Square of I64.
public _intern IC_SQR_U64 U64 SqrU64(U64 i); //Square of U64.
public _intern IC_SQRT F64 Sqrt(F64 d); //Square head of F64.
public _intern IC_SWAP_I64 U0 SwapI64(
I64 *n1,I64 *n2); //Swap two I64s. Not atomic.
public _intern IC_SWAP_U16 U0 SwapU16(
U16 *n1,U16 *n2); //Swap two U16s. Not atomic.
public _intern IC_SWAP_U32 U0 SwapU32(
U32 *n1,U32 *n2); //Swap two U32s. Not atomic.
public _intern IC_SWAP_U8 U0 SwapU8(
U8 *n1,U8 *n2); //Swap two U8s. Not atomic.
public _intern IC_TAN F64 Tan(F64 d); //Tangent.
public _intern IC_TO_BOOL Bool ToBool(I64 i); //Convert to Boolean.
public _intern IC_TO_F64 F64 ToF64(I64 i); //Convert to F64.
public _intern IC_TO_I64 I64 ToI64(F64 d); //Convert to I64. Truncates.
public _extern _ARG F64 Arg(F64 x,F64 y); //Polar coordinate angle.
public _extern _CEIL F64 Ceil(F64 d); //Ceiling of F64.
public _extern _CLAMP_I64 I64 ClampI64(
I64 num,I64 lo,I64 hi); //Clamp to I64 [] range.
public _extern _CLAMP_U64 U64 ClampU64(
U64 num,U64 lo,U64 hi); //Clamp to U64 [] range.
public _extern _EXP F64 Exp(F64 d); //Exponential function.
_extern _FCLEX U0 Fclex();
_extern _FLDCW U0 Fldcw(U16 w);
public _extern _FLOOR F64 Floor(F64 d); //Floor of F64.
_extern _FSTCW U16 Fstcw();
_extern _FSTSW U16 Fstsw();
public _extern _LN F64 Ln(F64 d); //Logarithm.
public _extern _LOG10 F64 Log10(F64 d); //Log base 10.
public _extern _LOG2 F64 Log2(F64 d); //Log base 2.
public _extern _POW F64 Pow(F64 base,F64 power); //F64 base to a power.
public _extern _POW10 F64 Pow10(F64 d); //Ten to the dth power.
public _extern _ROUND F64 Round(F64 d); //Round F64 to whole number.
public _extern _SIGN F64 Sign(F64 d); //Sign of F64: -1,0,1
public _extern _TRUNC F64 Trunc(F64 d); //Truncate F64.
#help_index "Math/CD3;Data Types/CD3"
#help_file "::/Doc/D3"
public _extern _D3_ADD CD3 *D3Add(CD3 *sum,CD3 *d1,CD3 *d2); //sum=d1+d2
public _extern _D3_ADD_EQU CD3 *D3AddEqu(CD3 *sum,CD3 *d); //sum+=d
public _extern _D3_COPY CD3 *D3Copy(CD3 *dst,CD3 *src); //dst=src
public _extern _D3_CROSS CD3 *D3Cross(CD3 *prod,CD3 *d1,CD3 *d2); //prod=d1xd2
public _extern _D3_DIST F64 D3Dist(CD3 *d1,CD3 *d2); //Distance
public _extern _D3_DIST_SQR F64 D3DistSqr(CD3 *d1,CD3 *d2); //Distance Squared
public _extern _D3_DIV CD3 *D3Div(CD3 *quot,CD3 *d,F64 s); //quot=d/s
public _extern _D3_DIV_EQU CD3 *D3DivEqu(CD3 *quot,F64 s); //quot/=s
public _extern _D3_DOT F64 D3Dot(CD3 *d1,CD3 *d2); //d1 dot d2
public _extern _D3_EQU CD3 *D3Equ(CD3 *dst,F64 x,F64 y,F64 z); //dst=(x,y,z)
public _extern _D3_MUL CD3 *D3Mul(CD3 *prod,F64 s,CD3 *d); //prod=s*d
public _extern _D3_MUL_EQU CD3 *D3MulEqu(CD3 *prod,F64 s); //prod*=s
public _extern _D3_NORM F64 D3Norm(CD3 *d); //Norm
public _extern _D3_NORM_SQR F64 D3NormSqr(CD3 *d); //Norm Squared
public _extern _D3_SUB CD3 *D3Sub(CD3 *diff,CD3 *d1,CD3 *d2); //diff=d1-d2
public _extern _D3_SUB_EQU CD3 *D3SubEqu(CD3 *diff,CD3 *d); //diff-=d
public _extern _D3_UNIT CD3 *D3Unit(CD3 *d); //To unit vect
public _extern _D3_ZERO CD3 *D3Zero(CD3 *dst); //To zero
#help_index "Memory"
public _extern _MEMCMP I64 MemCmp(
U8 *ptr1,U8 *ptr2,I64 cnt); //Compare chunk of memory.
public _extern _MEMCPY U8 *MemCpy(
U8 *dst,U8 *src,I64 cnt); //Copy chunk of memory. Only goes fwd.
public _extern _MEMSET U8 *MemSet(
U8 *dst,I64 val,I64 cnt); //Set chunk of U8s to value.
public _extern _MEMSET_I64 I64 *MemSetI64(
I64 *dst,I64 val,I64 I64cnt); //Set chunk of I64s to value.
public _extern _MEMSET_U16 U16 *MemSetU16(
U16 *dst,I64 val,I64 U16cnt); //Set chunk of U16s to value.
public _extern _MEMSET_U32 U32 *MemSetU32(
U32 *dst,I64 val,I64 U32cnt); //Set chunk of U32s to value.
public _extern _MEMSET U8 *MemSetU8(
U8 *dst,I64 val,I64 U8cnt); //Set chunk of U8s to value.
_extern SYS_HEAP_DBG_FLAG U8 sys_heap_dbg;
_extern SYS_HEAP_INIT_FLAG U8 sys_heap_init_flag;
_extern SYS_HEAP_INIT_VAL U8 sys_heap_init_val;
_extern SYS_MEM_INIT_FLAG U8 sys_mem_init_flag;
_extern SYS_MEM_INIT_VAL U8 sys_mem_init_val;
_extern SYS_STAFF_MODE_FLAG U8 sys_staff_mode_flag;
_extern SYS_VAR_INIT_FLAG U8 sys_var_init_flag;
_extern SYS_VAR_INIT_VAL U8 sys_var_init_val;
#help_index "Memory/BlkPool"
public _extern SYS_CODE_BP CBlkPool *sys_code_bp; //System's BlkPool for code.
public _extern SYS_DATA_BP CBlkPool *sys_data_bp; //System's BlkPool for data.
#help_index "Memory/Info"
_extern MEM_HEAP_BASE U8 *mem_heap_base;
_extern MEM_HEAP_LIMIT U8 *mem_heap_limit;
_extern MEM_MAPPED_SPACE U8 *mem_mapped_space;
_extern MEM_PHYSICAL_SPACE U8 *mem_physical_space;
#help_index "Messages;Windows"
public _extern SYS_FOCUS_TASK CTask *sys_focus_task; //Current focus task.
#help_index "Misc"
public _extern SYS_COMPILE_TIME
CDate sys_compile_time; //Date and time kernel was compiled.
_extern SYS_CTRL_ALT_FLAGS
I64 sys_ctrl_alt_flags[1]; //Should be semiphores?
#help_index "Misc/Progress Bars"
public _extern SYS_PROGRESS1 I64 progress1; //Current progress 1.
public _extern SYS_PROGRESS1_DESC
U8 progress1_desc[PROGRESS_DESC_LEN]; //Progress 1 desc.
public _extern SYS_PROGRESS1_MAX I64 progress1_max; //Progress 1 max.
public _extern SYS_PROGRESS1_T0 F64 progress1_t0; //Progress 1 start time.
public _extern SYS_PROGRESS1_TF F64 progress1_tf; //Progress 1 end time.
public _extern SYS_PROGRESS2 I64 progress2; //Current progress 2.
public _extern SYS_PROGRESS2_DESC
U8 progress2_desc[PROGRESS_DESC_LEN]; //Progress 2 desc.
public _extern SYS_PROGRESS2_MAX I64 progress2_max; //Progress 2 max.
public _extern SYS_PROGRESS2_T0 F64 progress2_t0; //Progress 2 start time.
public _extern SYS_PROGRESS2_TF F64 progress2_tf; //Progress 2 end time.
public _extern SYS_PROGRESS3 I64 progress3; //Current progress 3.
public _extern SYS_PROGRESS3_DESC
U8 progress3_desc[PROGRESS_DESC_LEN]; //Progress 3 desc.
public _extern SYS_PROGRESS3_MAX I64 progress3_max; //Progress 3 max.
public _extern SYS_PROGRESS3_T0 F64 progress3_t0; //Progress 3 start time.
public _extern SYS_PROGRESS3_TF F64 progress3_tf; //Progress 3 end time.
public _extern SYS_PROGRESS4 I64 progress4; //Current progress 4.
public _extern SYS_PROGRESS4_DESC
U8 progress4_desc[PROGRESS_DESC_LEN]; //Progress 4 desc.
public _extern SYS_PROGRESS4_MAX I64 progress4_max; //Progress 4 max.
public _extern SYS_PROGRESS4_T0 F64 progress4_t0; //Progress 4 start time.
public _extern SYS_PROGRESS4_TF F64 progress4_tf; //Progress 4 end time.
public _extern SYS_PROGRESSES
CProgress sys_progresses[PROGRESS_BARS_NUM]; //All progress bars.
#help_index "MultiCore"
#help_file "::/Doc/MultiCore"
public _extern SYS_CPU_STRUCTS CCPU *cpu_structs; //$LK,"Gs",A="MN:Gs"$ points to cur $LK,"CCPU",A="MN:CCPU"$.
public _extern SYS_MP_CNT I64 mp_cnt; //Count of cores
_extern SYS_MP_CNT_INITIAL I64 mp_cnt_initial; //only used during $LK,"Core0StartMP",A="MN:Core0StartMP"$
_extern SYS_MP_CNT_LOCK I64 mp_cnt_lock;
_extern SYS_SEMAS CSema sys_semas[SEMA_SEMAS_NUM];
#help_index "MultiCore;Processor"
public _intern IC_GS CCPU *Gs(); //GS points to current $LK,"CCPU",A="MN:CCPU"$.
#help_index "PCI"
public _extern SYS_PCI_BUSES U16 sys_pci_busses; //Number of PCI buses.
#help_index "Processor"
public _intern IC_CARRY I64 Carry(); //See $LK,"::/Demo/Carry.HC"$
public _intern IC_GET_RAX I64 GetRAX(); //Get RAX register value.
public _intern IC_GET_RBP U8 *GetRBP(); //Get RBP register value.
public _intern IC_GET_RFLAGS I64 GetRFlags(); //Get RFlags register value.
public _intern IC_GET_RSP U8 *GetRSP(); //Get RSP register value.
public _intern IC_POP I64 Pop(); //Pop value from stk.
public _intern IC_PUSH U0 Push(I64 d); //Push value on stk.
public _intern IC_SET_RAX U0 SetRAX(I64 d); //Set RAX register value.
public _intern IC_SET_RBP U0 SetRBP(U8 *d); //Set RBP register value.
public _intern IC_SET_RFLAGS U0 SetRFlags(I64 d); //Set RFlags register value.
public _intern IC_SET_RSP U0 SetRSP(U8 *d); //Set RSP register value.
public _extern _CPUID U0 CPUId(
U32 rax,CRAXRBCRCXRDX *res); //Do CPUID inst.
public _extern _LXCHG_I64 I64 LXchgI64(I64 *dst,I64 d); //Locked eXchange I64s.
public _extern _LXCHG_U16 U16 LXchgU16(U16 *dst,U16 d); //Locked eXchange U16s.
public _extern _LXCHG_U32 U32 LXchgU32(U32 *dst,U32 d); //Locked eXchange U32s.
public _extern _LXCHG_U8 U8 LXchgU8(U8 *dst,U8 d); //Locked eXchange U8s.
public _extern _SET_MSR U0 SetMSR(
I64 model_specific_reg,I64 val); //Model Specific Reg See $LK,"MSRs",A="MN:IA32_EFER"$.
public _extern _SYS_HLT U0 SysHlt(); //Loops doing HLT inst.
public _extern _XCHG_I64 I64 XchgI64(I64 *dst,I64 d); //eXchange I64s.
public _extern _XCHG_U16 U16 XchgU16(U16 *dst,U16 d); //eXchange U16s.
public _extern _XCHG_U32 U32 XchgU32(U32 *dst,U32 d); //eXchange U32s.
public _extern _XCHG_U8 U8 XchgU8(U8 *dst,U8 d); //eXchange U8s.
_extern SYS_GDT CGDT sys_gdt;
#help_index "Processor/Cache;Memory/Cache"
public _intern IC_CLFLUSH U0 CLFlush(U8 *a); //Flush cache line inst.
public _extern SYS_CACHE_LINE_WIDTH
I64 sys_cache_line_width; //CPU's Cache line width.
#help_index "Processor/Page Tables;Memory/Page Tables"
public _intern IC_INVLPG
U0 InvlPg(U8 *a); //Invalidate page at addr inst.
public _extern MEM_PAGE_SIZE U64 mem_page_size;
#help_index "Task;Processor"
public _intern IC_FS CTask *Fs(); //FS seg reg points to the current $LK,"CTask",A="MN:CTask"$.
#help_index "Time/CPU Cycles"
#help_file "::/Doc/TimeCycles"
public _intern IC_RDTSC I64 GetTSC(); //Get time stamp counter.
#help_index ""
+764
View File
@@ -0,0 +1,764 @@
#help_index "AutoComplete"
#help_file "::/Doc/AutoComplete"
public extern CAutoCompleteGlbls ac;
#help_index "AutoComplete/Dictionary"
public extern CAutoCompleteDictGlbls acd;
#help_index "Bit"
public extern I64 BCnt(I64 d);
public extern U8 *rev_bits_table,*set_bits_table;
#help_index "Boot"
#help_file "::/Doc/Boot"
public extern U0 Reboot();
#help_index "Call"
public argpop extern I64 CallStkGrow(I64 stk_size_threshold,I64 stk_size,
/*argpop*/I64 (*fp_addr)(...),...);
//fp_addr can have any fixed number of arguments.
#help_index "Call/FarCall32"
public _extern _FAR_CALL32 Bool FarCall32(U0 (*fp_addr)());//Not reentrant
public _extern C32_EAX U32 c32_eax;
public _extern C32_EBX U32 c32_ebx;
public _extern C32_ECX U32 c32_ecx;
public _extern C32_EDI U32 c32_edi;
public _extern C32_EDX U32 c32_edx;
public _extern C32_EFLAGS U32 c32_eflags;
public _extern C32_ESI U32 c32_esi;
#help_index "Char/BitMaps"
public extern U32 char_bmp_alpha[16],char_bmp_alpha_numeric[16],
char_bmp_alpha_numeric_no_at[16], char_bmp_word[16],
char_bmp_dec_numeric[16], char_bmp_hex_numeric[16],
char_bmp_white_space[16], char_bmp_non_eol_white_space[16],
char_bmp_zero_cr_nl_cursor[16], char_bmp_zero_tab_cr_nl_cursor[16],
char_bmp_zero_tab_cr_nl_cursor_dollar[16],
char_bmp_macro[16], char_bmp_printable[16],
char_bmp_displayable[16], char_bmp_safe_dollar[16],
char_bmp_filename[16], char_bmp_non_eol[16];
#help_index "Char/Conversion"
public extern U8 *Char2KeyName(I64 ch,Bool include_ctrl=TRUE);
public extern I64 Char2ScanCode(I64 ch,I64 sc_flags=0);
public extern U8 ScanCode2Char(I64 sc);
public extern U8 *ScanCode2KeyName(I64 sc);
public extern F64 Str2F64(U8 *src,U8 **_end_ptr=NULL);
public extern I64 Str2I64(U8 *st,I64 radix=10,U8 **_end_ptr=NULL);
public extern U8 *StrScan(U8 *src,U8 *fmt,...);
#help_index "Char/Conversion;Time/Date/CDate;Date/CDate"
public extern CDate Str2Date(U8 *src);
#help_index "Char/Flags"
public extern U0 ScanFlags(U8 *_dst_flags,U8 *lst,U8 *src);
public extern U8 *StrPrintFlags(U8 *dst,U8 *lst,I64 flags);
#help_index "Char/Lists"
public extern I64 LstMatch(U8 *needle, U8 *haystack_lst,I64 flags=0);
public extern U8 *LstSub(I64 sub, U8 *lst);
#help_index "Char/Operations"
public extern U8 *MStrPrint(U8 *fmt,...);
public extern U8 *MStrUtil(U8 *src,I64 flags,F64 indent_scale_factor=0);
public extern U8 *ScaleIndent(U8 *src,F64 indent_scale_factor);
public extern I64 Spaces2Tabs(U8 *dst,U8 *src);
public _extern _STRCMP I64 StrCmp(U8 *st1,U8 *st2);
public _extern _STRCPY U0 StrCpy(U8 *dst,U8 *src);
public extern U8 *StrFind(U8 *needle,U8 *haystack_str,I64 flags=0);
public extern U8 *StrFirstOcc(U8 *src,U8 *marker);
public extern U8 *StrFirstRem(U8 *src,U8 *marker,U8 *dst=NULL);
public _extern _STRICMP I64 StrICmp(U8 *st1,U8 *st2);
public _extern _STRIMATCH U8 *StrIMatch(U8 *needle,U8 *haystack_str);
public extern U8 *StrLastOcc(U8 *src,U8 *marker);
public extern U8 *StrLastRem(U8 *src,U8 *marker,U8 *dst=NULL);
public _extern _STRMATCH U8 *StrMatch(U8 *needle,U8 *haystack_str);
public _extern _STRNCMP I64 StrNCmp(U8 *st1,U8 *st2,I64 n);
public _extern _STRNICMP I64 StrNICmp(U8 *st1,U8 *st2,I64 n);
public extern I64 StrOcc(U8 *src, U8 ch);
public extern U8 *StrPrint(U8 *dst,U8 *fmt,...);
public extern U8 *StrPrintJoin(U8 *dst,U8 *fmt,I64 argc,I64 *argv);
public extern U8 *StrUtil(U8 *_src,I64 flags);
public extern U8 *Tabs2Spaces(U8 *src);
public extern Bool WildMatch(U8 *test_str,U8 *wild_str);
#help_index "Char/Operations;Memory"
public extern U8 *CatPrint(U8 *dst,U8 *fmt,...);
#help_index "Char/Operations;Memory/Adam Heap"
public extern U8 *AStrNew(U8 *buf);
#help_index "Char/Operations;Memory/Heap"
public extern U8 *StrNew(U8 *buf,CTask *mem_task=NULL);
#help_index "Char/Output;StdOut"
public extern U0 GetOutOfDollar();
public extern Bool IsSilent();
public extern U0 Print(U8 *fmt,...);
public extern U0 PrintErr(U8 *fmt,...);
public extern U0 PrintWarn(U8 *fmt,...);
public extern U0 PutChars(U64 ch);
extern U0 PutHex(I64 num,I64 width);
public extern U0 PutKey(I64 ch=0,I64 sc=0);
extern U0 PutS(U8 *st); //Use $LK,"Print",A="MN:Print"$()
public extern Bool Silent(Bool val=ON);
extern U8 *StrPrintHex(U8 *dst,I64 num;I64 width);
#help_index "Char;Debugging/Raw Output;TextBase Layer/Char"
public extern CTextGlbls text;
#help_index "Compiler/Lex"
public extern U0 HashSrcFileSet(CCmpCtrl *cc,
CHashSrcSym *h,I64 line_num_offset=0);
#help_index "Compiler;Cmd Line (Typically)"
extern U8 *Load(U8 *filename,I64 ld_flags=0,
CBinFile *bfh_addr=INVALID_PTR); //INVALID_PTR=don't care what load addr
#help_index "Compression"
public extern CArcCompress *CompressBuf(U8 *src,I64 size,CTask *mem_task=NULL);
public extern U8 *ExpandBuf(CArcCompress *arc,CTask *mem_task=NULL);
#help_index "Compression/Piece by Piece"
public extern U0 ArcCompressBuf(CArcCtrl *c);
public extern U0 ArcCtrlDel(CArcCtrl *c);
public extern CArcCtrl *ArcCtrlNew(Bool expand,I64 compression_type=CT_8_BIT);
public extern U0 ArcExpandBuf(CArcCtrl *c);
public extern Bool ArcFinishCompression(CArcCtrl *c);
#help_index "Data Types/Circular Queue"
public extern I64 QueCnt(CQue *head);
public extern CQue *QueCopy(CQue *head,CTask *mem_task=NULL);
public extern U0 QueDel(CQue *head,Bool querem=FALSE);
public extern I64 QueSize(CQue *head);
#help_index "Data Types/Fifo"
public extern I64 FifoI64Cnt(CFifoI64 *f);
public extern U0 FifoI64Del(CFifoI64 *f);
public extern U0 FifoI64Flush(CFifoI64 *f);
public extern Bool FifoI64Ins(CFifoI64 *f,I64 q);
public extern CFifoI64 *FifoI64New(I64 size,CTask *mem_task=NULL);
public extern Bool FifoI64Peek(CFifoI64 *f,I64 *_q);
public extern Bool FifoI64Rem(CFifoI64 *f,I64 *_q);
public extern I64 FifoU8Cnt(CFifoU8 *f);
public extern U0 FifoU8Del(CFifoU8 *f);
public extern U0 FifoU8Flush(CFifoU8 *f);
public extern Bool FifoU8Ins(CFifoU8 *f,U8 b);
public extern CFifoU8 *FifoU8New(I64 size,CTask *mem_task=NULL);
public extern Bool FifoU8Peek(CFifoU8 *f,U8 *_b);
public extern Bool FifoU8Rem(CFifoU8 *f,U8 *_b);
#help_index "Data Types/Linked List"
public extern I64 LinkedLstCnt(U8 **_lst);
public extern U8 *LinkedLstCopy(U8 **_lst,CTask *mem_task=NULL);
public extern U0 LinkedLstDel(U8 **_lst);
public extern I64 LinkedLstSize(U8 **_lst);
#help_index "Data Types/Queue Vector"
public extern U0 QueVectU8Del(CQueVectU8 *v);
public extern I64 QueVectU8Get(CQueVectU8 *v,I64 idx);
public extern CQueVectU8 *QueVectU8New(I64 min_idx=0);
public extern U0 QueVectU8Put(CQueVectU8 *v,I64 idx,U8 ch);
#help_index "Debugging"
public extern U8 *Caller(I64 num=1);
public extern Bool ChkCodePtr(U8 *ptr);
public extern Bool ChkOnStk(U8 *ptr,CTask *task=NULL);
public extern Bool ChkPtr(U8 *ptr);
public extern Bool IsSingleUser();
public extern Bool IsSysDbg();
public extern Bool SingleUser(Bool val);
public extern Bool SysDbg(Bool val);
public extern U8 *TaskCaller(CTask *task=NULL,
I64 num=0,Bool saved_context=FALSE);
public extern I64 UnusedStk(CTask *task=NULL);
public extern CDbgGlbls dbg;
#help_index "Debugging/Debugger"
public extern Bool B(U8 *addr,CTask *task=NULL,Bool live=TRUE) //Toggle bpt.
public extern I64 B2(CTask *task=NULL,Bool live=TRUE);
extern CBpt *BptFind(U8 *needle_addr,CTask *haystack_task=NULL,Bool rem=FALSE);
public extern Bool BptR(U8 *addr,CTask *task=NULL,Bool live=TRUE,Bool rem=TRUE);
public extern Bool BptS(U8 *addr,CTask *task=NULL,Bool live=TRUE);
public extern Bool DbgMode(Bool val);
public extern Bool E(U8 *addr,I64 cnt=512,I64 edf_dof_flags=0);
public extern Bool EdLite(U8 *filename,I64 num=1,I64 edf_dof_flags=0);
extern Bool EdLiteFileLine(U8 *fl_file_line,I64 edf_dof_flags=0);
public extern Bool Fix(I64 edf_dof_flags=0);
public extern U0 FixSet(U8 *filename,I64 line);
public extern U0 G(U8 *ms=INVALID_PTR,CTask *task=NULL);
public extern U0 G2(U8 *ms=INVALID_PTR,CTask *task=NULL);
public extern Bool IsDbgMode();
public extern U0 S(U8 *ms=INVALID_PTR,CTask *task=NULL);
#help_index "Debugging/Debugger;DolDoc/Cmd Line (Typically);"\
"Cmd Line (Typically);Help System"
public extern Bool Man(U8 *st,I64 edf_dof_flags=0);
#help_index "Debugging/Dump"
public extern U0 CallerRep(U8 **rbp=NULL,CTask *task=NULL);
public extern U0 D(U8 *addr,I64 cnt=0x80,Bool show_offset=TRUE);
public extern U0 Da(U8 **addr,I64 cnt=0x10);
public extern U0 Dm(U8 *addr,I64 cnt=0x80);
public extern U0 Dr(CTask *task=NULL);
public extern U0 StkRep(CTask *task=NULL);
extern I64 *TaskRegAddr(CTask *task,I64 reg_num);
#help_index "Debugging/FunSeg"
#help_file "::/Doc/DbgFunSeg"
public extern Bool PutSrcLink(U8 *addr,I64 cnt=1,U8 *buf=NULL);
public extern U8 *SrcEdLink(U8 *addr,I64 cnt=1,CTask *mem_task=NULL);
public extern U8 *SrcFileName(U8 *addr,I64 cnt=1,CTask *mem_task=NULL);
public extern I64 SrcLineNum(U8 *addr,I64 cnt=1);
#help_index "Debugging/FunSeg;Hash/System"
public extern CHash *FunSegFind(U8 *addr,I64 *_offset);
#help_index "Debugging/Raw Output"
public extern Bool IsRaw();
public extern Bool Raw(Bool val);
public extern U0 RawD(I64 mS=100,U8 *addr,I64 cnt=0x80);
public extern U0 RawDm(I64 mS=100,U8 *addr,I64 cnt=0x80);
extern U0 RawDr(CTask *task=NULL);
public extern U0 RawPrint(I64 mS=100,U8 *fmt,...);
public extern U0 RawPutChar(I64 ch);
public extern U0 VGAFlush();
#help_index "Debugging;Debugging/Debugger"
public extern U0 Dbg(U8 *msg=NULL,I64 msg_num=0);
public extern U0 Panic(U8 *msg=NULL,I64 msg_num=0,Bool panic=TRUE);
#help_index "Define;Char/Define"
#help_file "::/Doc/Define"
public extern U8 *Define(U8 *dname);
public extern CHashDefineStr *DefineLoad(U8 *dname,U8 *st);
public extern U0 DefinePrint(U8 *dname,U8 *src,...);
#help_index "Define;Char/Define;Char/Lists"
public extern I64 DefineCnt(U8 *dname);
public extern CHashDefineStr *DefineLstLoad(U8 *dname,U8 *lst);
public extern I64 DefineMatch(U8 *needle,U8 *haystack_lst_dname,I64 flags=0);
public extern U8 *DefineSub(I64 sub,U8 *dname);
#help_index "Devices;Memory/Page Tables"
public extern U8 *Mem32DevAlloc(I64 size,I64 alignment);
public extern U0 Mem32DevFree(U8 *base);
public extern U8 *Mem64DevAlloc(I64 *_pages1Gig);
public extern U0 Mem64DevFree(U8 *base,I64 pages1Gig);
public extern CDevGlbls dev;
#help_index "DolDoc/Clipboard"
public extern CDoc *sys_clipboard_doc;
#help_index "DolDoc/Task;StdOut/Task"
#help_file "::/Doc/StdOutTask"
extern CDoc *(*fp_doc_put)(CTask *task=NULL);
#help_index "Exceptions"
public extern U0 Break();
public extern Bool BreakLock(CTask *task=NULL);
public extern Bool BreakUnlock(CTask *task=NULL);
public extern U0 PutExcept(Bool catch_it=TRUE);
extern U0 SysTry(U8 *start_label,U8 *skip_label);
extern U0 SysUntry();
public extern U0 throw(I64 ch=0,Bool no_log=FALSE);
#help_index "File/CD DVD"
public extern U0 DVDImageRead(U8 dvd_drv_let,U8 *out_name);
public extern U0 DVDImageWrite(U8 dvd_drv_let,
U8 *in_name=NULL,I64 media_type=MT_DVD);
#help_index "File/CFile"
public extern U0 FClose(CFile *f);
public extern CFile *FOpen(U8 *filename,U8 *flags,I64 cnt=0);
public extern Bool FRBlks(CFile *f,U8 *buf,I64 blk=FFB_NEXT_BLK,I64 cnt=1);
public extern I64 FSize(CFile *f);
public extern Bool FWBlks(CFile *f,U8 *buf,I64 blk=FFB_NEXT_BLK,I64 cnt=1);
#help_index "File/Cmd Line (Typically);Cmd Line (Typically)"
public extern Bool Cd(U8 *dirname=NULL,Bool make_dirs=FALSE);
public extern U0 ChgDsk(U8 drv_let=0);
public extern I64 Del(U8 *files_find_mask,Bool make_mask=FALSE,
Bool del_dir=FALSE,Bool print_msg=TRUE);
public extern I64 Dir(U8 *files_find_mask="*",Bool full=FALSE);
public extern Bool Drv(U8 drv_let);
public extern U0 HomeSet(U8 *dirname);
public extern Bool MkDir(U8 *filename,I64 entry_cnt=0);
#help_index "File/Cmd Line (Typically);Cmd Line (Typically);Install"
public extern Bool DrvMap(U8 drv_let,CDrv *dv);
#help_index "File/FileNames"
extern CDirEntry *Cd2DirEntry(CDirEntry *tmpde,U8 *abs_name);
public extern U8 *ChgExt(U8 *filename,U8 *extension);
public extern U8 *CurDir(CTask *task=NULL,CTask *mem_task=NULL);
public extern U8 *DftExt(U8 *filename,U8 *extension);
public extern U8 *DirFile(U8 *dirname,U8 *name=NULL,U8 *_extension=NULL);
public extern U8 *DirNameAbs(U8 *dirname);
public extern CBlkDev *DrvIsWritable(U8 drv_let=0,Bool except=FALSE);
public extern U8 *FileExtDot(U8 *src);
public extern U8 *FileExtRem(U8 *src,U8 *dst=NULL);
public extern U8 *FileNameAbs(U8 *filename,I64 fuf_flags=0);
public extern Bool FileNameChk(U8 *filename);
public extern Bool FilesFindMatch(U8 *_test_name,
U8 *files_find_mask,I64 fuf_flags=0);
public extern Bool IsDir(U8 *dir_name);
public extern Bool IsDotC(U8 *filename);
public extern Bool IsDotZ(U8 *filename);
public extern U0 PutDirLink(U8 *dirname,U8 *full_name=NULL);
public extern U0 PutFileLink(U8 *filename,U8 *full_name=NULL,
I64 line=0,Bool plain_text=FALSE);
public extern U0 ToFileLine(U8 *_fl_file_line,U8 **_filename,I64 *_linenum);
public extern U8 *ToggleZorNotZ(U8 *name);
#help_index "File/FileNames;Misc"
public extern U8 *FileNameTmpTxt();
#help_index "File/Internal"
public extern U0 DirContextDel(CDirContext *dirc,Bool restore=TRUE);
public extern CDirContext *DirContextNew(U8 *mask,
Bool make_mask=FALSE,Bool make_dirs=FALSE,Bool no_mask=FALSE);
public extern Bool DirNew(CDrv *dv,U8 *cur_dir,
CDirEntry *tmpde,Bool free_old_chain=TRUE);
extern I64 FileAttr(U8 *name,I64 old_attr=0);
#help_index "File/Low Level"
#help_file "::/Doc/FileLowLevel"
public extern CBlkDev *BlkDevChk(CBlkDev *bd,Bool except=TRUE);
public extern U0 BlkDevDel(CBlkDev *bd);
public extern Bool BlkDevLock(CBlkDev *bd);
public extern CBlkDev *BlkDevNextFreeSlot(U8 first_drv_let,I64 type);
public extern Bool BlkDevUnlock(CBlkDev *bd,Bool rst=FALSE);
public extern U0 BlkDevsRelease();
public extern I64 Cluster2Blk(CDrv *dv,I64 c);
public extern I64 ClusterNumNext(CDrv *dv,I64 c,I64 cnt=1);
public extern I64 ClustersAlloc(CDrv *dv,I64 c=0,
I64 cnt=1,Bool contiguous=FALSE);
extern Bool CopySingle(U8 *f1,U8 *f2); //Just one file
public extern U8 Drv2Let(CDrv *dv=NULL);
public extern CDrv *DrvChk(CDrv *dv,Bool except=TRUE);
public extern U0 DrvDel(CDrv *dv);
public extern Bool DrvLock(CDrv *dv);
public extern CDrv *DrvMakeFreeSlot(U8 drv_let);
public extern U8 *DrvModelNum(U8 drv_let=0);
public extern U8 DrvNextFreeLet(U8 first_drv_let='C');
public extern U8 *DrvSerialNum(U8 drv_let=0);
public extern U8 DrvTextAttrGet(U8 drv_let=0);
public extern Bool DrvUnlock(CDrv *dv,Bool rst=FALSE);
public extern U0 DrvsRelease();
extern U0 FAT32FreeClusters(CDrv *dv,I64 c);
public extern CBlkDev *Let2BlkDev(U8 drv_let=0,Bool except=TRUE);
public extern I64 Let2BlkDevType(U8 drv_let);
public extern CDrv *Let2Drv(U8 drv_let=0,Bool except=TRUE);
public extern U8 Let2Let(U8 drv_let=0);
extern I64 Name2DirCluster(CDrv *dv,U8 *dirname);
extern I64 Name2ParentDirCluster(CDrv *dv,U8 *dirname);
public extern Bool RBlks(CDrv *dv,U8 *buf, I64 blk, I64 cnt);
public extern I64 RClusters(CDrv *dv,U8 *buf,I64 c,I64 cnt);
public extern I64 RClustersBlks(CDrv *dv,U8 *buf,I64 c,I64 blks);
extern U0 RedSeaFreeClusters(CDrv *dv,I64 c,I64 cnt);
public extern Bool WBlks(CDrv *dv,U8 *buf, I64 blk, I64 cnt);
public extern I64 WClusters(CDrv *dv,U8 *buf,I64 c,I64 cnt);
public extern I64 WClustersBlks(CDrv *dv,U8 *buf,I64 c,I64 blks);
public extern U0 WZeroBlks(CDrv *dv,I64 blk,I64 cnt);
#help_index "File/Program Routines"
public extern U0 DirEntryDel(CDirEntry *tmpde);
public extern U0 DirEntryDel2(CDirEntry *tmpde);
public extern U0 DirTreeDel(CDirEntry *tmpde);
public extern U0 DirTreeDel2(CDirEntry *tmpde);
public extern Bool FileFind(U8 *filename,CDirEntry *_de=NULL,I64 fuf_flags=0);
public extern U8 *FileRead(U8 *filename,I64 *_size=NULL,I64 *_attr=NULL);
public extern I64 FileWrite(U8 *filename,
U8 *fbuf,I64 size,CDate cdt=0,I64 attr=0);
#help_index "File/Program Routines;File/FileNames"
public extern CDirEntry *FilesFind(U8 *files_find_mask,I64 fuf_flags=0);
#help_index "File/System"
public extern CATARep *ATAIDDrvs(CATARep *head,CATARep **_ata_drv,
CATARep **_atapi_drv);
extern CBlkDev *ATAMount(U8 first_drv_let,
I64 type,I64 base0,I64 base1,I64 unit);
extern Bool ATAPIStartStop(CBlkDev *bd,F64 timeout,Bool start);
extern I64 ATAProbe(I64 base0,I64 base1,I64 unit);
extern U0 ATAReadBlks(CBlkDev *bd,U8 *buf, I64 blk, I64 cnt);
extern U0 ATAWriteBlks(CBlkDev *bd,U8 *buf, I64 blk, I64 cnt);
public extern I64 AutoMountIDE();
extern I64 BlkDevAdd(CBlkDev *bd,I64 prt_num=I64_MIN,
Bool whole_drv,Bool make_free);
extern U0 DskCacheInit(I64 size_in_U8s);
public extern U0 DskCacheInvalidate(CDrv *dv);
public extern CBlkDevGlbls blkdev;
#help_index "Graphics/Color"
extern U0 (*fp_set_std_palette)();
public extern U8 *Color2Str(U8 *buf,CColorROPU32 c);
public extern CColorROPU16 Str2ColorU16(U8 *st);
public extern CColorROPU32 Str2ColorU32(U8 *st);
#help_index "Hash"
#help_file "::/Doc/Hash"
public _extern _HASH_ADD U0 HashAdd(CHash *tmph,CHashTable *table);
public _extern _HASH_ADD_AFTER U0 HashAddAfter(CHash *tmph,
CHash *pred,CHashTable *table); //Add hash entry after entry.
public _extern _HASH_BUCKET_FIND CHash **HashBucketFind(
U8 *needle_str,CHashTable *haystack_table);
public _extern _HASH_FIND CHash *HashFind(U8 *needle_str,
CHashTable *haystack_table,I64 mask,I64 instance=1);
public _extern _HASH_SINGLE_TABLE_FIND CHash *HashSingleTableFind(
U8 *needle_str,CHashTable *haystack_table,I64 mask,I64 instance=1);
public _extern _HASH_STR I64 HashStr(U8 *st);
public extern CHashTable *HashTableNew(I64 size,CTask *mem_task=NULL);
#help_index "Hash/Frame"
#help_file "::/Doc/Frame"
public extern I64 FramePtr(U8 *name,CTask *task=NULL);
public extern CHashGeneric *FramePtrAdd(U8 *name,I64 val=0,CTask *task=NULL);
public extern I64 FramePtrDel(U8 *name,CTask *task=NULL);
public extern I64 FramePtrSet(U8 *name,I64 val,CTask *task=NULL);
#help_index "Hash/System"
public extern U0 HashDel(CHashSrcSym *tmph);
public extern CHashGeneric *HashGenericAdd(U8 *name,
I64 type,I64 val=0,I64 u8=0,I64 u16=0,CTask *task=NULL);
public extern CHashGeneric *HashPublic(U8 *st,I64 mask,Bool val=TRUE);
public _extern _HASH_REM_DEL Bool HashRemDel(CHash *tmph,CHashTable *table,
I64 instance=1);//instance must match tmph's
public extern U0 HashTableDel(CHashTable *table);
public extern I64 HashTablePurge(CHashTable *table);
public extern I64 HashTypeNum(CHash *tmph);
public extern I64 HashVal(CHash *tmph);
extern U0 SysSymImportsResolve(U8 *sptr,I64 ld_flags=0);
#help_index "Hash/System;Char/Lists"
public extern I64 HashLstAdd(U8 *lst,I64 type,CHashTable *table);
#help_index "Hash/System;Define;Char/Define;Char/Lists"
public extern I64 HashDefineLstAdd(U8 *dname,I64 type,CHashTable *table);
#help_index "Help System;Debugging/Debugger"
public extern U0 Help();
#help_index "Info;File/Cmd Line (Typically);Cmd Line (Typically);Install"
public extern U0 DrvRep();
#help_index "Install"
#help_file "::/Doc/Install"
extern CATARep *ATARepFind(CATARep *haystack_head,I64 needle_num);
public extern Bool DrvEnable(U8 drv_let,Bool val);
#help_index "Install;File/Cmd Line (Typically);Cmd Line (Typically);"
public extern U0 Fmt(U8 drv_let,Bool quick=TRUE,
Bool confirm=TRUE,I64 type=FSt_FAT32);
#help_index "Install;Memory/BlkPool"
public extern I64 Scale2Mem(I64 min,I64 max,I64 limit=2*1024*1024*1024);
#help_index "Job/Exe;Task/Job/Exe"
public extern U0 AdamErr(U8 *fmt,...);
public extern U0 AdamLog(U8 *fmt,...);
public extern I64 ExeCmdLine(CCmpCtrl *cc);
public extern U0 JobDel(CJob *tmpc);
public extern I64 JobsHndlr(I64 run_flags,CTask *task=NULL);
extern U0 SrvCmdLine();
public extern U0 SrvTaskCont();
public extern CJob *TaskExe(CTask *srv,CTask *master,U8 *data,I64 flags);
public extern U0 TaskRstAwaitingMsg(CTask *task=NULL);
public extern U0 UserTaskCont();
#help_index "Job/Exe;Task/Job/Exe;Compiler"
public extern I64 Adam(U8 *fmt,...);
public extern I64 PopUp(U8 *buf,CTask *parent=NULL,CTask **_pu_task=NULL);
public extern I64 PopUpPrint(U8 *fmt,...);
#help_index "Job/Exe;Task/Job/Exe;MultiCore"
public extern I64 JobResGet(CJob *rqst=NULL);
public extern Bool JobResScan(CJob *rqst=NULL,I64 *_res=NULL);
#help_index "Job/Text & Msgs;Task/Job/Text & Msgs"
public extern CJob *TaskText(CTask *srv,CTask *master,U8 *data,I64 flags);
#help_index "Job/Text & Msgs;Task/Job/Text & Msgs;InFile;StdIn/InFile"
public extern U0 In(U8 *fmt,...);
public extern U0 InFile(U8 *filename);
public extern U0 InStr(U8 *fmt,...);
public extern U0 XTalk(CTask *task,U8 *fmt,...);
public extern U0 XTalkStr(CTask *task,U8 *fmt,...);
public extern U0 XTalkStrWait(CTask *task,U8 *fmt,...);
public extern U0 XTalkWait(CTask *task,U8 *fmt,...);
#help_index "Job/Text & Msgs;Task/Job/Text & Msgs;Messages"
public extern U0 Msg(I64 msg_code,I64 arg1,I64 arg2,I64 flags=0);
public extern U0 PostMsg(CTask *task,
I64 msg_code,I64 arg1,I64 arg2,I64 flags=0);
public extern U0 PostMsgWait(CTask *task,I64 msg_code,
I64 arg1,I64 arg2,I64 flags=0);
public extern CJob *TaskMsg(CTask *srv,CTask *master,
I64 msg_code,I64 arg1,I64 arg2,I64 flags);
#help_index "Job;Task/Job"
#help_file "::/Doc/Job"
#help_index "Keyboard Devices/System;Char/System"
#help_file "::/Doc/KeyDev"
public extern U0 CtrlAltCBSet(U8 ch,U0 (*fp_hndlr)(I64 sc),
U8 *no_shift_desc=NULL,U8 *shift_desc=NULL,Bool in_irq=FALSE);
public extern U0 KeyDescSet(U8 *fmt,...);
public extern CKeyDevEntry *KeyDevAdd(Bool (*fp_put_key)(I64 ch,I64 sc),
Bool (*fp_puts)(U8 *st),I64 priority,Bool key_descs=FALSE);
public extern U0 KeyDevRem(CKeyDevEntry *tmpk);
extern CKeyDevGlbls keydev;
extern CJob sys_macro_head;
extern CTask *sys_macro_task;
#help_index "Keyboard Devices;Char/Input;StdIn"
extern U8 *(*fp_getstr2)(I64 flags=0); //GetStr $LK,"Flags",A="MN:GSF_SHIFT_ESC_EXIT"$
public extern Bool AreYouSure();
public extern I64 GetChar(I64 *_scan_code=NULL,Bool echo=TRUE,
Bool raw_cursor=FALSE);
public extern I64 GetKey(I64 *_scan_code=NULL,Bool echo=FALSE,
Bool raw_cursor=FALSE);
public extern I64 GetS(U8 *buf,I64 size,Bool allow_ext=TRUE);
public extern U8 *GetStr(U8 *msg=NULL,U8 *dft=NULL,I64 flags=0);
extern U0 KbdInit();
public extern I64 KbdMsEvtTime();
extern U0 KbdMsHndlr(Bool poll_kbd,Bool poll_ms);
extern U0 KbdMsInit();
extern I64 KbdMsgsQue();
public extern U0 KbdTypeMatic(U8 delay);
extern Bool MsHardDrvrInstall();
public extern I64 PressAKey();
public extern I64 ScanChar();
public extern Bool ScanKey(I64 *_ch=NULL,I64 *_scan_code=NULL,Bool echo=FALSE);
public extern Bool YorN();
public extern CKbdStateGlbls kbd;
#help_index "Math"
public extern I64 CeilI64(I64 num,I64 to);
public extern U64 CeilU64(U64 num,U64 to);
public extern F64 Clamp(F64 d,F64 lo,F64 hi);
public extern I64 FloorI64(I64 num,I64 to);
public extern U64 FloorU64(U64 num,U64 to);
public extern F64 Max(F64 n1,F64 n2);
public extern F64 Min(F64 n1,F64 n2);
public extern F64 Pow10I64(I64 i);
public extern F64 Rand(); //With timestamp
public extern I16 RandI16();
public extern I32 RandI32();
public extern I64 RandI64();
public extern U16 RandU16();
public extern U32 RandU32();
public extern U64 RandU64();
public extern I64 RoundI64(I64 num,I64 to);
public extern I64 Seed(I64 seed=0,CTask *task=NULL);
#help_index "Memory/Adam Heap"
public extern U8 *ACAlloc(I64 size);
public extern U8 *AMAlloc(I64 size);
public extern U8 *AMAllocIdent(U8 *src);
#help_index "Memory/BlkPool"
public extern U0 BlkPoolAdd(CBlkPool *bp,CMemBlk *m,I64 pags);
public extern U0 BlkPoolInit(CBlkPool *bp,I64 pags);
public extern U8 *MemPagAlloc(I64 pags,CBlkPool *bp=NULL);
public extern U0 MemPagFree(CMemBlk *m,CBlkPool *bp=NULL);
#help_index "Memory/Heap"
public extern U8 *CAlloc(I64 size,CTask *mem_task=NULL);
public extern U8 *CAllocAligned(I64 size,I64 alignment,
CTask *mem_task=NULL,I64 misalignment=0);
public _extern _FREE U0 Free(U8 *addr);
public _extern _MALLOC U8 *MAlloc(I64 size,CTask *mem_task=NULL);
public extern U8 *MAllocAligned(I64 size,I64 alignment,
CTask *mem_task=NULL,I64 misalignment=0);
public extern U8 *MAllocIdent(U8 *src,CTask *mem_task=NULL);
public _extern _MHEAP_CTRL CHeapCtrl *MHeapCtrl(U8 *src);
public _extern _MSIZE I64 MSize(U8 *src); //size of heap object
public _extern _MSIZE2 I64 MSize2(U8 *src); //Internal size
#help_index "Memory/HeapCtrl"
public extern U0 HeapCtrlDel(CHeapCtrl *hc);
public extern CHeapCtrl *HeapCtrlInit(CHeapCtrl *hc=NULL,
CTask *task=NULL,CBlkPool *bp);
#help_index "Memory/Page Tables"
public extern I64 *MemPageTable(U8 *a);
#help_index "Messages"
#help_file "::/Doc/Msgs"
public extern I64 FlushMsgs(CTask *task=NULL);
public extern I64 GetMsg(I64 *_arg1=NULL,I64 *_arg2=NULL,
I64 mask=~1,CTask *task=NULL);
extern U0 InputFilterTask();
public extern I64 ScanMsg(I64 *_arg1=NULL,I64 *_arg2=NULL,
I64 mask=~1,CTask *task=NULL);
#help_index "Misc"
public extern I64 EndianI64(I64 d);
public extern U16 EndianU16(U16 d);
public extern U32 EndianU32(U32 d);
public extern U0 QSort(U8 *base,I64 num, I64 width,
I64 (*fp_compare)(U8 *e1,U8 *e2));
public extern U0 QSortI64(I64 *base,I64 num,
I64 (*fp_compare)(I64 e1,I64 e2));
public extern F64 sys_os_version;
#help_index "Misc/Progress Bars"
public extern U0 ProgressBarsRst(U8 *path=NULL);
#help_index "Mouse"
#help_file "::/Doc/Mouse"
public extern U0 GridInit();
public extern U0 MsSet(I64 x=I64_MAX,I64 y=I64_MAX,I64 z=I64_MAX,
I64 l=I64_MAX,I64 r=I64_MAX);
public extern CMsStateGlbls ms;
public extern CGridGlbls ms_grid;
public extern CMsHardStateGlbls ms_hard;
extern CMsHardStateGlbls ms_hard_last;
extern CMsStateGlbls ms_last;
#help_index "Mouse/Ptr"
extern U0 MsInit();
extern U0 MsUpdate(I64 x,I64 y,I64 z,Bool l,Bool r);
#help_index "MultiCore"
extern U0 Core0StartMP();
extern U0 CoreAPSethTask();
public extern U0 MPInt(U8 num,I64 cpu_num=1);
public extern U0 MPIntAll(U8 num);
public extern U0 MPNMInt();
extern CTask *SpawnQue(U0 (*fp_addr)(U8 *data),U8 *data=NULL,
U8 *task_name=NULL,I64 target_cpu,
CTask *parent=NULL, //NULL means adam
I64 stk_size=0,I64 flags=1<<JOBf_ADD_TO_QUE);
#help_index "MultiCore;Boot"
public extern U0 MPHalt();
#help_index "MultiCore;Job/Exe;Task/Job/Exe"
public extern CJob *JobQue(I64 (*fp_addr)(U8 *data),U8 *data=NULL,
I64 target_cpu=1,I64 flags=1<<JOBf_FREE_ON_COMPLETE,
I64 job_code=JOBT_CALL,U8 *aux_str=NULL,I64 aux1=0,I64 aux2=0);
#help_index "PCI"
public extern I64 PCIClassFind(I64 class_code,I64 n);
public extern U16 PCIReadU16(I64 bus,I64 dev,I64 fun,I64 rg);
public extern U32 PCIReadU32(I64 bus,I64 dev,I64 fun,I64 rg);
public extern U8 PCIReadU8(I64 bus,I64 dev,I64 fun,I64 rg);
public extern U0 PCIWriteU16(I64 bus,I64 dev,I64 fun,I64 rg,I64 val);
public extern U0 PCIWriteU32(I64 bus,I64 dev,I64 fun,I64 rg,I64 val);
public extern U0 PCIWriteU8(I64 bus,I64 dev,I64 fun,I64 rg,I64 val);
public _extern SYS_PCIBIOS_SERVICE_DIR
U32 sys_PCIBIOS_service_dir;//Far call routine in the BIOS
public _extern SYS_PCI_SERVICES
U32 sys_pci_services;//Far call routine in the BIOS
#help_index "PCI;Info;File/System;Devices"
public extern I64 ATARep(Bool pmt=TRUE,
Bool just_ide=FALSE,CATARep **_head=NULL);
#help_index "Processor"
public extern U8 *IntEntryGet(I64 irq);
public extern U8 *IntEntrySet(I64 irq,
U0 (*fp_new_hndlr)(),I64 type=IDTET_IRQ,I64 dpl=0);
#help_index "Snd"
#help_file "::/Doc/Snd"
public extern U0 Beep(I8 ona=62,Bool busy=FALSE);
public extern I8 Freq2Ona(F64 freq);
public extern Bool IsMute();
public extern Bool Mute(Bool val);
public extern F64 Ona2Freq(I64 ona);
public extern U0 Snd(I8 ona=ONA_REST);
public extern U0 SndRst();
public extern CSndGlbls snd;
#help_index "StdIn"
#help_file "::/Doc/Streams"
#help_index "StdOut"
#help_file "::/Doc/Streams"
#help_index "Task"
public extern I64 BirthWait(CTask **_task,I64 task_num=-1);
public extern U0 DeathWait(CTask **_task,Bool send_exit=FALSE);
public extern U0 Exit();
public extern Bool IsSuspended(CTask *task=NULL);
public extern Bool Kill(CTask *task,Bool wait=TRUE,Bool just_break=FALSE);
public extern Bool Suspend(CTask *task=NULL,Bool state=TRUE);
_extern _TASK_CONTEXT_RESTORE U0 TaskContextRestore();
_extern _TASK_END_NOW U0 TaskEndNow();
extern U0 TaskKillDying();
public extern U0 TaskQueIns(CTask *task,CTask *pred=NULL);
public extern U0 TaskQueRem(CTask *task);
public extern Bool TaskValidate(CTask *task);
public extern U0 TaskWait(CTask *task=NULL,Bool cmd_line_pmt=FALSE);
public extern CTask *User(U8 *fmt=NULL,...);
public extern U0 UserCmdLine();
public _extern _YIELD U0 Yield();
public extern CTask *adam_task;
public extern I64 sys_num_spawned_tasks;
extern CTask *sys_winmgr_task,*sys_task_being_scrn_updated;
#help_index "Task/Delay;Time/CPU Cycles"
public extern U0 Busy(I64 æS); //Loosely timed
public extern U0 PortNop(); //On the order of 1uS
extern I64 TimeStampFreqCal();
#help_index "Task/Delay;Time/Jiffies"
public extern U0 Sleep(I64 mS);
public extern U0 SleepUntil(I64 wake_jiffy);
#help_index "Task/Misc"
extern U0 (*fp_update_ctrls)(CTask *task);
public extern U0 TSSBusy(I64 tr,Bool val=OFF);
public extern U0 TaskDerivedValsUpdate(CTask *task=NULL,Bool update_z_buf=TRUE);
public extern U0 WinDerivedValsUpdate(CTask *task);
#help_index "Task;Job/Exe;Task/Job/Exe;MultiCore"
public extern CTask *Spawn(U0 (*fp_addr)(U8 *data),U8 *data=NULL,
U8 *task_name=NULL,I64 target_cpu=-1, //-1 means current CPU
CTask *parent=NULL, //NULL means adam
I64 stk_size=0,I64 flags=1<<JOBf_ADD_TO_QUE);
#help_index "Time/CPU Cycles;Time/HPET;Time/Jiffies"
public extern CCntsGlbls cnts;
#help_index "Time/Date/CDate;Date/CDate"
#help_file "::/Doc/TimeDate"
extern U0 Date2ISO1(CISO1Date *dst,CDate cdt);
public extern U0 Date2Struct(CDateStruct *_ds,CDate cdt);
extern U8 *MPrintDate(CDate cdt);
extern U8 *MPrintTime(CDate cdt);
public extern CDate Now();
public extern CDate Struct2Date(CDateStruct *_ds);
public extern CDate local_time_offset;
#help_index "Time/Date;Date"
#help_file "::/Doc/Date"
public extern I64 DayOfWeek(I64 i);
public extern I64 FirstDayOfMon(I64 i);
public extern I64 FirstDayOfYear(I64 i);
public extern I64 LastDayOfMon(I64 i);
public extern I64 LastDayOfYear(I64 i);
public extern I64 YearStartDate(I64 year);
public extern U16 mon_start_days1[12];
public extern U16 mon_start_days2[12];
#help_index "Time/HPET"
#help_file "::/Doc/TimeHPET"
public extern I64 HPET();
#help_index "Time/Jiffies"
#help_file "::/Doc/TimeJiffy"
public extern I64 SysTimerRead();//18.33333*65536Hz (SYS_TIMER_FREQ)
#help_index "Time/Seconds"
public extern Bool Blink(F64 Hz=2.5);
public extern F64 tS(); //From SysTimerFreq.
#help_index "Windows"
public extern Bool WinInside(I64 x,I64 y,CTask *task=NULL,I64 border=0);
#help_index ""
+219
View File
@@ -0,0 +1,219 @@
U0 PutKey(I64 ch=0,I64 sc=0)
{//See $LK,"Keyboard Devices",A="HI:Keyboard Devices/System"$.
CKeyDevEntry *tmpk;
if (ch||sc) {
tmpk=keydev.put_key_head.next;
if (!Bt(&Fs->display_flags,DISPLAYf_SILENT)) {
if (kbd.scan_code & SCF_SCROLL && sys_focus_task==Fs)
while (kbd.scan_code & SCF_SCROLL)
Yield; //Wait on SCROLL LOCK Key
while (tmpk!=&keydev.put_key_head) {
if ((!(sc&SCF_KEY_DESC) || tmpk->flags & KDF_HAS_DESCS) &&
(*tmpk->put_key)(ch,sc))
break;
tmpk=tmpk->next;
}
}
}
}
U0 PutChars(U64 ch)
{//Output chars. Up to 8 chars in a single U64.
//Don't use this. $LK,"See Print() shortcut.",A="FF:::/Doc/HolyC.DD,DemoHolyC"$
while (ch) {
PutKey(ch&255,0);
ch>>=8;
}
}
U0 PutS(U8 *st)
{//Use $LK,"Print",A="MN:Print"$(). See $LK,"Keyboard Devices",A="HI:Keyboard Devices/System"$.
//Don't use this. $LK,"See Print() shortcut.",A="FF:::/Doc/HolyC.DD,DemoHolyC"$
I64 ch;
U8 *ptr;
Bool cont=TRUE;
if (!st) return;
CKeyDevEntry *tmpk=keydev.put_key_head.next;
if (!Bt(&Fs->display_flags,DISPLAYf_SILENT)) {
if (kbd.scan_code & SCF_SCROLL && sys_focus_task==Fs)
while (kbd.scan_code & SCF_SCROLL)
Yield;
while (cont && tmpk!=&keydev.put_key_head) {
if (tmpk->put_s) {
if ((*tmpk->put_s)(st))
break;
} else {
ptr=st;
while (ch=*ptr++)
if ((*tmpk->put_key)(ch,0))
cont=FALSE;
}
tmpk=tmpk->next;
}
}
}
U0 KeyDescSet(U8 *fmt,...)
{//Call this from key hndlr to report desc in $LK,"KeyMap",A="MN:KeyMap"$().
U8 *buf=StrPrintJoin(NULL,fmt,argc,argv);
StrCpy(keydev.desc,buf);
keydev.hndlr=Caller;
Free(buf);
}
U0 KeyDevRem(CKeyDevEntry *tmpk)
{//Remove StdOut hook and free.
QueRem(tmpk);
Free(tmpk);
}
CKeyDevEntry *KeyDevAdd(Bool (*fp_put_key)(I64 ch,I64 sc),
Bool (*fp_puts)(U8 *st),I64 priority,Bool key_descs=FALSE)
{//Places hook in StdOut chain. See $LK,"Keyboard Devices",A="HI:Keyboard Devices/System"$.
CKeyDevEntry *tmpk=keydev.put_key_head.last,
*tmpk1=ACAlloc(sizeof(CKeyDevEntry));
tmpk1->put_key=fp_put_key;
tmpk1->put_s=fp_puts;
tmpk1->priority=priority;
if (key_descs)
tmpk1->flags|=KDF_HAS_DESCS;
while (tmpk->priority>priority)
tmpk=tmpk->last;
QueIns(tmpk1,tmpk);
if (tmpk->priority==priority)
KeyDevRem(tmpk);
return tmpk1;
}
Bool KDRawPutKey(I64 ch,I64)
{
if (IsRaw) {
RawPutChar(ch);
return TRUE;
} else
return FALSE;
}
Bool KDRawPutS(U8 *st)
{
I64 ch;
if (IsRaw) {
while (ch=*st++)
RawPutChar(ch);
return TRUE;
} else
return FALSE;
}
Bool KDInputFilterPutKey(I64 ch,I64 scan_code)
{
if (Bt(&Fs->task_flags,TASKf_INPUT_FILTER_TASK)) {
Msg(MSG_KEY_DOWN,ch,scan_code);
return TRUE;
} else
return FALSE;
}
Bool KDInputFilterPutS(U8 *st)
{
I64 ch;
if (Bt(&Fs->task_flags,TASKf_INPUT_FILTER_TASK)) {
while (ch=*st++)
Msg(MSG_KEY_DOWN,ch,0);
return TRUE;
} else
return FALSE;
}
U0 CtrlAltDel(I64)
{
LBts(sys_ctrl_alt_flags,CTRL_ALT_DEL);
}
U0 CtrlAltC(I64)
{
LBts(sys_ctrl_alt_flags,CTRL_ALT_C);
}
U0 CtrlAltD(I64)
{
if (!IsDbgMode) {
if (Fs==Gs->idle_task)
BptS(sys_winmgr_task->rip,sys_winmgr_task);
else
BptS(*keydev.ctrl_alt_ret_addr);
}
}
U0 CtrlAltF(I64)
{
SwapI64(&text.font,&text.aux_font);
}
U0 CtrlAltM(I64)
{
Mute(!IsMute);
}
U0 CtrlAltN(I64)
{
LBts(sys_ctrl_alt_flags,CTRL_ALT_TAB);
}
U0 CtrlAltT(I64)
{
User;
}
U0 CtrlAltV(I64)
{
VGAFlush;
}
U0 CtrlAltX(I64)
{
LBts(sys_ctrl_alt_flags,CTRL_ALT_X);
}
U0 CtrlAltCBSet(U8 ch,U0 (*fp_hndlr)(I64 sc),
U8 *no_shift_desc=NULL,U8 *shift_desc=NULL,Bool in_irq=FALSE)
{//Set callback for <CTRL-ALT-letter>.
ch=ToUpper(ch)-'A';
if (ch<26) {
keydev.fp_ctrl_alt_cbs[ch]=fp_hndlr;
Free(keydev.ctrl_alt_no_shift_descs[ch]);
if (no_shift_desc)
keydev.ctrl_alt_no_shift_descs[ch]=AStrNew(no_shift_desc);
else
keydev.ctrl_alt_no_shift_descs[ch]=NULL;
Free(keydev.ctrl_alt_shift_descs[ch]);
if (shift_desc)
keydev.ctrl_alt_shift_descs[ch]=AStrNew(shift_desc);
else
keydev.ctrl_alt_shift_descs[ch]=NULL;
BEqu(&keydev.ctrl_alt_in_irq_flags,ch,in_irq);
}
}
U0 KeyDevInit()
{
keydev.fp_ctrl_alt_cbs =CAlloc(26*sizeof(U8 *));
keydev.ctrl_alt_no_shift_descs=CAlloc(26*sizeof(U8 *));
keydev.ctrl_alt_shift_descs =CAlloc(26*sizeof(U8 *));
keydev.ctrl_alt_in_irq_flags =0;
MemSet(&keydev.put_key_head,0,sizeof(CKeyDevEntry));
QueInit(&keydev.put_key_head);
KeyDevAdd(&KDInputFilterPutKey,&KDInputFilterPutS,0x40000000,FALSE);
KeyDevAdd(&KDRawPutKey,&KDRawPutS,0x60000000,FALSE);
CtrlAltCBSet('C',&CtrlAltC,"Cmd /Break Execution",,TRUE);
CtrlAltCBSet('D',&CtrlAltD,"Cmd /Enter Debugger",,TRUE);
CtrlAltCBSet('F',&CtrlAltF,"Cmd /Toggle Aux Font");
CtrlAltCBSet('M',&CtrlAltM,"Cmd /Toggle Mute");
CtrlAltCBSet('N',&CtrlAltN,"Cmd /Next Focus Task",,TRUE);
CtrlAltCBSet('T',&CtrlAltT,"Cmd /Terminal Window");
CtrlAltCBSet('V',&CtrlAltV,"Cmd /VGA Flush",,TRUE);
CtrlAltCBSet('X',&CtrlAltX,"Cmd /Kill Focused Task",,TRUE);
}
+73
View File
@@ -0,0 +1,73 @@
U0 BlkPoolAdd(CBlkPool *bp,CMemBlk *m,I64 pags)
{//Add mem to BlkPool.
if (sys_mem_init_flag)
MemSet(m,sys_mem_init_val,pags*MEM_PAG_SIZE);
PUSHFD
CLI
while (LBts(&bp->locked_flags,BPlf_LOCKED))
PAUSE
m->next=bp->mem_free_lst;
m->pags=pags;
m->mb_signature=MBS_UNUSED_SIGNATURE_VAL;
bp->alloced_u8s+=pags<<MEM_PAG_BITS;
bp->mem_free_lst=m;
LBtr(&bp->locked_flags,BPlf_LOCKED);
POPFD
}
U0 BlkPoolInit(CBlkPool *bp,I64 pags)
{//Make mem chunk into a BlkPool.
I64 num;
CMemBlk *m;
MemSet(bp,0,sizeof(CBlkPool));
m=(bp(U8 *)+sizeof(CBlkPool)+MEM_PAG_SIZE-1)&~(MEM_PAG_SIZE-1);
num=(bp(U8 *)+pags<<MEM_PAG_BITS-m(U8 *))>>MEM_PAG_BITS;
bp->alloced_u8s=(pags-num)<<MEM_PAG_BITS; //Compensate before num added.
BlkPoolAdd(bp,m,num);
}
U0 BlkPoolsInit()
{
I64 i,total,lo,hi,code_heap_limit;
CMemE820 *m20=MEM_E820;
Bool first=TRUE;
total=BIOSTotalMem;
if (total<=0x80000000)
code_heap_limit=total;
else if (total<=0x100000000)
code_heap_limit=total/4;
else
code_heap_limit=0x80000000;
i=code_heap_limit-SYS_16MEG_AREA_LIMIT; //See $LK,"RLf_16MEG_SYS_CODE_BP",A="FF:::/Kernel/Mem/PageTables.HC,RLf_16MEG_SYS_CODE_BP"$
BlkPoolAdd(sys_code_bp,SYS_16MEG_AREA_LIMIT,i>>MEM_PAG_BITS);
mem_heap_limit=i+SYS_16MEG_AREA_LIMIT-1;
if (code_heap_limit<total) {
while (m20->type) {
if (m20->type==1) {
lo=m20->base;
hi=m20->base+m20->len;
if (lo<code_heap_limit) {
if (hi>code_heap_limit)
lo=code_heap_limit;
else
hi=lo; //cancel
}
if (code_heap_limit<=lo<hi) {
if (first) {
BlkPoolInit(lo,(hi-lo)>>MEM_PAG_BITS);
sys_data_bp=lo;
Fs->data_heap=HeapCtrlInit(,Fs,sys_data_bp);
first=FALSE;
} else
BlkPoolAdd(sys_data_bp,lo,(hi-lo)>>MEM_PAG_BITS);
}
}
m20++;
}
}
LBts(&sys_run_level,RLf_FULL_HEAPS);
}
+33
View File
@@ -0,0 +1,33 @@
CHeapCtrl *HeapCtrlInit(CHeapCtrl *hc=NULL,CTask *task=NULL,CBlkPool *bp)
{//See $LK,"HeapLog",A="MN:HeapLog"$() for an example.
//Duplicated for $LK,"Adam Task",A="FF:::/Kernel/KStart64.HC,CHeapCtrl.bp"$.
if (!hc)
hc=ACAlloc(sizeof(CHeapCtrl));
hc->hc_signature=HEAP_CTRL_SIGNATURE_VAL;
hc->mem_task=task;
hc->bp=bp;
QueInit(&hc->next_mem_blk);
hc->last_mergable=NULL;
hc->next_um=hc->last_um=(&hc->next_um)(U8 *)-offset(CMemUsed.next);
return hc;
}
U0 HeapCtrlDel(CHeapCtrl *hc)
{//Free all blks alloced to a HeapCtrl.
CMemBlk *m,*m1;
if (hc) {
PUSHFD
CLI
while (LBts(&hc->locked_flags,HClf_LOCKED))
PAUSE
m=hc->next_mem_blk;
while (m!=&hc->next_mem_blk) {
m1=m->next;
MemPagTaskFree(m,hc);
m=m1;
}
LBtr(&hc->locked_flags,HClf_LOCKED);
POPFD
Free(hc);
}
}
+464
View File
@@ -0,0 +1,464 @@
asm {
//************************************
//See $LK,"::/Doc/Credits.DD"$.
_MALLOC::
// Throws 'OutMem'
PUSH RBP
MOV RBP,RSP
PUSH RSI
PUSH RDI
XOR RBX,RBX
MOV RDX,U64 SF_ARG2[RBP]
TEST RDX,RDX
JNZ @@05
MOV RDX,U64 FS:CTask.addr[RBX]
@@05: CMP U32 CTask.task_signature[RDX],TASK_SIGNATURE_VAL
#assert CTask.task_signature==CHeapCtrl.hc_signature //location signature same
JNE @@10
MOV RDX,U64 CTask.data_heap[RDX]
@@10: CMP U32 CHeapCtrl.hc_signature[RDX],HEAP_CTRL_SIGNATURE_VAL
JE @@15
PUSH RDX
CALL &SysBadMAlloc
JMP I32 _SYS_HLT
@@15: MOV RAX,U64 SF_ARG1[RBP]
PUSHFD
ADD RAX,CMemUsed.start+7 //round-up to I64
AND AL,0xF8
#assert CMemUsed.start>=sizeof(CMemUnused)
CMP RAX,CMemUsed.start
JAE @@20
MOV RAX,CMemUsed.start
@@20:
CLI
@@25: LOCK
BTS U32 CHeapCtrl.locked_flags[RDX],HClf_LOCKED
PAUSE //don't know if this inst helps
JC @@25
CMP RAX,MEM_HEAP_HASH_SIZE
JAE @@30
MOV RSI,U64 CHeapCtrl.heap_hash[RAX+RDX]
TEST RSI,RSI
JZ @@35
MOV RCX,U64 CMemUnused.next[RSI]
MOV U64 CHeapCtrl.heap_hash[RAX+RDX],RCX
JMP I32 MALLOC_ALMOST_DONE
//Big allocation
@@30: ADD RAX,sizeof(CMemBlk)+MEM_PAG_SIZE-1
SHR RAX,MEM_PAG_BITS
PUSH RDX //preserve HeapCtrl
PUSH RDX
PUSH RAX
CALL &MemPagTaskAlloc
POP RDX
TEST RAX,RAX
JZ @@45 //Out of memory
MOV RSI,RAX
MOV EAX,U32 CMemBlk.pags[RSI]
SHL RAX,MEM_PAG_BITS
SUB RAX,sizeof(CMemBlk)
ADD RSI,sizeof(CMemBlk)
JMP I32 MALLOC_ALMOST_DONE
//Little allocation, chunk-off piece from free lst chunks
@@35: LEA RSI,U64 CHeapCtrl.malloc_free_lst-CMemUnused.next[RDX]
@@40: MOV RBX,RSI
MOV RSI,U64 CMemUnused.next[RBX]
TEST RSI,RSI
JNZ I32 @@60
PUSH RAX //-**** save byte size
ADD RAX,16*MEM_PAG_SIZE-1
SHR RAX,MEM_PAG_BITS
PUSH RDX //preserve HeapCtrl
PUSH RDX
PUSH RAX
CALL &MemPagTaskAlloc
POP RDX
TEST RAX,RAX
JNZ @@50
//Out of memory
@@45: LOCK
BTR U32 CHeapCtrl.locked_flags[RDX],HClf_LOCKED
POPFD
PUSH TRUE
MOV RAX,'OutMem'
PUSH RAX
CALL I32 &throw
JMP I32 MALLOC_FINAL_EXIT //Never gets here, hopefully.
@@50: MOV RSI,RAX
MOV EAX,U32 CMemBlk.pags[RSI]
SHL RAX,MEM_PAG_BITS
//Can it be combined with last chunk? (Never Free these chunks.)
MOV RDI,U64 CHeapCtrl.last_mergable[RDX]
LEA RBX,U64 [RSI+RAX]
CMP RDI,RBX
JNE @@55
PUSH RAX
MOV EAX,U32 CMemBlk.pags[RDI]
ADD U32 CMemBlk.pags[RSI],EAX
//QueRem
MOV RAX,U64 CMemBlk.next[RDI]
MOV RBX,U64 CMemBlk.last[RDI]
MOV U64 CMemBlk.last[RAX],RBX
MOV U64 CMemBlk.next[RBX],RAX
POP RAX
@@55: MOV U64 CHeapCtrl.last_mergable[RDX],RSI
LEA RSI,U64 sizeof(CMemBlk)[RSI]
SUB RAX,sizeof(CMemBlk)
LEA RBX,U64 CHeapCtrl.malloc_free_lst-CMemUnused.next[RDX]
MOV RDI,U64 CMemUnused.next[RBX]
MOV U64 CMemUnused.next[RSI],RDI
MOV U64 CMemUnused.size[RSI],RAX
MOV U64 CMemUnused.next[RBX],RSI
POP RAX //+****
JMP @@70
@@60: CMP U64 CMemUnused.size[RSI],RAX
JB I32 @@40
JNE @@70
@@65: MOV RDI,U64 CMemUnused.next[RSI]
MOV U64 CMemUnused.next[RBX],RDI
JMP MALLOC_ALMOST_DONE
@@70: SUB U64 CMemUnused.size[RSI],RAX //UPDATE FREE ENTRY
CMP U64 CMemUnused.size[RSI],sizeof(CMemUnused)
JAE @@75 //take from top of block
ADD U64 CMemUnused.size[RSI],RAX //doesn't fit, undo
JMP I32 @@40
@@75: ADD RSI,U64 CMemUnused.size[RSI]
MALLOC_ALMOST_DONE:
//RSI=res-CMemUsed.size
//RAX=size+CMemUsed.size
//RDX=HeapCtrl
ADD U64 CHeapCtrl.used_u8s[RDX],RAX
#if _CFG_HEAP_DBG
//QueIns
MOV RDI,U64 CHeapCtrl.last_um[RDX]
MOV U64 CMemUsed.next[RDI],RSI
MOV U64 CHeapCtrl.last_um[RDX],RSI
MOV U64 CMemUsed.last[RSI],RDI
LEA RDI,U64 CHeapCtrl.next_um-CMemUsed.next[RDX]
MOV U64 CMemUsed.next[RSI],RDI
//Caller1/Caller2
PUSH RDX
MOV RDX,U64 [MEM_HEAP_LIMIT]
MOV RDI,U64 SF_RIP[RBP]
CMP RDI,RDX
JB @@80
XOR RDI,RDI
MOV U64 CMemUsed.caller1[RSI],RDI
JMP @@90
@@80: MOV U64 CMemUsed.caller1[RSI],RDI
MOV RDI,U64 SF_RBP[RBP]
CMP RDI,RDX
JB @@85
XOR RDI,RDI
JMP @@90
@@85: MOV RDI,U64 SF_RIP[RDI]
CMP RDI,RDX
JB @@90
XOR RDI,RDI
@@90: MOV U64 CMemUsed.caller2[RSI],RDI
POP RDX
#endif
LOCK
BTR U32 CHeapCtrl.locked_flags[RDX],HClf_LOCKED
POPFD
MOV U64 CMemUsed.size[RSI],RAX
MOV U64 CMemUsed.hc[RSI],RDX
LEA RAX,U64 CMemUsed.start[RSI]
TEST U8 [SYS_SEMAS+SEMA_HEAPLOG_ACTIVE*DFT_CACHE_LINE_WIDTH],1
JZ @@105
PUSH RAX
PUSH RAX
MOV RAX,U64 [SYS_EXTERN_TABLE]
MOV RAX,U64 EXT_HEAPLOG_MALLOC*8[RAX]
TEST RAX,RAX
JZ @@95
CALL RAX
JMP @@100
@@95: ADD RSP,8
@@100: POP RAX
@@105: TEST U8 [SYS_HEAP_INIT_FLAG],1
JZ MALLOC_FINAL_EXIT
PUSH RAX
MOV RCX,U64 CMemUsed.size-CMemUsed.start[RAX]
SUB RCX,CMemUsed.start
MOV RDI,RAX
MOV AL,U8 [SYS_HEAP_INIT_VAL]
REP_STOSB
POP RAX
MALLOC_FINAL_EXIT:
POP RDI
POP RSI
POP RBP
RET1 16
//************************************
_FREE::
//Be aware of $LK,"heap_hash",A="FF:::/Kernel/Mem/MAllocFree.HC,heap_hash"$ in $LK,"MemPagTaskAlloc",A="MN:MemPagTaskAlloc"$().
PUSH RBP
MOV RBP,RSP
PUSH RSI
PUSH RDI
TEST U8 [SYS_SEMAS+SEMA_HEAPLOG_ACTIVE*DFT_CACHE_LINE_WIDTH],1
JZ @@15
MOV RBX,U64 SF_ARG1[RBP]
TEST RBX,RBX
JZ @@05
MOV RAX,U64 CMemUsed.size-CMemUsed.start[RBX]
TEST RAX,RAX
JGE @@05 //Aligned alloced chunks have neg size
ADD RBX,RAX
@@05: PUSH RBX
MOV RAX,U64 [SYS_EXTERN_TABLE]
MOV RAX,U64 EXT_HEAPLOG_FREE*8[RAX]
TEST RAX,RAX
JZ @@10
CALL RAX
JMP @@15
@@10: ADD RSP,8
@@15: MOV RSI,U64 SF_ARG1[RBP]
TEST RSI,RSI
#if _CFG_HEAP_DBG
JZ I32 FREE_DONE
#else
JZ FREE_DONE
#endif
MOV RAX,U64 CMemUsed.size-CMemUsed.start[RSI]
TEST RAX,RAX
JGE @@20 //Aligned alloced chunks have neg size.
//The neg size is offset to start of $LK,"CMemUsed",A="MN:CMemUsed"$ struct.
ADD RSI,RAX
@@20: PUSHFD
SUB RSI,CMemUsed.start
MOV RDX,U64 CMemUsed.hc[RSI]
CMP U32 CHeapCtrl.hc_signature[RDX],HEAP_CTRL_SIGNATURE_VAL
JE @@25
ADD RSI,CMemUsed.start
PUSH RSI
CALL &SysBadFree
JMP I32 _SYS_HLT
@@25: MOV RAX,U64 CMemUsed.size[RSI]
SUB U64 CHeapCtrl.used_u8s[RDX],RAX
CLI
@@30: LOCK
BTS U32 CHeapCtrl.locked_flags[RDX],HClf_LOCKED
PAUSE
JC @@30
#if _CFG_HEAP_DBG
//QueRem
MOV RDX,U64 CMemUsed.next[RSI]
MOV RDI,U64 CMemUsed.last[RSI]
MOV U64 CMemUsed.last[RDX],RDI
MOV U64 CMemUsed.next[RDI],RDX
//Caller1/Caller2
MOV RDX,U64 [MEM_HEAP_LIMIT]
MOV RDI,U64 SF_RIP[RBP]
CMP RDI,RDX
JB @@35
XOR RDI,RDI
MOV U64 CMemUnused.caller1[RSI],RDI
JMP @@45
@@35: MOV U64 CMemUnused.caller1[RSI],RDI
MOV RDI,U64 SF_RBP[RBP]
CMP RDI,RDX
JB @@40
XOR RDI,RDI
JMP @@45
@@40: MOV RDI,U64 SF_RIP[RDI]
CMP RDI,RDX
JB @@45
XOR RDI,RDI
@@45: MOV U64 CMemUnused.caller2[RSI],RDI
MOV RDX,U64 CMemUsed.hc[RSI]
#endif
CMP RAX,MEM_HEAP_HASH_SIZE
JAE @@50
#assert CMemUnused.size==CMemUsed.size
// MOV U64 CMemUnused.size[RSI],RAX
MOV RBX,U64 CHeapCtrl.heap_hash[RAX+RDX]
MOV U64 CMemUnused.next[RSI],RBX
MOV U64 CHeapCtrl.heap_hash[RAX+RDX],RSI
JMP @@55
@@50: SUB RSI,sizeof(CMemBlk)
PUSH RDX
PUSH RDX
PUSH RSI
CALL &MemPagTaskFree
POP RDX
@@55: LOCK
BTR U32 CHeapCtrl.locked_flags[RDX],HClf_LOCKED
POPFD
FREE_DONE:
POP RDI
POP RSI
POP RBP
RET1 8
//************************************
_MSIZE::
PUSH RBP
MOV RBP,RSP
MOV RBX,U64 SF_ARG1[RBP]
XOR RAX,RAX
TEST RBX,RBX
JZ @@10
MOV RAX,U64 CMemUsed.size-CMemUsed.start[RBX]
TEST RAX,RAX
JGE @@05 //Aligned alloced chunks have neg size
ADD RBX,RAX
MOV RAX,U64 CMemUsed.size-CMemUsed.start[RBX]
@@05: SUB RAX,CMemUsed.start
@@10: POP RBP
RET1 8
//************************************
_MSIZE2::
PUSH RBP
MOV RBP,RSP
MOV RBX,U64 SF_ARG1[RBP]
XOR RAX,RAX
TEST RBX,RBX
JZ @@10
MOV RAX,U64 CMemUsed.size-CMemUsed.start[RBX]
TEST RAX,RAX
JGE @@05 //Aligned alloced chunks have neg size
ADD RBX,RAX
@@05: MOV RAX,U64 CMemUsed.size-CMemUsed.start[RBX]
@@10: POP RBP
RET1 8
//************************************
_MHEAP_CTRL::
PUSH RBP
MOV RBP,RSP
MOV RBX,U64 SF_ARG1[RBP]
XOR RAX,RAX
TEST RBX,RBX
JZ @@10
MOV RAX,U64 CMemUsed.size-CMemUsed.start[RBX]
TEST RAX,RAX
JGE @@05 //Aligned alloced chunks have neg size
ADD RBX,RAX
@@05: MOV RAX,U64 CMemUsed.hc-CMemUsed.start[RBX]
@@10: POP RBP
RET1 8
}
_extern _FREE U0 Free(U8 *addr); //Free $LK,"MAlloc",A="MN:MAlloc"$()ed memory chunk.
_extern _MSIZE I64 MSize(U8 *src); //Size of heap object.
_extern _MSIZE2 I64 MSize2(U8 *src); //Internal size of heap object.
_extern _MHEAP_CTRL CHeapCtrl *MHeapCtrl(U8 *src); //$LK,"CHeapCtrl",A="MN:CHeapCtrl"$ of object.
_extern _MALLOC U8 *MAlloc(I64 size,CTask *mem_task=NULL); //Alloc memory chunk.
//Accepts a $LK,"CTask",A="MN:CTask"$ or $LK,"CHeapCtrl",A="MN:CHeapCtrl"$. NULL allocs off current task's heap.
U8 *AMAlloc(I64 size)
{//Alloc memory in Adam's heap.
return MAlloc(size,adam_task);
}
U8 *CAlloc(I64 size,CTask *mem_task=NULL)
{//Accepts a $LK,"CTask",A="MN:CTask"$ or $LK,"CHeapCtrl",A="MN:CHeapCtrl"$. NULL allocs off current task's heap.
U8 *res=MAlloc(size,mem_task);
MemSet(res,0,size);
return res;
}
U8 *ACAlloc(I64 size)
{//Alloc and set to zero memory in Adam's heap.
return CAlloc(size,adam_task);
}
U8 *MAllocIdent(U8 *src,CTask *mem_task=NULL)
{//Accepts a $LK,"CTask",A="MN:CTask"$ or $LK,"CHeapCtrl",A="MN:CHeapCtrl"$. NULL allocs off current task's heap.
U8 *res;
I64 size;
if (!src) return NULL;
size=MSize(src);
res=MAlloc(size,mem_task);
MemCpy(res,src,size);
return res;
}
U8 *AMAllocIdent(U8 *src)
{//Alloc in Adam's heap, ident copy of heap node.
return MAllocIdent(src,adam_task);
}
U8 *MAllocAligned(I64 size,I64 alignment,
CTask *mem_task=NULL,I64 misalignment=0)
{//Only powers of two alignment. This is awful.
I64 mask=alignment-1;
U8 *ptr=MAlloc(size+mask+sizeof(I64)+misalignment,mem_task),
*res=(ptr+sizeof(I64)+mask)&~mask+misalignment;
res(I64 *)[-1]=ptr-res;
#assert offset(CMemUsed.size)==offset(CMemUsed.start)-sizeof(I64)
return res;
}
U8 *CAllocAligned(I64 size,I64 alignment,
CTask *mem_task=NULL,I64 misalignment=0)
{//Only powers of two alignment. This is awful.
I64 mask=alignment-1;
U8 *ptr=MAlloc(size+mask+sizeof(I64)+misalignment,mem_task),
*res=(ptr+sizeof(I64)+mask)&~mask+misalignment;
res(I64 *)[-1]=ptr-res;
#assert offset(CMemUsed.size)==offset(CMemUsed.start)-sizeof(I64)
MemSet(res,0,size);
return res;
}
U8 *StrNew(U8 *buf,CTask *mem_task=NULL)
{//Accepts a $LK,"CTask",A="MN:CTask"$ or $LK,"CHeapCtrl",A="MN:CHeapCtrl"$. NULL allocs off current task's heap.
U8 *res;
I64 size;
if (buf) {
size=StrLen(buf)+1;
res=MAlloc(size,mem_task);
MemCpy(res,buf,size);
} else {
res=MAlloc(1,mem_task);
*res=0;
}
return res;
}
U8 *AStrNew(U8 *buf)
{//Alloc copy of string in Adam's heap.
return StrNew(buf,adam_task);
}
+8
View File
@@ -0,0 +1,8 @@
#exe {Cd(__DIR__);};
#include "PageTables"
#include "MemPag"
#include "BlkPool"
#include "MAllocFree"
#include "HeapCtrl"
#include "MemPhysical"
#exe {Cd("..");};
+167
View File
@@ -0,0 +1,167 @@
U0 SysBadFree(I64 *ptr)
{
Panic("Bad Free:",ptr);
}
U0 SysBadMAlloc(I64 *ptr)
{
Panic("Bad MAlloc:",ptr);
}
U8 *MemPagAlloc(I64 pags,CBlkPool *bp=NULL)
{/*Alloc pags from BlkPool. Don't link to task.
(Linking to a task means they will be freed when the task dies.)
It might give you more than you asked for.
Return: NULL if out of memory.
*/
CMemBlk *res=NULL,*m;
I64 i;
if (!bp) bp=sys_code_bp;
PUSHFD
CLI
while (LBts(&bp->locked_flags,BPlf_LOCKED))
PAUSE
if (pags<MEM_FREE_PAG_HASH_SIZE) {
if (res=bp->free_pag_hash[pags]) {
bp->free_pag_hash[pags]=res->next;
goto at_done;
}
i=Bsr(MEM_FREE_PAG_HASH_SIZE)+1;
} else {
//We'll now round-up to a power of two.
//There is some overhead on allocations and
//we wouldn't want to round to the next
//power of two if a power of two was requested.
//So we use a little more than a power of two.
pags-=MEM_EXTRA_HASH2_PAGS;
i=Bsr(pags)+1;
pags=1<<i+MEM_EXTRA_HASH2_PAGS;
if (res=bp->free_pag_hash2[i]) {
bp->free_pag_hash2[i]=res->next;
goto at_done;
}
}
m=&bp->mem_free_lst;
while (TRUE) {
if (!(res=m->next)) {
//We're probably out of luck, but lets search for a
//freed larger size block... and, screw-it, return the whole thing.
do {
if (res=bp->free_pag_hash2[++i]) {
pags=1<<i+MEM_EXTRA_HASH2_PAGS;
bp->free_pag_hash2[i]=res->next;
goto at_done;
}
} while (i<64-MEM_PAG_BITS-1);
pags=0;
res=NULL; //Out of memory
goto at_done2;
}
if (res->pags<pags)
m=res;
else {
if (res->pags==pags) {
m->next=res->next;
goto at_done;
} else {
res->pags-=pags;
res(U8 *)+=res->pags<<MEM_PAG_BITS;
res->pags=pags;
goto at_done;
}
}
}
at_done:
bp->used_u8s+=res->pags<<MEM_PAG_BITS;
at_done2:
LBtr(&bp->locked_flags,BPlf_LOCKED);
POPFD
return res;
}
U0 MemPagFree(CMemBlk *m,CBlkPool *bp=NULL)
{//Return non-task pags to BlkPool.
I64 i,pags;
if (m) {
if (!bp) bp=sys_code_bp;
PUSHFD
CLI
while (LBts(&bp->locked_flags,BPlf_LOCKED))
PAUSE
pags=m->pags;
m->mb_signature=MBS_UNUSED_SIGNATURE_VAL;
bp->used_u8s-=pags<<MEM_PAG_BITS;
if (pags<MEM_FREE_PAG_HASH_SIZE) {
m->next=bp->free_pag_hash[pags];
bp->free_pag_hash[pags]=m;
} else {
//We'll now round-up to a power of two.
//There is some overhead on allocations and
//we wouldn't want to round to the next
//power of two if a power of two was requested.
//So we use a little more than a power of two.
pags-=MEM_EXTRA_HASH2_PAGS;
i=Bsr(pags);
m->next=bp->free_pag_hash2[i];
bp->free_pag_hash2[i]=m;
}
LBtr(&bp->locked_flags,BPlf_LOCKED);
POPFD
}
}
CMemBlk *MemPagTaskAlloc(I64 pags,CHeapCtrl *hc)
{/*hc must be locked. Don't preempt this routine.
Currently, this is only called from $LK,"MAlloc",A="MN:MAlloc"$().
Return: NULL if out of memory.
*/
CMemBlk *res;
I64 threshold,cnt,size;
CMemUnused *uum,**_uum,**_ptr;
if (res=MemPagAlloc(pags,hc->bp)) {
QueIns(res,hc->last_mem_blk);
res->mb_signature=MBS_USED_SIGNATURE_VAL;
hc->alloced_u8s+=res->pags<<MEM_PAG_BITS;
//Tidy-up free lst (Move into heap hash)
//because if free lst gets long, delay causes crash.
threshold=MEM_HEAP_HASH_SIZE>>4;
#assert MEM_HEAP_HASH_SIZE>>4>=sizeof(U8 *)
do {
cnt=0;
_uum=&hc->malloc_free_lst;
while (uum=*_uum) {
#assert !offset(CMemUnused.next)
size=uum->size;
if (size<threshold) {
*_uum=uum->next;
_ptr=(&hc->heap_hash)(U8 *)+size;
uum->next=*_ptr;
*_ptr=uum;
} else {
cnt++;
_uum=uum;
}
}
threshold<<=1;
} while (cnt>8 && threshold<=MEM_HEAP_HASH_SIZE);
}
return res;
}
U0 MemPagTaskFree(CMemBlk *m,CHeapCtrl *hc)
{//hc must be locked
if (m) {
PUSHFD
CLI
if (m->mb_signature!=MBS_USED_SIGNATURE_VAL)
SysBadFree(m);
else {
QueRem(m);
hc->alloced_u8s-=m->pags<<MEM_PAG_BITS;
MemPagFree(m,hc->bp);
}
POPFD
}
}
+181
View File
@@ -0,0 +1,181 @@
Bool Mem32DevIns(CMemRange *tmpmr)
{
CMemRange *tmpmr1=dev.mem32_head.next,*tmpmr2;
while (tmpmr1!=&dev.mem32_head) {
if (!tmpmr1->type && tmpmr->base>=tmpmr1->base &&
tmpmr->base+tmpmr->size<=tmpmr1->base+tmpmr1->size) {
if (tmpmr->base>tmpmr1->base) {
tmpmr2=AMAlloc(sizeof(CMemRange));
tmpmr2->type=MRT_UNUSED;
tmpmr2->flags=0;
tmpmr2->base=tmpmr1->base;
tmpmr2->size=tmpmr->base-tmpmr1->base;
QueInsRev(tmpmr2,tmpmr1);
}
QueInsRev(tmpmr,tmpmr1);
tmpmr1->size=tmpmr1->base+tmpmr1->size-
(tmpmr->base+tmpmr->size);
tmpmr1->base=tmpmr->base+tmpmr->size;
if (!tmpmr1->size) {
QueRem(tmpmr1);
Free(tmpmr1);
}
return TRUE;
}
tmpmr1=tmpmr1->next;
}
return FALSE;
}
U0 Mem32DevInit()
{
CMemRange *tmpmr;
CMemE820 *m20=MEM_E820;
QueInit(&dev.mem32_head);
tmpmr=AMAlloc(sizeof(CMemRange));
tmpmr->type=MRT_UNUSED;
tmpmr->flags=0;
//Maybe !!! Change this to 0xF0000000 !!!
tmpmr->base=0xE0000000;
tmpmr->size=0x10000000;
QueIns(tmpmr,dev.mem32_head.last);
if (m20->type) {
while (m20->type) {
tmpmr=AMAlloc(sizeof(CMemRange));
tmpmr->type=m20->type;
tmpmr->flags=0;
tmpmr->base=m20->base;
tmpmr->size=m20->len;
if (!Mem32DevIns(tmpmr))
Free(tmpmr);
m20++;
}
}
}
U8 *Mem32DevAlloc(I64 size,I64 alignment)
{//Alloc 32-bit addr space for device. (Doesn't work.) Not used.
//For this to work the BIOS E820 map must be searched for gaps in
//the 32-bit range and the pool initialized to the gaps.
U8 *base,*limit;
CMemRange *tmpmr,*tmpmr1;
while (LBts(&sys_semas[SEMA_DEV_MEM],0))
Yield;
tmpmr1=dev.mem32_head.next;
while (tmpmr1!=&dev.mem32_head) {
base=(tmpmr1->base+alignment-1)&~(alignment-1);
limit=base+size-1;
if (!tmpmr1->type &&
limit<tmpmr1->base+tmpmr1->size) {
tmpmr=AMAlloc(sizeof(CMemRange));
tmpmr->type=MRT_DEV;
tmpmr->flags=0;
tmpmr->base=base;
tmpmr->size=size;
if (!Mem32DevIns(tmpmr)) {
Free(tmpmr);
LBtr(&sys_semas[SEMA_DEV_MEM],0);
return NULL;
}
LBtr(&sys_semas[SEMA_DEV_MEM],0);
return tmpmr->base;
}
tmpmr1=tmpmr1->next;
}
LBtr(&sys_semas[SEMA_DEV_MEM],0);
return NULL;
}
U0 Mem32DevFree(U8 *base)
{//Free 32-bit device address space.
CMemRange *tmpmr;
if (!base) return;
while (LBts(&sys_semas[SEMA_DEV_MEM],0))
Yield;
tmpmr=dev.mem32_head.next;
while (tmpmr!=&dev.mem32_head) {
if (tmpmr->base==base) {
tmpmr->type=MRT_UNUSED;
break;
}
tmpmr=tmpmr->next;
}
LBtr(&sys_semas[SEMA_DEV_MEM],0);
}
U8 *Mem64DevAlloc(I64 *_pages1Gig)
{//Alloc 64-bit addr space for device.
U8 *a;
I64 i=*_pages1Gig,*pte;
while (LBts(&sys_semas[SEMA_DEV_MEM],0))
Yield;
while (i--) {
a=dev.mem64_ptr-=1<<30;
do {
pte=MemPageTable(a);
*pte=*pte&~0x18 |0x11; //Uncached and present
InvlPg(dev.mem64_ptr);
a+=mem_page_size;
} while (a-dev.mem64_ptr<1<<30);
}
LBtr(&sys_semas[SEMA_DEV_MEM],0);
return dev.mem64_ptr;
}
U0 Mem64DevFree(U8 *base,I64 pages1Gig)
{//Free 64-bit device address space.
if (!base) return;
while (LBts(&sys_semas[SEMA_DEV_MEM],0))
Yield;
if (base==dev.mem64_ptr)
dev.mem64_ptr+=pages1Gig*1<<30;
//else not freed
LBtr(&sys_semas[SEMA_DEV_MEM],0);
}
U0 UncachedAliasAlloc() //Make uncached alias for 4 lowest Gig.
{
I64 i=4,*pte;
U8 *a;
a=dev.uncached_alias=Mem64DevAlloc(&i);
do {
pte=MemPageTable(a);
*pte=0x197+a-dev.uncached_alias;
InvlPg(a);
a+=mem_page_size;
} while (a-dev.uncached_alias<1<<32);
}
I64 BIOSTotalMem()
{
I64 r01,r20;
U16 *m01=MEM_E801;
CMemE820 *m20=MEM_E820;
r01=0x100000+m01[0]<<10+m01[1]<<16;
r20=0;
if (m20->type) {
while (m20->type) {
if (m20->type==1)
r20+=m20->len;
m20++;
}
}
return MaxI64(r01,r20);
}
I64 Scale2Mem(I64 min,I64 max,I64 limit=2*1024*1024*1024)
{//Helps pick DiskCache and RAMDisk sizes.
//Can be used in $LK,"BootHDIns",A="MN:BootHDIns"$() config scripts.
I64 i;
if (sys_data_bp)
i=sys_data_bp->alloced_u8s;
else
i=sys_code_bp->alloced_u8s;
if (i>=limit)
return max;
else
return min+(max-min)*i/limit;
}
+205
View File
@@ -0,0 +1,205 @@
asm {
// $LK,"::/Doc/MemOverview.DD"$
USE32
SYS_INIT_PAGE_TABLES::
//Check 1Gig page capability and set page size.
MOV EAX,0x80000001
CPUID
MOV EAX,1<<21
BT EDX,26
JNC @@05
MOV EAX,1<<30
@@05: MOV U32 [MEM_PAGE_SIZE],EAX
//Set mapped space limit
MOV EAX,[MEM_PHYSICAL_SPACE]
MOV EDX,[MEM_PHYSICAL_SPACE+4]
BT U32 [MEM_PAGE_SIZE],30 //Round-up to 1Gig boundary?
JNC @@10
ADD EAX,0x3FFFFFFF
ADC EDX,0
AND EAX,~0x3FFFFFFF
@@10: INC EDX //Need 4Gig extra for uncached alias up at top of space.
MOV [MEM_MAPPED_SPACE],EAX
MOV [MEM_MAPPED_SPACE+4],EDX
//How many 2Meg pages?
MOV CL,21
ADD EAX,0x1FFFFF
ADC EDX,0
SHRD EAX,EDX
SHR EDX,CL
MOV [MEM_2MEG_NUM],EAX
MOV [MEM_2MEG_NUM+4],EDX
//How many 1Gig pages?
MOV CL,9
ADD EAX,0x1FF
ADC EDX,0
SHRD EAX,EDX
SHR EDX,CL
MOV [MEM_1GIG_NUM],EAX
MOV [MEM_1GIG_NUM+4],EDX
//How many 512Gig pages?
MOV CL,9
ADD EAX,0x1FF
ADC EDX,0
SHRD EAX,EDX
SHR EDX,CL
MOV [MEM_512GIG_NUM],EAX
MOV [MEM_512GIG_NUM+4],EDX
//Set $LK,"CSysFixedArea",A="MN:CSysFixedArea"$ to zero
MOV EDI,SYS_FIXED_AREA
XOR EAX,EAX
MOV ECX,sizeof(CSysFixedArea)/4
REP_STOSD
MOV U32 [MEM_PML2],EDI
//Check for 1Gig page capability.
BT U32 [MEM_PAGE_SIZE],30
JC @@15
//Find PML2 Size
MOV EAX,U32 [MEM_2MEG_NUM]
ADD EAX,0x1FF
AND EAX,~0x1FF
SHL EAX,3
ADD EDI,EAX
//Find PML3 Size
@@15: MOV U32 [MEM_PML3],EDI
MOV EAX,U32 [MEM_1GIG_NUM]
ADD EAX,0x1FF
AND EAX,~0x1FF
SHL EAX,3
ADD EDI,EAX
//Find PML4 Size
MOV U32 [MEM_PML4],EDI
MOV EAX,U32 [MEM_512GIG_NUM]
ADD EAX,0x1FF
AND EAX,~0x1FF
SHL EAX,3
ADD EAX,EDI
MOV U32 [MEM_HEAP_BASE],EAX
//Set page tables to zero
MOV EDI,U32 [MEM_PML2]
SUB EAX,EDI
MOV ECX,EAX
SHR ECX,2
XOR EAX,EAX
REP_STOSD
//Check for 1Gig page capability.
BT U32 [MEM_PAGE_SIZE],30
JC @@30
//PML2: Use 2Meg Pages
MOV EAX,0x87 //bit 7 is page size (2Meg)
XOR EDX,EDX
MOV EDI,[MEM_PML2]
MOV ECX,[MEM_2MEG_NUM]
@@20: MOV U32 [EDI],EAX
ADD EDI,4
MOV U32 [EDI],EDX
ADD EDI,4
ADD EAX,0x200000
ADC EDX,0
LOOP @@20
//PML3: Use 2Meg Pages
MOV EAX,[MEM_PML2]
OR EAX,7
XOR EDX,EDX
MOV EDI,[MEM_PML3]
MOV ECX,[MEM_1GIG_NUM]
@@25: MOV U32 [EDI],EAX
ADD EDI,4
MOV U32 [EDI],EDX
ADD EDI,4
ADD EAX,0x1000
ADC EDX,0
LOOP @@25
JMP @@40
//PML3: Use 1Gig Pages
@@30: MOV EAX,0x87 //bit 7 is page size (1Gig)
XOR EDX,EDX
MOV EDI,[MEM_PML3]
MOV ECX,[MEM_1GIG_NUM]
@@35: MOV U32 [EDI],EAX
ADD EDI,4
MOV U32 [EDI],EDX
ADD EDI,4
ADD EAX,0x40000000
ADC EDX,0
LOOP @@35
//PML4
@@40: MOV EAX,[MEM_PML3]
OR EAX,7
XOR EDX,EDX
MOV EDI,[MEM_PML4]
MOV ECX,[MEM_512GIG_NUM]
@@45: MOV U32 [EDI],EAX
ADD EDI,4
MOV U32 [EDI],EDX
ADD EDI,4
ADD EAX,0x1000
ADC EDX,0
LOOP @@45
RET
SYS_INIT_16MEG_SYS_CODE_BP::
// Init sys_code_bp to BIOS E801 lowest 16Meg val.
// $LK,"BlkPoolsInit",A="MN:BlkPoolsInit"$() adds the rest.
MOV U32 [SYS_CODE_BP],SYS_FIXED_AREA+CSysFixedArea.sys_code_bp
MOV U32 [SYS_CODE_BP+4],0
MOV U32 [SYS_DATA_BP],0
MOV U32 [SYS_DATA_BP+4],0
XOR EAX,EAX
MOV AX,U16 [MEM_E801] //1 Kb blks between 1M and 16M
SHL EAX,10
ADD EAX,0x100000
MOV EDI,U32 [MEM_HEAP_BASE]
SUB EAX,EDI
//EDI=BASE EAX=SIZE
TEST U8 [SYS_MEM_INIT_FLAG],1
JZ @@05
PUSH EAX
PUSH EDI
MOV ECX,EAX
MOV AL,U8 [SYS_MEM_INIT_VAL]
REP_STOSB
POP EDI
POP EAX
@@05: SHR EAX,MEM_PAG_BITS
MOV ESI,SYS_FIXED_AREA+CSysFixedArea.sys_code_bp
MOV EBX,U32 CBlkPool.mem_free_lst[ESI]
MOV U32 CMemBlk.next[EDI],EBX
MOV U32 CMemBlk.next+4[EDI],0
MOV U32 CBlkPool.mem_free_lst[ESI],EDI
MOV U32 CBlkPool.mem_free_lst+4[ESI],0
MOV U32 CMemBlk.mb_signature[EDI],MBS_UNUSED_SIGNATURE_VAL
MOV U32 CMemBlk.pags[EDI],EAX
SHL EAX,MEM_PAG_BITS
ADD U32 CBlkPool.alloced_u8s[ESI],EAX
BTS U32 [SYS_RUN_LEVEL],RLf_16MEG_SYS_CODE_BP
RET
}
I64 *MemPageTable(U8 *a)
{//Point to page table entry for addr.
if (Bt(&mem_page_size,30))
return *MEM_PML3(U64 *)+a>>30*8;
else
return *MEM_PML2(U64 *)+a>>21*8;
}
+389
View File
@@ -0,0 +1,389 @@
asm {
ALIGN 16,OC_NOP
USE16
//See $LK,"TempleOS MultiCore",A="FI:::/Doc/MultiCore.DD"$.
//This code gets copied to $LK,"MP_VECT_ADDR",A="MN:MP_VECT_ADDR"$.
//See $LK,"MemCpy(MP_VECT_ADDR",A="FF:::/Kernel/MultiProc.HC,MemCpy(mp:2"$.
COREAP_16BIT_INIT::
JMP @@05
ALIGN 4,OC_NOP
AP_GDT_PTR: DU16 sizeof(CGDT)-1;
DU64 0;
@@05: CLI
WBINVD
MOV AX,MP_VECT_ADDR/16
MOV DS,AX
LGDT U32 [CAP16BitInit.ap_gdt_ptr] //See $LK,"mp->ap_gdt_ptr",A="FF:::/Kernel/MultiProc.HC,mp->ap_gdt_ptr:2"$
MOV EAX,SYS_START_CR0
MOV_CR0_EAX
DU8 0x66,0xEA; //JMP CGDT.cs32:AP_32BIT_INIT
DU32 AP_32BIT_INIT;
DU16 CGDT.cs32;
COREAP_16BIT_INIT_END::
USE32
AP_32BIT_INIT:
MOV AX,CGDT.ds
MOV DS,AX
MOV ES,AX
MOV FS,AX
MOV GS,AX
MOV SS,AX
@@05: LOCK
BTS U32 [SYS_MP_CNT_LOCK],0
JC @@05
MOV ESI,U32 [SYS_MP_CNT_INITIAL]
LOCK
INC U32 [SYS_MP_CNT_INITIAL]
LOCK
BTR U32 [SYS_MP_CNT_LOCK],0
CMP ESI,MP_PROCESSORS_NUM
JAE I32 _SYS_HLT
IMUL2 ESI,sizeof(CCPU)
ADD ESI,U32 [SYS_CPU_STRUCTS]
LEA ESP,U32 CCPU.start_stk+sizeof(CCPU.start_stk)[ESI]
PUSH U32 RFLAGG_START
POPFD
PUSH U32 0 //Return from next call will be 64-bit
CALL SYS_ENTER_LONG_MODE
USE64
FNINIT
MOV RAX,RSI
CALL SET_GS_BASE
@@10: MOV RAX,U64 CCPU.seth_task[RSI]
TEST RAX,RAX
JZ @@10
MOV U64 CTask.gs[RAX],RSI
CALL SET_FS_BASE
JMP I32 _TASK_CONTEXT_RESTORE
}
U0 TSSBusy(I64 tr,Bool val=OFF)
{//See $LK,"::/Demo/Lectures/Ring3.HC"$.
LBEqu((&sys_gdt)(U8 *)+tr+4,9,val);
}
CTSS *TSSNew(I64 cpu_num)
{
U32 *d,*d1;
CTSS *tss=CAlloc(sizeof(CTSS));
tss->io_map_offset=offset(CTSS.io_map);
MemSet(tss->io_map,0xFF,0x10000/8);
tss->st0=MAlloc(MEM_INTERRUPT_STK);
tss->rsp0=tss->st0(U8 *)+MSize(tss->st0);
tss->st1=MAlloc(MEM_INTERRUPT_STK);
tss->rsp1=tss->st1(U8 *)+MSize(tss->st1);
tss->st2=MAlloc(MEM_INTERRUPT_STK);
tss->rsp2=tss->st2(U8 *)+MSize(tss->st2);
tss->tr =offset(CGDT.tr)+cpu_num*16;
tss->tr_ring3=offset(CGDT.tr_ring3)+cpu_num*16;
d=(&sys_gdt)(U8 *)+tss->tr;
d1=d(U8 *)+4;
*d =0x0000FFFF;
*d1=0x008F8900;
d(U8 *)+=2;
*d|=tss & 0x00FFFFFF;
*d1++|=tss & 0xFF000000;
*d1++=tss>>32;
*d1=0;
d=(&sys_gdt)(U8 *)+tss->tr_ring3;
d1=d(U8 *)+4;
*d =0x0000FFFF;
*d1=0x008FE900;
d(U8 *)+=2;
*d|=tss & 0x00FFFFFF;
*d1++|=tss & 0xFF000000;
*d1++=tss>>32;
*d1=0;
return tss;
}
CCPU *CPUStructInit(I64 num,CCPU *c,CTask *seth_task)
{//Seth is null when called by adam on CSysFixedArea.boot_cpu0
MemSet(c,0,sizeof(CCPU));
c->addr=c;
c->num=num;
c->idle_factor=0.01;
QueInit(&c->next_dying);
if (Bt(&sys_run_level,RLf_16MEG_ADAM_HEAP_CTRL)) {
c->idle_task=Spawn(0,NULL,"Idle Task",,Fs,,0);
LBts(&c->idle_task->task_flags,TASKf_IDLE);
c->tss=TSSNew(num);
}
c->seth_task=seth_task;// It waits for this to be filled-in: $LK,"seth_task",A="FF:::/Kernel/MultiProc.HC,seth_task"$
return c;
}
U0 MPInt(U8 num,I64 cpu_num=1)
{//Generate interrupt for specified core.
if (cpu_num>=mp_cnt) {
if (!Bt(&sys_run_level,RLf_MP))
return;
else
throw('MultCore');
}
PUSHFD
CLI //Multitasking safe because each core has a local apic and IRQ's are off
while (*(dev.uncached_alias+LAPIC_ICR_LOW)(U32 *)&0x1000)
PAUSE
*(dev.uncached_alias+LAPIC_ICR_HIGH)(U32 *)=dev.mp_apic_ids[cpu_num]<<24;
*(dev.uncached_alias+LAPIC_ICR_LOW)(U32 *)=0x4000+num;
POPFD
}
U0 MPIntAll(U8 num)
{//Generate interrupt for all but own core.
PUSHFD
CLI //Multitasking safe because each core has a local apic and IRQ's are off
while (*(dev.uncached_alias+LAPIC_ICR_LOW)(U32 *)&0x1000)
PAUSE
*(dev.uncached_alias+LAPIC_ICR_LOW)(U32 *)=0xC4800+num;
POPFD
}
U0 MPNMInt()
{//Generate nonmaskable interrupt.
*(dev.uncached_alias+LAPIC_ICR_LOW)(U32 *)=0xC4400;
}
U0 MPHalt()
{//Halt all other cores.
mp_cnt=1;
MPNMInt;
Busy(10000);
}
U0 MPAPICInit()
{//Called by adam during start-up
//and other cores during initialization
//after $LK,"Core0StartMP",A="MN:Core0StartMP"$().
*(dev.uncached_alias+LAPIC_SVR)(U32 *)|=LAPICF_APIC_ENABLED;
dev.mp_apic_ids[Gs->num]=*(dev.uncached_alias+LAPIC_APIC_ID)(U32 *)>>24;
*(dev.uncached_alias+LAPIC_LDR)(U32 *)=dev.mp_apic_ids[Gs->num]<<24;
*(dev.uncached_alias+LAPIC_DFR)(U32 *)=0xF0000000;
// MemSet(dev.uncached_alias+LAPIC_IRR,0,0x20);
// MemSet(dev.uncached_alias+LAPIC_ISR,0,0x20);
// MemSet(dev.uncached_alias+LAPIC_TMR,0,0x20);
SetRAX(Gs->tss->tr);
LTR AX
if (Gs->num) {
IntInit1;
SetRFlags(RFLAGG_NORMAL);
}
}
#assert !offset(CJobCtrl.next_waiting)
U0 CoreAPSethTask()
{
CJobCtrl *ctrl=&Fs->srv_ctrl;
while (TRUE) {
STI
do {
TaskKillDying;
do PAUSE
while (LBts(&ctrl->flags,JOBCf_LOCKED));
} while (ctrl->next_waiting!=ctrl && JobRunOne(GetRFlags,ctrl));
CLI
LBts(&Fs->task_flags,TASKf_AWAITING_MSG);
LBtr(&ctrl->flags,JOBCf_LOCKED);
LBts(&Fs->task_flags,TASKf_IDLE);
Yield;
LBtr(&Fs->task_flags,TASKf_IDLE);
}
}
CJob *JobQue(I64 (*fp_addr)(U8 *data),U8 *data=NULL,
I64 target_cpu=1,I64 flags=1<<JOBf_FREE_ON_COMPLETE,
I64 job_code=JOBT_CALL,U8 *aux_str=NULL,I64 aux1=0,I64 aux2=0)
{//Queue multicore jobs, handled by Seth tasks.
//Set flags to zero if you wish to get the res.
//See $LK,"::/Demo/MultiCore/Lock.HC"$
CJobCtrl *ctrl;
CJob *tmpc;
CTask *seth;
if (!(0<=target_cpu<mp_cnt))
throw('MultCore');
tmpc=ACAlloc(sizeof(CJob));
if (aux_str)
tmpc->aux_str=AStrNew(aux_str);
tmpc->job_code=job_code;
tmpc->addr=fp_addr;
tmpc->fun_arg=data;
tmpc->flags=flags;
tmpc->aux1=aux1;
tmpc->aux2=aux2;
seth=cpu_structs[target_cpu].seth_task;
tmpc->ctrl=ctrl=&seth->srv_ctrl;
PUSHFD
CLI
while (LBts(&ctrl->flags,JOBCf_LOCKED))
Yield;
if (ctrl->next_waiting==ctrl && LBtr(&seth->task_flags,TASKf_AWAITING_MSG))
MPInt(I_WAKE,target_cpu);
QueIns(tmpc,ctrl->last_waiting);
LBtr(&ctrl->flags,JOBCf_LOCKED);
POPFD
return tmpc;
}
CTask *SpawnQue(U0 (*fp_addr)(U8 *data),U8 *data=NULL,U8 *task_name=NULL,
I64 target_cpu, CTask *parent=NULL, //NULL means adam
I64 stk_size=0,I64 flags=1<<JOBf_ADD_TO_QUE)
{
CTask *res;
CJob *tmpc=JobQue(fp_addr,data,target_cpu,
flags,JOBT_SPAWN_TASK,task_name,parent,stk_size);
CJobCtrl *ctrl;
while (!Bt(&tmpc->flags,JOBf_DONE)) {
LBts(&Fs->task_flags,TASKf_IDLE);
Yield;
}
LBtr(&Fs->task_flags,TASKf_IDLE);
res=tmpc->spawned_task;
ctrl=tmpc->ctrl;
PUSHFD
CLI
while (LBts(&ctrl->flags,JOBCf_LOCKED))
Yield;
QueRem(tmpc);
LBtr(&ctrl->flags,JOBCf_LOCKED);
POPFD
JobDel(tmpc);
return res;
}
U0 CoreAPSethInit()
{//Called by multicore's seth task after $LK,"Core0StartMP",A="MN:Core0StartMP"$()
//as the first thing a CPU does before waiting for jobs.
MPAPICInit;
Fs->rip=&CoreAPSethTask;
TaskContextRestore;
}
U0 Core0StartMP()
{//Called by adam during $LK,"start-up",A="FF:::/Kernel/KEnd.HC,Core0StartMP"$.
CTask *task;
U8 buf[STR_LEN];
CAP16BitInit *mp=MP_VECT_ADDR;
CCPU *c;
I64 i,my_mp_cnt;
CRAXRBCRCXRDX ee;
CPUId(0x1,&ee);
if (!Bt(&ee.rdx,9))
return;
PUSHFD
CLI
if (mp_cnt>1) {
my_mp_cnt=mp_cnt;
MPHalt; //sets mp_cnt to 1
for (i=1;i<my_mp_cnt;i++) {
c=&cpu_structs[i];
JobQueDel(&c->seth_task->srv_ctrl.next_waiting);
JobQueDel(&c->seth_task->srv_ctrl.next_done);
}
}
MemSet(&cpu_structs[1],0,sizeof(CCPU)*(MP_PROCESSORS_NUM-1));
//When you start-up other cores, they jump to an addr
//specified by a byte vect number, $LK,"MPN_VECT",A="MN:MPN_VECT"$ which corresponds
//to a location 4096*vect number, $LK,"MP_VECT_ADDR",A="MN:MP_VECT_ADDR"$$WW,0$.
MemCpy(mp,COREAP_16BIT_INIT,COREAP_16BIT_INIT_END-COREAP_16BIT_INIT);
MemCpy(&mp->ap_gdt_ptr,SYS_GDT_PTR,sizeof(CSysLimitBase));
mp_cnt_initial=mp_cnt=1;
mp_cnt_lock=0;
*(dev.uncached_alias+LAPIC_LVT_ERR)(U32 *)=
*(dev.uncached_alias+LAPIC_LVT_ERR)(U32 *)&0xFFFFFF00+MPN_VECT;
WBINVD //Not sure why this is needed. Might just need delay. $LK,"MemCpy",A="MN:MemCpy"$ above?
*(dev.uncached_alias+LAPIC_ICR_LOW)(U32 *)=0xC4500; //assert init IPI
Busy(10000);
*(dev.uncached_alias+LAPIC_ICR_LOW)(U32 *)=0xC4600+MPN_VECT; //start-up
Busy(200);
*(dev.uncached_alias+LAPIC_ICR_LOW)(U32 *)=0xC4600+MPN_VECT;
Busy(100000);
for (i=0;i<10000;i++)
LBts(&mp_cnt_lock,0); //Don't let more through
my_mp_cnt=mp_cnt_initial;
if (my_mp_cnt>MP_PROCESSORS_NUM)
my_mp_cnt=MP_PROCESSORS_NUM;
for (i=1;i<my_mp_cnt;i++) {
StrPrint(buf,"Seth Task CPU%02X",i);
task=Spawn(&CoreAPSethInit,NULL,buf,,,MEM_SETH_STK,0);
task->rflags=RFLAGG_START;
//$LK,"CTask",A="MN:CTask"$ alloced off this core's seth_task's heap (Which is Adam)
CPUStructInit(i,&cpu_structs[i],task);
WBINVD //Not sure why this is needed. Might just need delay.
}
//Make sure they're all up-and-running
for (i=1;i<my_mp_cnt;i++)
while (!Bt(&cpu_structs[i].seth_task->task_flags,TASKf_AWAITING_MSG))
PAUSE;
POPFD
mp_cnt=my_mp_cnt; //Finalize cnt
}
U0 Core0Init()
{//Called by adam during start-up
CRAXRBCRCXRDX ee;
CPUId(0x1,&ee);
mp_cnt_initial=mp_cnt=1;
mp_cnt_lock=0;
dbg.mp_crash=ACAlloc(sizeof(CMPCrash));
//Must be in code heap because init code uses 32 bit addr of cpu_struct
adam_task->gs=cpu_structs=
CAlloc(sizeof(CCPU)*MP_PROCESSORS_NUM,Fs->code_heap);
CPUStructInit(0,cpu_structs,adam_task);
asm {//RAX has GS
IMPORT SET_GS_BASE;
CALL SET_GS_BASE
}
if (Bt(&ee.rdx,9)) {
//Unnecessary?
// SetMSR(IA32_LAPIC_BASE,dev.uncached_alias+LAPIC_BASE+0x900);
MPAPICInit;
}
}
interrupt U0 IntMPCrash()
{//Entering the debugger from another core causes an interrupt on Core0
//Which calls this routine.
*(dev.uncached_alias+LAPIC_EOI)(U32 *)=0;
mp_cnt=1;
Raw(ON);
text.raw_flags|=RWF_SHOW_DOLLAR;
"MP Crash CPU%02X Task:%08X\n"
"RIP:%P\n",dbg.mp_crash->cpu_num,dbg.mp_crash->task,dbg.mp_crash->rip;
Panic(dbg.mp_crash->msg,dbg.mp_crash->msg_num);
}
+289
View File
@@ -0,0 +1,289 @@
asm {
USE32
SYS_PCIBIOS_SERVICE_DIR:: DU32 0;
SYS_PCI_SERVICES:: DU32 0;
SYS_FIND_PCIBIOS_SERVICE_DIR::
MOV ESI,0xE0000
MOV ECX,(0x100000-0xE0000)/4
@@05: CMP U32 [ESI],'_32_'
JNE @@20
PUSH ECX
XOR ECX,ECX
MOV CL,U8 9[ESI]
SHL ECX,4
@@10: MOV EDI,ESI
XOR EAX,EAX
XOR EDX,EDX
@@15: MOV DL,U8 [EDI]
ADD EAX,EDX
INC EDI
DEC ECX
JNZ @@15
POP ECX
TEST AL,AL
JNZ @@20
MOV U32 [SYS_PCIBIOS_SERVICE_DIR],ESI
MOV ESI,U32 4[ESI]
MOV U32 [SYS_PCIBIOS_SERVICE_CALL],ESI
RET
@@20: ADD ESI,4
LOOP @@05
MOV U32 [SYS_PCIBIOS_SERVICE_DIR],0
RET
SYS_FIND_PCI_SERVICES::
MOV ESI,U32 [SYS_PCIBIOS_SERVICE_DIR]
TEST ESI,ESI
JNZ @@05
MOV U32 [SYS_PCI_SERVICES],0
RET
@@05: MOV EAX,'$$PCI'
XOR EBX,EBX
DU8 0x9A; //CALL CGDT.cs32:PCIBIOS_SERVICE
SYS_PCIBIOS_SERVICE_CALL:: DU32 0;
DU16 CGDT.cs32;
TEST AL,AL
JNZ @@05
LEA ESI,U32 [EBX+EDX]
MOV U32 [SYS_PCI_SERVICES],ESI
RET
@@05: MOV U32 [SYS_PCI_SERVICES],0
RET
USE64
C32_EAX:: DU32 0;
C32_EBX:: DU32 0;
C32_ECX:: DU32 0;
C32_EDX:: DU32 0;
C32_ESI:: DU32 0;
C32_EDI:: DU32 0;
C32_EFLAGS:: DU32 0;
C32_RSP:: DU64 0;
_FAR_CALL32::
//This calls a 32-bit mode routine.
//(We must switch from 64-bit mode to do it.)
//
//NON REENTRANT
//
PUSH RBP
MOV RBP,RSP
MOV RAX,U64 SF_ARG1[RBP]
TEST RAX,RAX
JNZ @@05
POP RBP
RET1 8 //return FALSE
@@05: MOV U32 [C32_ADD],EAX
PUSH_REGS
PUSHFD
XOR RAX,RAX
PUSH U64 FS:CTask.addr[RAX]
PUSH U64 GS:CCPU.addr[RAX]
MOV U64 [C32_RSP],RSP
PUSH U32 CGDT.ds //STKSEG
PUSH U32 BOOT_RAM_LIMIT //STK
PUSH U32 0 //FLAGS--interrupts off
PUSH U32 CGDT.cs32
LEA RAX,[@@15]
PUSH RAX
IRET
USE32
@@15:
WBINVD
//disable paging
MOV_EAX_CR0
BTR EAX,31
MOV_CR0_EAX
MOV ECX,IA32_EFER
XOR EDX,EDX
XOR EAX,EAX
WRMSR
MOV AX,CGDT.ds
MOV FS,AX
MOV GS,AX
//SS already set
MOV EAX,U32 [C32_EAX]
MOV EBX,U32 [C32_EBX]
MOV ECX,U32 [C32_ECX]
MOV EDX,U32 [C32_EDX]
MOV ESI,U32 [C32_ESI]
MOV EDI,U32 [C32_EDI]
MOV U32 [C32_EFLAGS],0
DU8 0x9A; //CALL CGDT.cs32:[C32_ADD]
C32_ADD:: DU32 0;
DU16 CGDT.cs32;
PUSHFD
POP U32 [C32_EFLAGS]
MOV U32 [C32_EAX],EAX
MOV U32 [C32_EBX],EBX
MOV U32 [C32_ECX],ECX
MOV U32 [C32_EDX],EDX
MOV U32 [C32_ESI],ESI
MOV U32 [C32_EDI],EDI
PUSH U32 0 //Return from next call will be 64-bit
CALL SYS_ENTER_LONG_MODE
USE64 MOV RSP,U64 [C32_RSP]
POP RAX
CALL SET_GS_BASE
POP RAX
CALL SET_FS_BASE
POPFD
POP_REGS
XOR RAX,RAX
MOV AL,TRUE
POP RBP
RET1 8
}
_extern C32_EAX U32 c32_eax;
_extern C32_EBX U32 c32_ebx;
_extern C32_ECX U32 c32_ecx;
_extern C32_EDX U32 c32_edx;
_extern C32_ESI U32 c32_esi;
_extern C32_EDI U32 c32_edi;
_extern C32_EFLAGS U32 c32_eflags;
_extern SYS_PCI_SERVICES U32 sys_pci_services;
_extern _FAR_CALL32 Bool FarCall32(U0 (*fp_addr)());//Not reentrant.For PCIBIOS.
U8 PCIReadU8(I64 bus,I64 dev,I64 fun,I64 rg)
{//Read U8 in PCI configspace at bus,dev,fun,reg.
I64 res;
PUSHFD
CLI
while (LBts(&sys_semas[SEMA_FAR_CALL32],0))
Yield;
c32_eax=0xB108;
c32_ebx=bus<<8+dev<<3+fun;
c32_edi=rg;
if (FarCall32(sys_pci_services))
res=c32_ecx.u8[0];
else
res=0xFF;
LBtr(&sys_semas[SEMA_FAR_CALL32],0);
POPFD
return res;
}
U16 PCIReadU16(I64 bus,I64 dev,I64 fun,I64 rg)
{//Read U16 in PCI configspace at bus,dev,fun,reg.
I64 res;
PUSHFD
CLI
while (LBts(&sys_semas[SEMA_FAR_CALL32],0))
Yield;
c32_eax=0xB109;
c32_ebx=bus<<8+dev<<3+fun;
c32_edi=rg;
if (FarCall32(sys_pci_services))
res=c32_ecx.u16[0];
else
res=0xFFFF;
LBtr(&sys_semas[SEMA_FAR_CALL32],0);
POPFD
return res;
}
U32 PCIReadU32(I64 bus,I64 dev,I64 fun,I64 rg)
{//Read U32 in PCI configspace at bus,dev,fun,reg.
I64 res;
PUSHFD
CLI
while (LBts(&sys_semas[SEMA_FAR_CALL32],0))
Yield;
c32_eax=0xB10A;
c32_ebx=bus<<8+dev<<3+fun;
c32_edi=rg;
if (FarCall32(sys_pci_services))
res=c32_ecx;
else
res=0xFFFFFFFF;
LBtr(&sys_semas[SEMA_FAR_CALL32],0);
POPFD
return res;
}
U0 PCIWriteU8(I64 bus,I64 dev,I64 fun,I64 rg,I64 val)
{//Write U8 in PCI configspace at bus,dev,fun,reg.
PUSHFD
CLI
while (LBts(&sys_semas[SEMA_FAR_CALL32],0))
Yield;
c32_eax=0xB10B;
c32_ebx=bus<<8+dev<<3+fun;
c32_edi=rg;
c32_ecx=val;
FarCall32(sys_pci_services);
LBtr(&sys_semas[SEMA_FAR_CALL32],0);
POPFD
}
U0 PCIWriteU16(I64 bus,I64 dev,I64 fun,I64 rg,I64 val)
{//Write U16 in PCI configspace at bus,dev,fun,reg.
PUSHFD
CLI
while (LBts(&sys_semas[SEMA_FAR_CALL32],0))
Yield;
c32_eax=0xB10C;
c32_ebx=bus<<8+dev<<3+fun;
c32_edi=rg;
c32_ecx=val;
FarCall32(sys_pci_services);
LBtr(&sys_semas[SEMA_FAR_CALL32],0);
POPFD
}
U0 PCIWriteU32(I64 bus,I64 dev,I64 fun,I64 rg,I64 val)
{//Write U32 in PCI configspace at bus,dev,fun,reg.
PUSHFD
CLI
while (LBts(&sys_semas[SEMA_FAR_CALL32],0))
Yield;
c32_eax=0xB10D;
c32_ebx=bus<<8+dev<<3+fun;
c32_edi=rg;
c32_ecx=val;
FarCall32(sys_pci_services);
LBtr(&sys_semas[SEMA_FAR_CALL32],0);
POPFD
}
I64 PCIClassFind(I64 class_code,I64 n)
{/*Find bus,dev,fun of Nth class_code dev.
class_code is low three bytes
n is index starting at zero
Return: -1 not found
else bus,dev,fun.
*/
I64 res;
PUSHFD
CLI
while (LBts(&sys_semas[SEMA_FAR_CALL32],0))
Yield;
c32_eax=0xB103;
c32_esi=n;
c32_ecx=class_code;
if (FarCall32(sys_pci_services) && !c32_eax.u8[1])
res=c32_ebx.u8[1]<<16+(c32_ebx&0xF8)<<5+c32_ebx&7;
else
res=-1;
LBtr(&sys_semas[SEMA_FAR_CALL32],0);
POPFD
return res;
}
+104
View File
@@ -0,0 +1,104 @@
U0 QSortI64(I64 *base,I64 num, I64 (*fp_compare)(I64 e1,I64 e2))
{/*Quick Sort for width==8.
fp_compare() passes by value instead of ref.
For ascending strings: return StrCmp(e1,e2);
For ascending ints : return e1-e2;
Maybe, look at $LK,"::/Demo/MultiCore/MPRadix.HC"$.
*/
I64 i,*left,*right,pivot;
if (num>1) {
left =base;
right=base+num-1;
pivot=base[num/2];
do {
while ((*fp_compare)(*left,pivot)<0)
left++;
while ((*fp_compare)(*right,pivot)>0)
right--;
if (left<=right)
SwapI64(left++,right--);
} while (left<=right);
i=right+1-base;
if (1<i<num)
QSortI64(base,i,fp_compare);
i=base+num-left;
if (1<i<num)
QSortI64(left,i,fp_compare);
}
}
U0 QSort2a(U8 **base,I64 num,I64 (*fp_compare)(U8 **_e1,U8 **_e2))
{//Not public.For case of width==size(U8 *)==8.
//fp_compare() passes by ref.
I64 i;
U8 **left,**right,*pivot;
left =base;
right=base+num-1;
pivot=base[num/2];
do {
while ((*fp_compare)(left,&pivot)<0)
left++;
while ((*fp_compare)(right,&pivot)>0)
right--;
if (left<=right)
SwapI64(left++,right--);
} while (left<=right);
i=right+1-base;
if (1<i<num)
QSort2a(base,i,fp_compare);
i=base+num-left;
if (1<i<num)
QSort2a(left,i,fp_compare);
}
U0 QSort2b(U8 *base,I64 num, I64 width,
I64 (*fp_compare)(U8 *e1,U8 *e2),U8 *tmp)
{//Not public
I64 i;
U8 *left,*right,*pivot=tmp+width;
left =base;
right=base+(num-1)*width;
MemCpy(pivot,base+num/2*width,width);
do {
while ((*fp_compare)(left,pivot)<0)
left+=width;
while ((*fp_compare)(right,pivot)>0)
right-=width;
if (left<=right) {
if (left!=right) {
MemCpy(tmp,right,width);
MemCpy(right,left,width);
MemCpy(left,tmp,width);
}
left+=width;
right-=width;
}
} while (left<=right);
i=1+(right-base)/width;
if (1<i<num)
QSort2b(base,i,width,fp_compare,tmp);
i=num+(base-left)/width;
if (1<i<num)
QSort2b(left,i,width,fp_compare,tmp);
}
U0 QSort(U8 *base,I64 num, I64 width, I64 (*fp_compare)(U8 *e1,U8 *e2))
{/*Quick Sort: fp_compare() passes by ref.
For ascending strings: return StrCmp(*e1,*e2);
For ascending ints : return *e1-*e2;
Don't return e1-e2 if numbers can overflow, return -1,0 or 1.
Maybe, look at $LK,"::/Demo/MultiCore/MPRadix.HC"$.
*/
U8 *tmp;
if (width && num>1) {
if (width==sizeof(U8 *)) //assign instead of MemCpy for width 8
QSort2a(base,num,fp_compare);
else {
tmp=MAlloc(width*2);
QSort2b(base,num,width,fp_compare,tmp);
Free(tmp);
}
}
}
+325
View File
@@ -0,0 +1,325 @@
/*On each core, tasks are linked in a
circular doubly-linked list queue with
the Seth task as the head. On Core0,
the queue order represents the front-to-back
window stack order with the window mgr
as the wallpaper.
The scheduler is round-robin. It checks
if a task is ready and runs it or skips it.
Swapping tasks just involves storing and
restoring regs (no disk I/O for virtual
memory and no addr map changes). It is
always fully identity-mapped on all cores.
Tasks can be switched in half a microsecond.
The scheduler checks if a task is
waiting for a certain time or waiting
on a message and skips if not ready.
A task runs until it voluntarily yields ctrl
with a call to $LK,"Yield",A="MN:Yield"$(). Tasks waiting on I/O
often loop, checking for a status and
$LK,"Yield",A="MN:Yield"$ing. This does not really degrade
performance, but pegs the CPU Load.
The scheduler checks for a few keys:
<CTRL-ALT-x> kill a task.
<CTRL-ALT-DEL> reboots.
<CTRL-ALT-n> Next task.
<CTRL-ALT-c> breaks execution of a program.
Each core has its own circular task queue.
For AP processors, they have a "Seth" task
which stays in a loop waiting for jobs or
requests to spawn tasks. See $LK,"CoreAPSethTask",A="MN:CoreAPSethTask"$().
$HL,1$*/
U0 TaskFocusNext()
{
CTask *task,*_task=sys_focus_task;
sys_focus_task=NULL;
if (!_task) _task=adam_task;
task=_task->next_task;
do {
if (!Bt(&task->win_inhibit,WIf_SELF_FOCUS)) {
sys_focus_task=task;
CallExtNum(EXT_WIN_TO_TOP,task,TRUE);
return;
}
task=task->next_task;
} while (task!=_task);
}
asm {
TASK_CONTEXT_SAVE::
//OUT: RSI=FS
PUSH RSI
PUSHFD
XOR RSI,RSI
MOV RSI,FS:CTask.addr[RSI]
POP U64 CTask.rflags[RSI]
POP U64 CTask.rsi[RSI]
MOV U64 CTask.rax[RSI],RAX
/*Divert the stk to the Task memory
and push onto it and divert it back.
It's a little faster.
*/
MOV RAX,RSP
LEA RSP,U64 CTask.r15+8[RSI]
PUSH R15
PUSH R14
PUSH R13
PUSH R12
PUSH R11
PUSH R10
PUSH R9
PUSH R8
PUSH RDI
PUSH RBP
PUSH RBX
PUSH RDX
PUSH RCX
MOV RSP,RAX
MOV RAX,U64 CTask.fpu_mmx[RSI]
FXSAVE U64 [RAX]
MOV RDX,U64 CTask.bpt_lst[RSI]
@@05: TEST RDX,RDX
JZ @@10
MOV RDI,U64 CBpt.addr[RDX]
MOV AL,U8 CBpt.val[RDX]
MOV U8 [RDI],AL
MOV RDX,U64 CBpt.next[RDX]
JMP @@05
@@10: RET
//************************************
_TASK_CONTEXT_RESTORE::
XOR RAX,RAX
INC U64 GS:CCPU.swap_cnter[RAX]
MOV RSI,FS:CTask.addr[RAX]
BT U32 CTask.rflags[RSI],RFLAGf_INT
JNC @@05
BTS U32 GS:CCPU.cpu_flags[RAX],CPUf_RAN_A_TASK
@@05: BT U64 CTask.task_flags[RSI],TASKf_DISABLE_BPTS
JC @@15
MOV RDX,U64 CTask.bpt_lst[RSI]
@@10: TEST RDX,RDX
JZ @@15
MOV RDI,U64 CBpt.addr[RDX]
MOV U8 [RDI],OC_BPT
MOV RDX,U64 CBpt.next[RDX]
JMP @@10
@@15: INC U64 CTask.swap_cnter[RSI]
MOV RAX,U64 CTask.fpu_mmx[RSI]
FXRSTOR U64 [RAX]
MOV RAX,RSP
LEA RSP,U64 CTask.rcx[RSI]
POP RCX
POP RDX
POP RBX
POP RBP
POP RDI
POP R8
POP R9
POP R10
POP R11
POP R12
POP R13
POP R14
POP R15
MOV RSP,RAX
MOV RAX,U64 CTask.rax[RSI]
PUSH CGDT.ds
PUSH U64 CTask.rsp[RSI]
PUSH U64 CTask.rflags[RSI]
PUSH CGDT.cs64
PUSH U64 CTask.rip[RSI]
MOV RSI,U64 CTask.rsi[RSI]
IRET
//************************************
END_RSI_TASK:
MOV RAX,RSI
CALL SET_FS_BASE
_TASK_END_NOW::
CALL &TaskEnd
MOV RSI,RAX
CALL SET_FS_BASE
JMP I8 RESTORE_RSI_TASK
_YIELD::
PUSHFD
TEST U8 [SYS_SEMAS+SEMA_SINGLE_USER*DFT_CACHE_LINE_WIDTH],1
JZ @@05
POPFD //If single user, don't change task.
RET
@@05: CLI
CALL TASK_CONTEXT_SAVE
MOV EBX,U32 _RET
MOV U64 CTask.rip[RSI],RBX
POP U64 CTask.rflags[RSI]
MOV U64 CTask.rsp[RSI],RSP
MOV RSI,U64 CTask.next_task[RSI]
RESTORE_RSI_TASK:
TEST U64 [SYS_CTRL_ALT_FLAGS],1<<CTRL_ALT_DEL|
1<<CTRL_ALT_TAB|1<<CTRL_ALT_X|1<<CTRL_ALT_C
JNZ HANDLE_SYSF_KEY_EVENT
RESTORE_RSI_TASK2:
@@20: BT U64 CTask.task_flags[RSI],TASKf_KILL_TASK
JC END_RSI_TASK
TEST U64 CTask.task_flags[RSI],
1<<TASKf_AWAITING_MSG|1<<TASKf_SUSPENDED
JNZ @@25
MOV RAX,U64 [&cnts.jiffies]
CMP U64 CTask.wake_jiffy[RSI],RAX
JG @@25 //Jmp if not ready, yet.
MOV RAX,RSI
CALL SET_FS_BASE
JMP I32 _TASK_CONTEXT_RESTORE
@@25: MOV RSI,U64 CTask.next_task[RSI]
XOR RAX,RAX
CMP U64 GS:CCPU.seth_task[RAX],RSI
JNE @@20 //Jmp if not Seth
BTR U32 GS:CCPU.cpu_flags[RAX],CPUf_RAN_A_TASK
JC @@20 //Jmp if had chance for IRQ already
MOV RAX,U64 GS:CCPU.idle_task[RAX]
MOV RSP,U64 CTask.stk[RAX]
ADD RSP,MEM_DFT_STK+CTaskStk.stk_base //Rst to top
CALL SET_FS_BASE
STI //Restore idle task so we can unmask IRQs.
HLT
SYS_IDLE_PT::
CLI
RESTORE_SETH_TASK_IF_READY:
XOR RAX,RAX
MOV RSI,GS:CCPU.seth_task[RAX]
JMP RESTORE_RSI_TASK
HANDLE_SYSF_KEY_EVENT:
MOV RAX,RSI
CALL SET_FS_BASE
XOR RBX,RBX
MOV RAX,GS:CCPU.num[RBX]
TEST RAX,RAX
JNZ I32 RESTORE_RSI_TASK2
MOV EAX,U32 SYS_CTRL_ALT_FLAGS
LOCK
BTR U32 [RAX],CTRL_ALT_DEL
JC I32 &Reboot
CMP U64 GS:CCPU.idle_task[RBX],RSI
JE RESTORE_SETH_TASK_IF_READY
LOCK
BTR U32 [RAX],CTRL_ALT_TAB
JNC @@05
CALL &TaskFocusNext
JMP I32 RESTORE_FS_TASK
@@05: LOCK
BTR U32 [RAX],CTRL_ALT_X
JC END_FOCUS_USER
LOCK
BTR U32 [RAX],CTRL_ALT_C
JNC I32 RESTORE_RSI_TASK
BREAK_FOCUS_USER:
MOV RSI,U64 [SYS_FOCUS_TASK]
TEST RSI,RSI
JZ RESTORE_SETH_TASK_IF_READY
BT U64 CTask.win_inhibit[RSI],WIf_SELF_FOCUS
JC I32 RESTORE_RSI_TASK
LOCK
BTR U64 CTask.task_flags[RSI],TASKf_BREAK_LOCKED
JNC @@10
LOCK
BTS U64 CTask.task_flags[RSI],TASKf_PENDING_BREAK
JMP I32 RESTORE_RSI_TASK
@@10: MOV RAX,&Break
MOV U64 CTask.rip[RSI],RAX
BT U64 CTask.task_flags[RSI],TASKf_BREAK_TO_SHIFT_ESC
JC I32 RESTORE_RSI_TASK
//Do these now, in case interrupt happens.
MOV U64 CTask.wake_jiffy[RSI],0
PUSH RSI
CALL &TaskRstAwaitingMsg
JMP I32 RESTORE_RSI_TASK
END_FOCUS_USER:
MOV RSI,U64 [SYS_FOCUS_TASK]
CALL &TaskFocusNext
TEST RSI,RSI
JZ I32 RESTORE_SETH_TASK_IF_READY
MOV RAX,RSI
CALL SET_FS_BASE
BT U64 CTask.win_inhibit[RSI],WIf_SELF_FOCUS
JC I32 RESTORE_RSI_TASK
LOCK
BTS U64 CTask.task_flags[RSI],TASKf_KILL_TASK
JMP I32 END_RSI_TASK
RESTORE_FS_TASK:
XOR RSI,RSI
MOV RSI,FS:CTask.addr[RSI]
JMP I32 RESTORE_RSI_TASK
}
_extern _TASK_CONTEXT_RESTORE U0 TaskContextRestore(); //Restore a task context.
_extern _YIELD U0 Yield(); //Yield cpu to next task.
_extern _TASK_END_NOW U0 TaskEndNow(); //Terminate current task.
U0 TaskQueIns(CTask *task,CTask *pred=NULL)
{//Insert a task in the scheduler running task queue.
//You have no business with this, probably.
CTask *last;
PUSHFD
CLI
if (!pred) pred=Fs;
last=pred->last_task;
last->next_task=pred->last_task=task;
task->last_task=last;
task->next_task=pred;
POPFD
}
U0 TaskQueRem(CTask *task)
{//Remove a task from the scheduler running task queue.
//Use $LK,"Suspend",A="MN:Suspend"$().
CTask *next,*last;
PUSHFD
CLI
next=task->next_task;
last=task->last_task;
last->next_task=next;
next->last_task=last;
POPFD
}
U0 TaskQueInsChild(CTask *task)
{
CTask *last,*pred;
PUSHFD
CLI
pred=task->parent_task->last_child_task;
last=pred->last_sibling_task;
last->next_sibling_task=pred->last_sibling_task=task;
task->last_sibling_task=last;
task->next_sibling_task=pred;
POPFD
}
+492
View File
@@ -0,0 +1,492 @@
asm {
NORMAL_KEY_SCAN_DECODE_TABLE::
DU8 0,CH_ESC,"1234567890-=",CH_BACKSPACE,'\t';
DU8 "qwertyuiop[]",'\n',0,"as";
DU8 "dfghjkl;'\`",0,"\\zxcv";
DU8 "bnm,./",0,'*',0,CH_SPACE,0,0,0,0,0,0;
DU8 0,0,0,0,0,0,0,0,0,0,'-',0,0,0,'+',0;
SHIFT_KEY_SCAN_DECODE_TABLE::
DU8 0,CH_SHIFT_ESC,"!@#$$%^&*()_+",CH_BACKSPACE,'\t';
DU8 "QWERTYUIOP{}",'\n',0,"AS";
DU8 "DFGHJKL:\"~",0,"|ZXCV";
DU8 "BNM<>?",0,'*',0,CH_SHIFT_SPACE,0,0,0,0,0,0;
DU8 0,0,0,0,0,0,0,0,0,0,'-',0,0,0,'+',0;
CTRL_KEY_SCAN_DECODE_TABLE::
DU8 0,CH_ESC,"1234567890-=",CH_BACKSPACE,'\t';
DU8 CH_CTRLQ,CH_CTRLW,CH_CTRLE,CH_CTRLR,CH_CTRLT,CH_CTRLY,CH_CTRLU,
CH_CTRLI,CH_CTRLO,CH_CTRLP,"[]",'\n',0,CH_CTRLA,CH_CTRLS;
DU8 CH_CTRLD,CH_CTRLF,CH_CTRLG,CH_CTRLH,CH_CTRLJ,CH_CTRLK,CH_CTRLL,
";'\`",0,"\\",CH_CTRLZ,CH_CTRLX,CH_CTRLC,CH_CTRLV;
DU8 CH_CTRLB,CH_CTRLN,CH_CTRLM,",./",0,'*',0,CH_SPACE,0,0,0,0,0,0;
DU8 0,0,0,0,0,0,0,0,0,0,'-',0,0,0,'+',0;
}
U0 KbdCmdSend(I64 port, U8 val)
{
F64 timeout=tS+0.125;
while (tS<timeout) {
if (!(InU8(KBD_CTRL)&2)) {
OutU8(port,val);
return;
}
}
throw;
}
I64 KbdCmdRead()
{
F64 timeout=tS+0.125;
while (tS<timeout)
if (InU8(KBD_CTRL)&1)
return InU8(KBD_PORT);
throw;
}
U0 KbdCmdFlush()
{
F64 timeout=tS+0.03;
while (tS<timeout)
InU8(KBD_PORT);
}
U0 KbdLEDsSet(I64 sc)
{
U8 v=0;
BEqu(&v,0,Bt(&sc,SCf_SCROLL));
BEqu(&v,1,Bt(&sc,SCf_NUM));
BEqu(&v,2,Bt(&sc,SCf_CAPS));
try {
KbdCmdSend(KBD_PORT,0xED);
KbdCmdSend(KBD_PORT,v);
} catch
Fs->catch_except=TRUE;
}
U0 KbdMsCmdAck(...)
{
I64 i,ack,timeout;
for (i=0;i<argc;i++) {
timeout=5;
do {
ack=0;
try {
KbdCmdSend(KBD_CTRL,0xD4);
KbdCmdSend(KBD_PORT,argv[i]);
ack=KbdCmdRead;
} catch {
KbdCmdFlush;
Fs->catch_except=TRUE;
}
} while (ack!=0xFA && --timeout);
if (!timeout)
throw;
}
}
U0 KbdTypeMatic(U8 delay)
{//Set speed of repeated keys.
try {
KbdCmdSend(KBD_CTRL,0xA7); //Disable Mouse
KbdCmdSend(KBD_CTRL,0xAE); //Enable Keyboard
KbdCmdSend(KBD_PORT,0xF3);
KbdCmdSend(KBD_PORT,delay); //Typematic rate
KbdCmdSend(KBD_CTRL,0xA8); //Enable Mouse
} catch {
KbdCmdFlush;
Fs->catch_except=TRUE;
}
}
I64 Char2ScanCode(I64 ch,I64 sc_flags=0)
{//ASCII val to scan code (Slow).
I64 i;
U8 *table;
if (sc_flags) {
table=NORMAL_KEY_SCAN_DECODE_TABLE;
if (sc_flags & SCF_CTRL || ch<26)
table=CTRL_KEY_SCAN_DECODE_TABLE;
else if (sc_flags & SCF_SHIFT || 'A'<=ch<='Z') {
if (!(sc_flags & SCF_CAPS))
table=SHIFT_KEY_SCAN_DECODE_TABLE;
} else {
if (sc_flags & SCF_CAPS)
table=SHIFT_KEY_SCAN_DECODE_TABLE;
}
for (i=0;i<0x50;i++)
if (table[i]==ch)
return i|sc_flags;
return sc_flags;
} else {
table=NORMAL_KEY_SCAN_DECODE_TABLE;
for (i=0;i<0x50;i++)
if (table[i]==ch)
return i;
table=SHIFT_KEY_SCAN_DECODE_TABLE;
for (i=0;i<0x50;i++)
if (table[i]==ch)
return i|SCF_SHIFT;
table=CTRL_KEY_SCAN_DECODE_TABLE;
for (i=0;i<0x50;i++)
if (table[i]==ch)
return i|SCF_CTRL;
return 0;
}
}
U8 ScanCode2Char(I64 sc)
{//Scan code to ASCII val.
U8 *table=NORMAL_KEY_SCAN_DECODE_TABLE;
if (sc&SCF_E0_PREFIX)
return 0;
if (sc&SCF_CTRL)
table=CTRL_KEY_SCAN_DECODE_TABLE;
else if (sc&SCF_SHIFT) {
if (!(sc&SCF_CAPS))
table=SHIFT_KEY_SCAN_DECODE_TABLE;
} else {
if (sc&SCF_CAPS)
table=SHIFT_KEY_SCAN_DECODE_TABLE;
}
sc&=0x7F;
if (sc>=0x50)
return 0;
else
return table[sc];
}
U8 scan_code_map[0x100]={
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,SC_SHIFT,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,SC_ENTER,SC_CTRL,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0x35,0,0,SC_ALT,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,SC_HOME,
SC_CURSOR_UP,SC_PAGE_UP,0,SC_CURSOR_LEFT,0,SC_CURSOR_RIGHT,0,SC_END,
SC_CURSOR_DOWN,SC_PAGE_DOWN,SC_INS,SC_DELETE,0,0,0,0,
0,0,0,0,SC_GUI,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
};
U8 num_lock_map[0x100]={
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,8,9,10,0,5,6,7,0,2,
3,4,11,0x34,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,SC_ENTER,SC_CTRL,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0x35,0,0,SC_ALT,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,SC_HOME,
SC_CURSOR_UP,SC_PAGE_UP,0,SC_CURSOR_LEFT,0,SC_CURSOR_RIGHT,0,SC_END,
SC_CURSOR_DOWN,SC_PAGE_DOWN,SC_INS,SC_DELETE,0,0,0,0,
0,0,0,0,SC_GUI,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
};
U8 *Char2KeyName(I64 ch,Bool include_ctrl=TRUE)
{//ASCII val to key name.
I64 i;
U8 buf[STR_LEN];
if (ch<=CH_SPACE) {
switch [ch] {
case '\n':
StrCpy(buf,"ENTER");
break;
case CH_BACKSPACE:
StrCpy(buf,"BACKSPACE");
break;
case '\t':
StrCpy(buf,"TAB");
break;
case CH_ESC:
StrCpy(buf,"ESC");
break;
case CH_SHIFT_ESC:
StrCpy(buf,"SHIFT_ESC");
break;
case 0: //nobound switch
case 29:
case 30:
*buf=0;
break;
case CH_SHIFT_SPACE:
StrCpy(buf,"SHIFT_SPACE");
break;
case CH_SPACE:
StrCpy(buf,"SPACE");
break;
default:
if (include_ctrl)
StrCpy(buf,"CTRL ");
buf[i=StrLen(buf)]=ch-1+'a';
buf[i+1]=0;
break;
}
} else if (Bt(char_bmp_printable,ch)) {
*buf=ch;
buf[1]=0;
} else
*buf=0;
return StrNew(buf);
}
U8 *ScanCode2KeyName(I64 sc)
{//Scan code to key name.
I64 ch;
U8 buf[STR_LEN],*st;
*buf=0;
if (sc&SCF_CTRL)
CatPrint(buf,"CTRL ");
if (sc&SCF_ALT)
CatPrint(buf,"ALT ");
if (sc&SCF_SHIFT)
CatPrint(buf,"SHIFT ");
if (sc&SCF_NO_SHIFT)
CatPrint(buf," ");
if (ch=ScanCode2Char(sc&255)) {
st=Char2KeyName(ch,FALSE);
StrCpy(buf+StrLen(buf),st);
Free(st);
} else {
switch (sc&255) {
case SC_BACKSPACE:CatPrint(buf,"BACK"); break;
case SC_CAPS: CatPrint(buf,"CAPS"); break;
case SC_NUM: CatPrint(buf,"NUM"); break;
case SC_SCROLL: CatPrint(buf,"SCROLL"); break;
case SC_CURSOR_UP:CatPrint(buf,"UP"); break;
case SC_CURSOR_DOWN:CatPrint(buf,"DOWN"); break;
case SC_CURSOR_LEFT:CatPrint(buf,"LEFT"); break;
case SC_CURSOR_RIGHT:CatPrint(buf,"RIGHT"); break;
case SC_PAGE_UP: CatPrint(buf,"PAGE_UP"); break;
case SC_PAGE_DOWN:CatPrint(buf,"PAGE_DOWN");break;
case SC_HOME: CatPrint(buf,"HOME"); break;
case SC_END: CatPrint(buf,"END"); break;
case SC_INS: CatPrint(buf,"INS"); break;
case SC_DELETE: CatPrint(buf,"DELETE"); break;
case SC_F1: CatPrint(buf,"F1"); break;
case SC_F2: CatPrint(buf,"F2"); break;
case SC_F3: CatPrint(buf,"F3"); break;
case SC_F4: CatPrint(buf,"F4"); break;
case SC_F5: CatPrint(buf,"F5"); break;
case SC_F6: CatPrint(buf,"F6"); break;
case SC_F7: CatPrint(buf,"F7"); break;
case SC_F8: CatPrint(buf,"F8"); break;
case SC_F9: CatPrint(buf,"F9"); break;
case SC_F10: CatPrint(buf,"F10"); break;
case SC_F11: CatPrint(buf,"F11"); break;
case SC_F12: CatPrint(buf,"F12"); break;
case SC_GUI: CatPrint(buf,"WINDOWS"); break;
case SC_PRTSCRN1: CatPrint(buf,"PRTSCRN1"); break;
case SC_PRTSCRN2: CatPrint(buf,"PRTSCRN2"); break;
}
}
return StrNew(buf);
}
U0 KbdBuildSC(U8 raw_byte,Bool in_irq,U8 *_last_raw_byte,I64 *_last_sc)
{
I64 ch,sc_flags,sc,sc2,sc_raw,new_key_f;
Bool set_LEDs=FALSE;
if (raw_byte==0xE0) {
*_last_sc&=~0x1FF;
*_last_raw_byte=raw_byte;
return;
}
sc=raw_byte;
BEqu(&sc,SCf_E0_PREFIX,*_last_raw_byte==0xE0);
BEqu(&sc,SCf_KEY_UP,raw_byte & 0x80);
*_last_raw_byte=raw_byte;
sc_flags=_last_sc->u32[0]&~0x1FF;
sc_raw=sc;
if (sc_flags & SCF_NUM) {
if (sc2=num_lock_map[sc.u8[0]])
sc.u8[0]=sc2;
} else {
if (sc2=scan_code_map[sc.u8[0]])
sc.u8[0]=sc2;
}
new_key_f=SCF_NEW_KEY;
if (sc&SCF_KEY_UP)
switch (sc&~SCF_KEY_UP) {
case SC_SHIFT: sc_flags&=~SCF_SHIFT; break;
case SC_CTRL: sc_flags&=~SCF_CTRL; break;
case SC_ALT: sc_flags&=~SCF_ALT; break;
case SC_DELETE: sc_flags&=~SCF_DELETE; break;
case SC_INS: sc_flags&=~SCF_INS; break;
case SC_CAPS: sc_flags^=SCF_CAPS; set_LEDs=TRUE; break;
case SC_NUM: sc_flags^=SCF_NUM; set_LEDs=TRUE; break;
case SC_SCROLL: sc_flags^=SCF_SCROLL; set_LEDs=TRUE; break;
}
else
switch (sc) {
case SC_SHIFT:
if (Bts(&sc_flags,SCf_SHIFT)) new_key_f=0;
break;
case SC_CTRL:
if (Bts(&sc_flags,SCf_CTRL)) new_key_f=0;
break;
case SC_ALT:
if (Bts(&sc_flags,SCf_ALT)) new_key_f=0;
break;
case SC_DELETE:
sc_flags|=SCF_DELETE;
break;
case SC_INS:
sc_flags|=SCF_INS;
break;
}
sc_flags|=new_key_f;
sc=sc_flags|sc|(sc_flags|sc_raw)<<32;
if (sc_flags & SCF_CTRL && sc_flags & SCF_ALT) {
if (!(sc&SCF_KEY_UP)) {
if (sc&255==SC_DELETE && !(sc_flags & SCF_SHIFT))
CtrlAltDel(sc);
else {
if (sc&255==SC_ESC)
ch='t';
else if (sc&255==SC_TAB)
ch='n';
else
ch=ScanCode2Char(sc&255);
if ('a'<=ch<='z') {
sc&=~(SCF_NEW_KEY|SCF_NEW_KEY<<32);
ch-='a';
kbd.last_down_scan_code=sc;
if (keydev.fp_ctrl_alt_cbs[ch] &&
Bt(&keydev.ctrl_alt_in_irq_flags,ch)==in_irq &&
(!(sc_flags & SCF_SHIFT)&&keydev.ctrl_alt_no_shift_descs[ch]) ||
sc_flags & SCF_SHIFT && keydev.ctrl_alt_shift_descs[ch])
(*keydev.fp_ctrl_alt_cbs[ch])(sc);
}
}
}
}
if (set_LEDs && !in_irq)
KbdLEDsSet(sc);
*_last_sc=sc;
}
U0 KbdPktRead()
{
static U8 last_raw_byte=0;
static I64 last_sc=0;
U8 raw_byte;
if (GetTSC>kbd.timestamp+cnts.time_stamp_freq>>3)
FifoU8Flush(kbd.fifo);
kbd.timestamp=GetTSC;
raw_byte=InU8(KBD_PORT);
KbdBuildSC(raw_byte,TRUE,&last_raw_byte,&last_sc);
if (!FifoU8Cnt(kbd.fifo)) {
FifoU8Ins(kbd.fifo,raw_byte);
if (raw_byte!=0xE0) {
while (FifoU8Rem(kbd.fifo,&raw_byte))
FifoU8Ins(kbd.fifo2,raw_byte);
}
} else {
FifoU8Ins(kbd.fifo,raw_byte);
while (FifoU8Rem(kbd.fifo,&raw_byte))
FifoU8Ins(kbd.fifo2,raw_byte);
}
}
interrupt U0 IRQKbd()
{
CLD
OutU8(0x20,0x20);
kbd.irqs_working=TRUE;
if (ms_hard.install_in_progress) {
kbd.rst=TRUE;
return;
}
keydev.ctrl_alt_ret_addr=GetRBP()(I64)+8;
KbdPktRead;
}
U0 KbdInit()
{
try {
KbdCmdFlush;
KbdCmdSend(KBD_CTRL,0xA7); //Disable Mouse
KbdCmdSend(KBD_CTRL,0xAE); //Enable Keyboard
KbdCmdSend(KBD_PORT,0xF0);
KbdCmdSend(KBD_PORT,0x02);
KbdLEDsSet(kbd.scan_code);
} catch {
KbdCmdFlush;
Fs->catch_except=TRUE;
}
IntEntrySet(0x21,&IRQKbd);
OutU8(0x21,InU8(0x21)&~2);
}
U0 KbdHndlr()
{
static U8 last_raw_byte=0;
U8 raw_byte;
FifoU8Rem(kbd.fifo2,&raw_byte);
KbdBuildSC(raw_byte,FALSE,&last_raw_byte,&kbd.scan_code);
if (raw_byte==0xE0) {
FifoU8Rem(kbd.fifo2,&raw_byte);
KbdBuildSC(raw_byte,FALSE,&last_raw_byte,&kbd.scan_code);
}
if (Btr(&kbd.scan_code,SCf_NEW_KEY)) {
kbd.new_key_timestamp=kbd.timestamp;
Btr(&kbd.scan_code,32+SCf_NEW_KEY);
FifoI64Ins(kbd.scan_code_fifo,kbd.scan_code);
kbd.cnt++;
if (!(kbd.scan_code&SCF_KEY_UP)) {
kbd.last_down_scan_code=kbd.scan_code;
Bts(kbd.down_bitmap,kbd.scan_code.u8[0]);
Bts(kbd.down_bitmap2,kbd.scan_code.u8[4]);
} else {
Btr(kbd.down_bitmap,kbd.scan_code.u8[0]);
Btr(kbd.down_bitmap2,kbd.scan_code.u8[4]);
}
}
}
I64 KbdMsgsQue()
{
I64 arg1,arg2,msg_code=MSG_NULL;
CTask *task_focus;
if (task_focus=sys_focus_task) {
while (FifoI64Rem(kbd.scan_code_fifo,&arg2)) {
arg1=ScanCode2Char(arg2);
if (arg2 & SCF_KEY_UP) {
TaskMsg(task_focus,0,MSG_KEY_UP,arg1,arg2,0);
msg_code=MSG_KEY_UP;
} else {
TaskMsg(task_focus,0,MSG_KEY_DOWN,arg1,arg2,0);
msg_code=MSG_KEY_DOWN;
}
}
}
return msg_code;
}
I64 KbdMsEvtTime()
{//Timestamp of last key or mouse event.
if (ms_hard.timestamp>kbd.timestamp)
return ms_hard.timestamp;
else
return kbd.new_key_timestamp;
}
@@ -0,0 +1,5 @@
#exe {Cd(__DIR__);};
#include "Keyboard"
#include "Mouse"
#include "Message"
#exe {Cd("..");};
+244
View File
@@ -0,0 +1,244 @@
U0 InputFilterTask()
{
CJob *tmpc,*tmpc1;
Bool old_filter;
I64 old_flags=GetRFlags;
Fs->win_inhibit=WIG_USER_TASK_DFT;
LBts(&Fs->task_flags,TASKf_INPUT_FILTER_TASK);
old_filter=LBts(&Fs->last_input_filter_task->task_flags,TASKf_FILTER_INPUT);
LBEqu(&Fs->task_flags,TASKf_FILTER_INPUT,old_filter);
while (TRUE) {
CLI
JobsHndlr(old_flags);
tmpc1=&Fs->srv_ctrl.next_waiting;
tmpc=tmpc1->next;
if (tmpc==tmpc1)
break;
else {
if (tmpc->job_code==JOBT_TEXT_INPUT) {
QueRem(tmpc);
SetRFlags(old_flags);
try
ExePrint("%s",tmpc->aux_str);
catch
Fs->catch_except=TRUE;
JobDel(tmpc);
} else
break;
}
}
Fs->next_input_filter_task->last_input_filter_task=Fs->last_input_filter_task;
Fs->last_input_filter_task->next_input_filter_task=Fs->next_input_filter_task;
if (!old_filter)
LBtr(&Fs->last_input_filter_task->task_flags,TASKf_FILTER_INPUT);
SetRFlags(old_flags);
}
I64 ScanMsg(I64 *_arg1=NULL,I64 *_arg2=NULL,I64 mask=~1,CTask *task=NULL)
{/*Check for a message of type specified by a one in the mask.
Throw-out messages not in mask.
If no message fit mask, return NULL immediately.
Remove desired message, return $LK,"msg_code",A="MN:MSG_CMD"$.
Note: This delivers messages from parent down to pop-up.
*/
I64 res,old_flags;
CJob *tmpc,*tmpc1;
if (!task) task=Fs;
old_flags=GetRFlags;
tmpc1=&task->srv_ctrl.next_waiting;
while (TRUE) {
CLI
if (task==Fs)
JobsHndlr(old_flags);
tmpc=tmpc1->next;
if (tmpc==tmpc1)
break;
else {
if (tmpc->job_code==JOBT_MSG) {
QueRem(tmpc);
SetRFlags(old_flags);
res=tmpc->msg_code;
if (_arg1)
*_arg1=tmpc->aux1;
if (_arg2)
*_arg2=tmpc->aux2;
JobDel(tmpc);
if ((res!=MSG_KEY_DOWN || !(tmpc->aux2&SCF_KEY_DESC) ||
!Bt(&task->win_inhibit,WIf_SELF_KEY_DESC)) && Bt(&mask,res))
goto sm_done;
}
}
SetRFlags(old_flags);
}
res=MSG_NULL;
if (_arg1)
*_arg1=0;
if (_arg2)
*_arg2=0;
if (task->parent_task&&task->parent_task->popup_task==task) {
SetRFlags(old_flags);
return ScanMsg(_arg1,_arg2,mask,task->parent_task);
}
sm_done:
SetRFlags(old_flags);
return res;
}
I64 FlushMsgs(CTask *task=NULL)
{//Throw away all messages. Return count.
I64 res=0,arg1,arg2;
while (ScanMsg(&arg1,&arg2,~1,task))
res++;
return res;
}
I64 GetMsg(I64 *_arg1=NULL,I64 *_arg2=NULL,I64 mask=~1,CTask *task=NULL)
{//Wait for a message of type specified by a one in the mask.
//Throw-out all messages not in mask.
//Returns $LK,"msg_code",A="MN:MSG_CMD"$. See $LK,"::/Demo/MsgLoop.HC"$.
I64 res;
if (!task) task=Fs;
LBtr(&task->task_flags,TASKf_IDLE);
while (!(res=ScanMsg(_arg1,_arg2,mask,task))) {
LBts(&task->task_flags,TASKf_IDLE);
Yield;
}
LBtr(&task->task_flags,TASKf_IDLE);
return res;
}
I64 ScanChar()
{//Checks for $LK,"MSG_KEY_DOWN",A="MN:MSG_KEY_DOWN"$ and returns 0 immediately if no key.
//Waits for $LK,"MSG_KEY_UP",A="MN:MSG_KEY_UP"$ of non-zero $LK,"ASCII",A="MN:CH_CTRLA"$ key and returns $LK,"ASCII",A="MN:CH_CTRLA"$ if key.
//$LK,"ScanMsg",A="MN:ScanMsg"$() throws away other message types.
I64 arg1a,arg2a,arg1b,arg2b;
if (!ScanMsg(&arg1a,&arg2a,1<<MSG_KEY_DOWN)||!arg1a)
return 0;
else
do GetMsg(&arg1b,&arg2b,1<<MSG_KEY_UP);
while (!arg1b); //Be careful of $LK,"SC_SHIFT",A="MN:SC_SHIFT"$ and $LK,"SC_CTRL",A="MN:SC_CTRL"$, etc.
return arg1a;
}
Bool ScanKey(I64 *_ch=NULL,I64 *_scan_code=NULL,Bool echo=FALSE)
{//Checks for $LK,"MSG_KEY_DOWN",A="MN:MSG_KEY_DOWN"$ and returns FALSE immediately if no key.
//Sets $LK,"ASCII",A="MN:CH_CTRLA"$ and $LK,"scan_code",A="FI:::/Doc/CharOverview.DD"$.
//Removes key message and returns TRUE.
//$LK,"ScanMsg",A="MN:ScanMsg"$() throws away other message types.
I64 ch=0,sc=0;
if (ScanMsg(&ch,&sc,1<<MSG_KEY_DOWN)) {
if (_ch) *_ch=ch;
if (_scan_code) *_scan_code=sc;
if (echo)
PutKey(ch,sc);
return TRUE;
} else {
if (_ch) *_ch=0;
if (_scan_code) *_scan_code=0;
return FALSE;
}
}
I64 GetKey(I64 *_scan_code=NULL,Bool echo=FALSE,Bool raw_cursor=FALSE)
{//Waits for $LK,"MSG_KEY_DOWN",A="MN:MSG_KEY_DOWN"$ message and returns $LK,"ASCII",A="MN:CH_CTRLA"$.
//Sets $LK,"scan_code",A="FI:::/Doc/CharOverview.DD"$.
//$LK,"ScanKey",A="MN:ScanKey"$() throws away other message types.
I64 ch,sc;
Bool cursor_on=FALSE;
while (!ScanKey(&ch,&sc,FALSE)) {
if (IsRaw && raw_cursor) {
if (!cursor_on && ToI64(GetTSC*5/cnts.time_stamp_freq)&1) {
'Û';
cursor_on=TRUE;
} else if (cursor_on && !(ToI64(GetTSC*5/cnts.time_stamp_freq)&1)) {
'' CH_BACKSPACE;
cursor_on=FALSE;
}
}
LBts(&Fs->task_flags,TASKf_IDLE);
if (IsDbgMode) {
//We don't want interrupt-driven keyboard when in debugger
//because that could have side-effects or crash, so we poll
//keyboard when in debugger with interrupts off.
PUSHFD
CLI
KbdMsHndlr(TRUE,FALSE);
KbdMsgsQue;
POPFD
} else {
LBts(&Fs->task_flags,TASKf_AWAITING_MSG);
Yield;
}
LBtr(&Fs->task_flags,TASKf_IDLE);
}
if (IsRaw && raw_cursor && cursor_on)
'' CH_BACKSPACE;
if (echo)
PutKey(ch,sc);
if (_scan_code) *_scan_code=sc;
return ch;
}
I64 GetChar(I64 *_scan_code=NULL,Bool echo=TRUE,Bool raw_cursor=FALSE)
{//Waits for non-zero $LK,"ASCII",A="MN:CH_CTRLA"$ key.
//Sets $LK,"scan_code",A="FI:::/Doc/CharOverview.DD"$.
I64 ch1;
do ch1=GetKey(_scan_code,FALSE,raw_cursor);
while (!ch1);
if (echo)
"$$PT$$%c$$FG$$",ch1;
return ch1;
}
U8 *GetStr(U8 *msg=NULL,U8 *dft=NULL,I64 flags=0)
{//Returns a $LK,"MAlloc",A="MN:MAlloc"$()ed prompted string. See $LK,"Flags",A="MN:GSF_SHIFT_ESC_EXIT"$.
U8 *st;
if (msg)
"" msg,dft;
st=(*fp_getstr2)(flags);
if (!*st) {
Free(st);
if (dft)
return StrNew(dft);
else
return StrNew("");
}
return st;
}
I64 GetS(U8 *buf,I64 size,Bool allow_ext=TRUE)
{//Prompt into fixed length string. Size must include terminator.
U8 *st;
I64 ch,i=0;
if (!size || !buf) return 0;
if (allow_ext) {
st=GetStr;
if (StrLen(st)>size-1) {
MemCpy(buf,st,size-1);
buf[size-1]=0;
} else
StrCpy(buf,st);
i=StrLen(buf);
Free(st);
} else {
while (TRUE) {
ch=GetChar(,FALSE,IsDbgMode);
if (ch=='\n') {
'' ch;
break;
} else if (ch==CH_BACKSPACE) {
if (i>0) {
i--;
'' ch;
}
} else {
if (i<size-1) {
buf[i++]=ch;
'' ch;
}
}
}
buf[i]=0;
}
return i;
}
+367
View File
@@ -0,0 +1,367 @@
U0 GridInit()
{//Init mouse grid struct. See $LK,"::/Demo/Graphics/Grid.HC"$.
ms_grid.x=ms_grid.y=ms_grid.z=8;
ms_grid.x_offset=ms_grid.y_offset=ms_grid.z_offset=0;
ms_grid.x_speed =ms_grid.y_speed =ms_grid.z_speed =1;
ms_grid.show=ms_grid.snap=ms_grid.coord=FALSE;
}
U0 MsUpdate(I64 x,I64 y,I64 z,Bool l,Bool r)
{
ms.presnap.x=ToI64(ms.scale.x*x)+ms.offset.x;
ms.presnap.y=ToI64(ms.scale.y*y)+ms.offset.y;
ms.presnap.z=ToI64(ms.scale.z*z)+ms.offset.z;
if (ms_grid.snap) {
ms.pos.x=Trunc(ms.presnap.x/ms_grid.x)*ms_grid.x+ms_grid.x_offset;
ms.pos.y=Trunc(ms.presnap.y/ms_grid.y)*ms_grid.y+ms_grid.y_offset;
ms.pos.z=Trunc(ms.presnap.z/ms_grid.z)*ms_grid.z+ms_grid.z_offset;
} else {
ms.pos.x=ms.presnap.x;
ms.pos.y=ms.presnap.y;
ms.pos.z=ms.presnap.z;
}
ms.pos.x=ClampI64(ms.pos.x,0,GR_WIDTH-1);
ms.pos.y=ClampI64(ms.pos.y,0,GR_HEIGHT-1);
ms.pos_text.x=ms.pos.x/FONT_WIDTH;
if (ms.pos_text.x>=text.cols) {
ms.pos_text.x=text.cols-1;
ms.pos.x=text.cols*FONT_WIDTH-1;
}
ms.pos_text.y=ms.pos.y/FONT_HEIGHT;
if (ms.pos_text.y>=text.rows) {
ms.pos_text.y=text.rows-1;
ms.pos.y=text.rows*FONT_HEIGHT-1;
}
ms.lb=l;
ms.rb=r;
LBEqu(&kbd.scan_code,SCf_MS_L_DOWN,ms.lb);
LBEqu(&kbd.scan_code,SCf_MS_R_DOWN,ms.rb);
}
U0 MsSet(I64 x=I64_MAX,I64 y=I64_MAX,I64 z=I64_MAX,I64 l=I64_MAX,I64 r=I64_MAX)
{//Note: Generates a message. See $LK,"MsSet",A="FF:::/Demo/Games/Zing.HC,MsSet"$().
if (!(0<=x<GR_WIDTH))
x=ms.pos.x;
if (!(0<=y<GR_HEIGHT))
y=ms.pos.y;
if (z==I64_MAX)
z=ms.pos.z;
if (!(FALSE<=l<=TRUE))
l=ms.lb;
if (!(FALSE<=r<=TRUE))
r=ms.rb;
x=(x-ms.offset.x)/ms.scale.x;
y=(y-ms.offset.y)/ms.scale.y;
z=(z-ms.offset.z)/ms.scale.z;
MsUpdate(x,y,z,l,r);
MsHardSet(x,y,z,l,r);
}
U0 MsInit()
{
MemSet(&ms,0,sizeof(CMsStateGlbls));
MemSet(&ms_last,0,sizeof(CMsStateGlbls));
ms.offset.x=ms.offset.y=ms.offset.z=0;
ms.scale.x=ms.scale.y=ms.scale.z=1.0;
ms.pos_text.x=ms.pos_text.y=ms.pos_text.z=0;
ms.has_wheel=FALSE;
ms.show=TRUE;
ms.speed=0;
ms.timestamp=GetTSC;
ms.dbl_time=0.350;
GridInit;
}
U0 MsHardPktRead()
{
U8 j;
if (GetTSC>ms_hard.timestamp+cnts.time_stamp_freq>>3)
FifoU8Flush(ms_hard.fifo);
ms_hard.timestamp=GetTSC;
FifoU8Ins(ms_hard.fifo,InU8(KBD_PORT));
if (FifoU8Cnt(ms_hard.fifo)==ms_hard.pkt_size)
while (FifoU8Rem(ms_hard.fifo,&j))
FifoU8Ins(ms_hard.fifo2,j);
}
interrupt U0 IRQMsHard()
{
CLD
OutU8(0xA0,0x20);
OutU8(0x20,0x20);
ms_hard.irqs_working=TRUE;
if (ms_hard.install_in_progress || !ms_hard.installed) {
kbd.rst=TRUE;
return;
}
MsHardPktRead;
}
U0 MsHardGetType()
{
I64 b;
KbdMsCmdAck(0xF2);
b=KbdCmdRead;
if (b==3)
ms_hard.has_wheel=TRUE;
else if (b==4)
ms_hard.has_ext_bttns=TRUE;
}
Bool MsHardRst()
{
U8 b,*_b;
F64 timeout;
Bool res=FALSE;
ms_hard.has_wheel=FALSE;
ms_hard.has_ext_bttns=FALSE;
if (*0x40E(U16 *)==0x9FC0) {
_b=0x9FC00+0x30;
*_b=1; //This enables my mouse. It might be for one machine.
//USB DMA packets, set-up by BIOS to make legacy PS/2?
}
try {
KbdCmdFlush;
KbdCmdSend(KBD_CTRL,0xAD); //Disable Kbd
KbdCmdSend(KBD_CTRL,0xA8); //Enable Mouse
KbdMsCmdAck(0xFF); //Rst
timeout=tS+10.0;
do
try {
KbdCmdRead;
timeout=0; //force exit
} catch
Fs->catch_except=TRUE;
while (tS<timeout);
try
KbdCmdRead;
catch
Fs->catch_except=TRUE;
KbdMsCmdAck(0xF3,200,0xF3,100,0xF3,80);
MsHardGetType;
KbdMsCmdAck(0xF3,10);
MsHardGetType;
KbdMsCmdAck(0xE8,0x03,0xE6,0xF3,100,0xF4);
res=TRUE;
//Enable IRQ 12
KbdCmdSend(KBD_CTRL,0x20);
b=KbdCmdRead;
KbdCmdSend(KBD_CTRL,0x60);
KbdCmdSend(KBD_PORT,(b|2)&~0x20);
} catch
Fs->catch_except=TRUE;
//This is been added to override failure
//because the mouse sometimes still works.
res=TRUE;
try
KbdCmdSend(KBD_CTRL,0xAE); //Enable Keyboard
catch
Fs->catch_except=TRUE;
if (ms_hard.has_wheel || ms_hard.has_ext_bttns)
ms_hard.pkt_size=4;
else
ms_hard.pkt_size=3;
if (!res)
try
KbdCmdSend(KBD_CTRL,0xA7); //Disable Mouse
catch
Fs->catch_except=TRUE;
return res;
}
U0 MsHardSpeedSet()
{
I64 dd,tmp;
if ((dd=SqrI64(ms_hard_last.pos.x-ms_hard.pos.x)
+SqrI64(ms_hard_last.pos.y-ms_hard.pos.y)) &&
(tmp=ms_hard.timestamp-ms_hard_last.timestamp))
ms_hard.speed=Sqrt(dd)*cnts.time_stamp_freq/tmp;
ms_hard_last.timestamp=ms_hard.timestamp;
}
U0 MsHardSetPre()
{
I64 old_timestamp=ms_hard_last.timestamp;
MemCpy(&ms_hard_last,&ms_hard,sizeof(CMsHardStateGlbls));
ms_hard_last.timestamp=old_timestamp;
}
U0 MsHardSetPost()
{
I64 i;
ms_hard.pos.x=ms_hard.prescale.x*ms_hard.scale.x*ms_grid.x_speed;
ms_hard.pos.y=ms_hard.prescale.y*ms_hard.scale.y*ms_grid.y_speed;
ms_hard.pos.z=ms_hard.prescale.z*ms_hard.scale.z*ms_grid.z_speed;
i=Trunc(ms.scale.x*ms_hard.pos.x/ms_grid.x)*ms_grid.x+ms.offset.x;
//TODO ms_grid.x_offset?
if (i<0)
ms.offset.x-=i;
else if (i>=GR_WIDTH)
ms.offset.x+=GR_WIDTH-1-i;
i=Trunc(ms.scale.y*ms_hard.pos.y/ms_grid.y)*ms_grid.y+ms.offset.y;
if (i<0)
ms.offset.y-=i;
else if (i>=GR_HEIGHT)
ms.offset.y+=GR_HEIGHT-1-i;
if (ms_hard.pos.x!=ms_hard_last.pos.x || ms_hard.pos.y!=ms_hard_last.pos.y ||
ms_hard.pos.z!=ms_hard_last.pos.z) {
ms_hard.evt=TRUE;
MsHardSpeedSet;
} else
for (i=0;i<5;i++)
if (ms_hard.bttns[i]!=ms_hard_last.bttns[i]) {
ms_hard.evt=TRUE;
break;
}
}
U0 MsHardHndlr()
{
I64 i,dx,dy,dz;
U8 ms_buf[4];
MsHardSetPre;
for (i=0;i<4;i++)
ms_buf[i]=0;
for (i=0;i<ms_hard.pkt_size;i++)
if (!FifoU8Rem(ms_hard.fifo2,&ms_buf[i]))
ms_buf[i]=0;
ms_hard.bttns[0] = ms_buf[0] & 1;
ms_hard.bttns[1] = (ms_buf[0] & 2) >> 1;
ms_hard.bttns[2] = (ms_buf[0] & 4) >> 2;
ms_hard.bttns[3] = (ms_buf[3] & 0x10) >> 4;
ms_hard.bttns[4] = (ms_buf[3] & 0x20) >> 5;
if (ms_buf[0] & 0x10)
dx=ms_buf[1]-256;
else
dx=ms_buf[1];
if (ms_buf[0] & 0x20)
dy=256-ms_buf[2];
else
dy=-ms_buf[2];
if (ms_buf[3] & 0x08)
dz=ms_buf[3]&7-8;
else
dz=ms_buf[3]&7;
ms_hard.prescale.x+=dx;
ms_hard.prescale.y+=dy;
ms_hard.prescale.z+=dz;
MsHardSetPost;
}
U0 MsHardSet(I64 x,I64 y,I64 z,I64 l,I64 r)
{
ms_hard.timestamp=GetTSC;
MsHardSetPre;
ms_hard.prescale.x=x/ms_hard.scale.x/ms_grid.x_speed;
ms_hard.prescale.y=y/ms_hard.scale.y/ms_grid.y_speed;
ms_hard.prescale.z=z/ms_hard.scale.z/ms_grid.z_speed;
ms_hard.bttns[0]=l;
ms_hard.bttns[1]=r;
MsHardSetPost;
}
U0 KbdMsRst()
{
KbdCmdFlush;
FifoU8Flush(kbd.fifo2);
FifoU8Flush(ms_hard.fifo2);
FifoI64Flush(kbd.scan_code_fifo);
kbd.scan_code=0;
kbd.rst=FALSE;
}
Bool MsHardDrvrInstall(I64 dummy=0) //can be spawned
{
no_warn dummy;
I64 i;
ms_hard.install_in_progress=TRUE;
OutU8(0xA1,InU8(0xA1)|0x10);
ms_hard.installed=ms_hard.irqs_working=FALSE;
IntEntrySet(0x2C,&IRQMsHard);
for(i=0;i<5;i++)
ms_hard.bttns[i]=0;
if (i=MsHardRst)
OutU8(0xA1,InU8(0xA1)&~0x10);
KbdMsRst;
ms_hard.install_attempts++;
ms_hard.installed=ms_hard.evt=i;
ms_hard.install_in_progress=FALSE;
return ms_hard.installed;
}
U0 KbdMsHndlr(Bool poll_kbd,Bool poll_ms)
{
if (ms_hard.install_in_progress) {
Yield;
return;
}
if (kbd.rst)
KbdMsRst;
else {
if (poll_ms && ms_hard.installed && !ms_hard.irqs_working) {
PUSHFD
CLI
while (InU8(KBD_CTRL)&1)
MsHardPktRead;
POPFD
}
if (poll_kbd)
while (InU8(KBD_CTRL)&1)
KbdPktRead;
if (kbd.rst)
KbdMsRst;
else {
while (FifoU8Cnt(kbd.fifo2))
KbdHndlr;
while (FifoU8Cnt(ms_hard.fifo2))
if (ms_hard.installed)
MsHardHndlr;
else
KbdMsRst;
}
}
}
U0 KbdMsInit()
{
MemSet(&kbd,0,sizeof(CKbdStateGlbls));
kbd.fifo=FifoU8New(8);
kbd.fifo2=FifoU8New(0x1000);
kbd.scan_code_fifo=FifoI64New(0x1000);
kbd.irqs_working=FALSE;
MemSet(&ms_hard,0,sizeof(CMsHardStateGlbls));
ms_hard.fifo=FifoU8New(8);
ms_hard.fifo2=FifoU8New(0x1000);
ms_hard.scale.x=0.5;
ms_hard.scale.y=0.5;
ms_hard.scale.z=1.0;
ms_hard.prescale.x=GR_WIDTH/ms_hard.scale.x/2.0;
ms_hard.prescale.y=GR_HEIGHT/ms_hard.scale.y/2.0;
ms_hard.prescale.z=0/ms_hard.scale.z;
ms_hard.pos.x=GR_WIDTH>>1;
ms_hard.pos.y=GR_HEIGHT>>1;
MemCpy(&ms_hard_last,&ms_hard,sizeof(CMsHardStateGlbls));
}
+686
View File
@@ -0,0 +1,686 @@
U8 *StrPrintHex(U8 *dst,I64 num;I64 width)
{
U8 *res=dst+width;
dst=res;
while (width--) {
*--dst="0123456789ABCDEF"(U8 *)[num&15];
num>>=4;
}
return res;
}
U0 PutHex(I64 num,I64 width)
{
U8 buf[17];
if (width>16) width=16;
*StrPrintHex(buf,num,width)=0;
"%s",buf;
}
asm {
// IN: RAX=NUM TO PRINT
PUT_HEX_U64::
PUSH_C_REGS
PUSH 16
PUSH RAX
CALL &PutHex
POP_C_REGS
RET
PUT_HEX_U32::
PUSH_C_REGS
PUSH 8
PUSH RAX
CALL &PutHex
POP_C_REGS
RET
PUT_HEX_U16::
PUSH_C_REGS
PUSH 4
PUSH RAX
CALL &PutHex
POP_C_REGS
RET
PUT_HEX_U8::
PUSH_C_REGS
PUSH 2
PUSH RAX
CALL &PutHex
POP_C_REGS
RET
PUT_CHARS::
// IN: RAX=Char
PUSH_C_REGS
PUSH RAX
CALL &PutChars
POP_C_REGS
RET
PUT_STR::
// IN: RSI=String
PUSH_C_REGS
PUSH RSI
CALL &PutS
POP_C_REGS
RET
_STRCPY::
PUSH RBP
MOV RBP,RSP
PUSH RSI
PUSH RDI
MOV RDI,U64 SF_ARG1[RBP]
TEST RDI,RDI
JZ @@15
MOV RSI,U64 SF_ARG2[RBP]
TEST RSI,RSI
JNZ @@05
XOR RAX,RAX
JMP @@10
@@05: LODSB
@@10: STOSB
TEST AL,AL
JNZ @@05
@@15: POP RDI
POP RSI
POP RBP
RET1 16
_STRCMP::
PUSH RBP
MOV RBP,RSP
PUSH RSI
PUSH RDI
MOV RSI,U64 SF_ARG2[RBP]
MOV RDI,U64 SF_ARG1[RBP]
@@05: LODSB
TEST AL,AL
JZ @@20
SCASB
JE @@05
JA @@15
@@10: MOV RAX,1
JMP @@25
@@15: MOV RAX,-1
JMP @@25
@@20: SCASB
JNE @@10
XOR RAX,RAX
@@25: POP RDI
POP RSI
POP RBP
RET1 16
TO_UPPER::
CMP AL,'a'
JB @@05
CMP AL,'z'
JA @@05
ADD AL,'A'-'a'
@@05: RET
_STRICMP::
PUSH RBP
MOV RBP,RSP
PUSH RSI
PUSH RDI
MOV RSI,U64 SF_ARG2[RBP]
MOV RDI,U64 SF_ARG1[RBP]
@@05: LODSB
TEST AL,AL
JZ @@30
CMP AL,'a'
JB @@10
CMP AL,'z'
JA @@10
ADD AL,'A'-'a'
@@10: MOV BL,U8 [RDI]
INC RDI
CMP BL,'a'
JB @@15
CMP BL,'z'
JA @@15
ADD BL,'A'-'a'
@@15: CMP AL,BL
JE @@05
JA @@25
@@20: MOV RAX,1
JMP @@35
@@25: MOV RAX,-1
JMP @@35
@@30: MOV BL,U8 [RDI]
TEST BL,BL
JNE @@20
XOR RAX,RAX
@@35: POP RDI
POP RSI
POP RBP
RET1 16
_STRNCMP::
PUSH RBP
MOV RBP,RSP
PUSH RSI
PUSH RDI
MOV RCX,U64 SF_ARG3[RBP]
MOV RSI,U64 SF_ARG2[RBP]
MOV RDI,U64 SF_ARG1[RBP]
@@05: TEST RCX,RCX
JZ @@25
DEC RCX
LODSB
TEST AL,AL
JZ @@20
SCASB
JE @@05
JA @@15
@@10: MOV RAX,1
JMP @@30
@@15: MOV RAX,-1
JMP @@30
@@20: MOV BL,U8 [RDI]
TEST BL,BL
JNE @@10
@@25: XOR RAX,RAX
@@30: POP RDI
POP RSI
POP RBP
RET1 24
_STRNICMP::
PUSH RBP
MOV RBP,RSP
PUSH RSI
PUSH RDI
MOV RCX,U64 SF_ARG3[RBP]
MOV RSI,U64 SF_ARG2[RBP]
MOV RDI,U64 SF_ARG1[RBP]
@@05: TEST RCX,RCX
JZ @@35
DEC RCX
LODSB
TEST AL,AL
JZ @@30
CMP AL,'a'
JB @@10
CMP AL,'z'
JA @@10
ADD AL,'A'-'a'
@@10: MOV BL,U8 [RDI]
INC RDI
CMP BL,'a'
JB @@15
CMP BL,'z'
JA @@15
ADD BL,'A'-'a'
@@15: CMP AL,BL
JE @@05
JA @@25
@@20: MOV RAX,1
JMP @@40
@@25: MOV RAX,-1
JMP @@40
@@30: SCASB
JNE @@20
@@35: XOR RAX,RAX
@@40: POP RDI
POP RSI
POP RBP
RET1 24
_STRMATCH::
PUSH RBP
MOV RBP,RSP
PUSH RSI
PUSH RDI
MOV RSI,U64 SF_ARG2[RBP]
TEST RSI,RSI
JZ @@25
MOV RDI,U64 SF_ARG1[RBP]
TEST RDI,RDI
JZ @@25
MOV DL,U8 [RDI]
TEST DL,DL
JZ @@20
JMP @@10
@@05: INC RSI
@@10: LODSB
TEST AL,AL
JZ @@25
CMP AL,DL
JNE @@10
DEC RSI
MOV RCX,1
@@15: MOV AL,U8 [RDI+RCX]
TEST AL,AL
JZ @@20
CMP AL,U8 [RSI+RCX]
JNE @@05
INC RCX
JMP @@15
DEC RSI
@@20: MOV RAX,RSI
JMP @@30
@@25: XOR RAX,RAX
@@30: POP RDI
POP RSI
POP RBP
RET1 16
_STRIMATCH::
PUSH RBP
MOV RBP,RSP
PUSH RSI
PUSH RDI
MOV RSI,U64 SF_ARG2[RBP]
TEST RSI,RSI
JZ @@25
MOV RDI,U64 SF_ARG1[RBP]
TEST RDI,RDI
JZ @@25
MOV AL,U8 [RDI]
CALL TO_UPPER
MOV DL,AL
TEST DL,DL
JZ @@20
JMP @@10
@@05: INC RSI
@@10: LODSB
CALL TO_UPPER
TEST AL,AL
JZ @@25
CMP AL,DL
JNE @@10
DEC RSI
MOV RCX,1
@@15: MOV AL,U8 [RDI+RCX]
CALL TO_UPPER
TEST AL,AL
JZ @@20
MOV BL,U8 [RSI+RCX]
XCHG AL,BL
CALL TO_UPPER
CMP AL,BL
JNE @@05
INC RCX
JMP @@15
DEC RSI
@@20: MOV RAX,RSI
JMP @@30
@@25: XOR RAX,RAX
@@30: POP RDI
POP RSI
POP RBP
RET1 16
}
_extern _STRCMP I64 StrCmp(
U8 *st1,U8 *st2); //Compare two strings.
_extern _STRICMP I64 StrICmp(
U8 *st1,U8 *st2); //Compare two strings, ignoring case.
_extern _STRNCMP I64 StrNCmp(
U8 *st1,U8 *st2,I64 n); //Compare N bytes in two strings.
_extern _STRNICMP I64 StrNICmp(
U8 *st1,U8 *st2,I64 n); //Compare N bytes in two strings, ignoring case.
_extern _STRMATCH U8 *StrMatch(
U8 *needle,U8 *haystack_str); //Scan for string in string.
_extern _STRIMATCH U8 *StrIMatch(
U8 *needle,U8 *haystack_str);//Scan for string in string, ignoring case.
_extern _STRCPY U0 StrCpy(
U8 *dst,U8 *src); //Copy string.
//These bitmaps go to 0-511 so that $LK,"Lex",A="MN:Lex"$() can use them with $LK,"Token Codes",A="MN:TK_EOF"$.
U32
char_bmp_alpha[16]=
{0x0000000,0x00000000,0x87FFFFFF,0x07FFFFFE,
0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,
0,0,0,0,0,0,0,0},
char_bmp_alpha_numeric[16]=
{0x0000000,0x03FF0000,0x87FFFFFF,0x07FFFFFE,
0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,
0,0,0,0,0,0,0,0},
char_bmp_alpha_numeric_no_at[16]=
{0x0000000,0x03FF0000,0x87FFFFFE,0x07FFFFFE,
0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,
0,0,0,0,0,0,0,0},
char_bmp_word[16]=
{0x0000000,0x03FF0080,0x87FFFFFE,0x07FFFFFE,
0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,
0,0,0,0,0,0,0,0},
char_bmp_filename[16]=
{0x0000000,0x03FF73FB,0xEFFFFFFF,0x6FFFFFFF,
0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,
0,0,0,0,0,0,0,0},
char_bmp_dec_numeric[16]=
{0x0000000,0x03FF0000,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
char_bmp_hex_numeric[16]=
{0x0000000,0x03FF0000,0x7E,0x7E,0,0,0,0,0,0,0,0,0,0,0,0},
char_bmp_white_space[16]=
{0x80002600,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
char_bmp_non_eol_white_space[16]=
{0x80000200,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
char_bmp_zero_cr_nl_cursor[16]=
{0x00002421,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
char_bmp_zero_tab_cr_nl_cursor[16]=
{0x00002621,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
char_bmp_zero_tab_cr_nl_cursor_dollar[16]=
{0x00002621,0x10,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
char_bmp_macro[16]=
{0x80002600,0xFFFFFFDF,0xFFFFFFFF,0x7FFFFFFF,
0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,
0,0,0,0,0,0,0,0},
char_bmp_printable[16]=
{0x80002600,0xFFFFFFFF,0xFFFFFFFF,0x7FFFFFFF,
0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,
0,0,0,0,0,0,0,0},
char_bmp_displayable[16]=
{0x80000000,0xFFFFFFFF,0xFFFFFFFF,0x7FFFFFFF,
0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,
0,0,0,0,0,0,0,0},
char_bmp_safe_dollar[16]=
{0x80000000,0xFFFFFFEF,0xFFFFFFFF,0x7FFFFFFF,
0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,
0,0,0,0,0,0,0,0},//same but no dollar sign
char_bmp_non_eol[16]=
{0xFFFFDBFE,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,
0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,
0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,
0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF};
U8 *LstSub(I64 sub, U8 *lst)
{//Point to lst entry.
//Not efficient. Use an array of U8 ptrs for efficiency.
if (!lst) return NULL;
while (*lst && sub>0) {
while (*lst) //Advance to end of cur entry.
lst++;
lst++; //Skip trailing zero.
if (*lst=='@') //Check for '@' alias lst entry.
lst++;
else
sub--;
}
if (sub||!*lst)
return NULL;
else
return lst;
}
I64 LstMatch(U8 *needle, U8 *haystack_lst,I64 flags=0)
{//-2 if Ambiguous
// -1 if not found
// Not efficient. Use hash tables for efficiency.
I64 n,sub=0,res=-1;
U8 *ptr;
Bool exact_match=FALSE;
if (!haystack_lst) return -1;
n=StrLen(needle);
while (*haystack_lst) {
if (*haystack_lst=='@') { //Check for '@' alias haystack_lst entry
sub--;
haystack_lst++;
}
ptr=needle;
if (flags & LMF_IGNORE_CASE)
while (*ptr && ToUpper(*ptr)==ToUpper(*haystack_lst)) {
ptr++;
haystack_lst++;
}
else
while (*ptr && *ptr==*haystack_lst) {
ptr++;
haystack_lst++;
}
if (!*ptr) { //Did we reach end of needle?
if (!*haystack_lst) //Did we reach end of haystack_lst?
return sub; //Found Exact match
else {
if (res!=-1) {
if (!exact_match)
res=-2; //Ambiguous unless later exact match.
} else {
if (!(flags & LMF_EXACT))
res=sub;
}
}
}
while (*haystack_lst) //Advance to end of cur entry.
haystack_lst++;
haystack_lst++; //Skip trailing zero
sub++;
}
return res;
}
I64 StrOcc(U8 *src, I64 ch)
{//Count occurrences of a char.
I64 i=0;
if (!src) return 0;
while (*src)
if (*src++==ch)
i++;
return i;
}
I64 Spaces2Tabs(U8 *dst,U8 *src)
{//Src buf with spaces to dst buf without.
U8 *src2;
I64 chged=0,space_cnt,space_cnt2,col=0;
if (*src)
while (TRUE) {
src2=src;
while (*src2==CH_SPACE)
src2++;
space_cnt=src2-src;
while (col+space_cnt>=8) {
space_cnt2=8-col;
if (space_cnt2==1)
*dst++=CH_SPACE;
else {
*dst++='\t';
chged+=space_cnt2-1;
}
space_cnt-=space_cnt2;
col=0;
}
if (*src2=='\t') {
if (space_cnt==1 && col==7)
*dst++=CH_SPACE;
else
chged+=space_cnt;
*dst++='\t';
col=0;
} else {
while (space_cnt--) {
*dst++=CH_SPACE;
if (++col==8)
col=0;
}
if (*src2) {
*dst++=*src2;
if (++col==8)
col=0;
} else
break;
}
src=++src2;
}
*dst=0;
return chged;
}
U8 *StrUtil(U8 *_src,I64 flags)
{//Modifies in place. See $LK,"flags",A="MN:SUF_REM_SPACES"$ for all the options.
U8 *src=_src,*dst=_src;
I64 ch;
if (flags & SUF_REM_LEADING)
while (Bt(char_bmp_white_space,*src))
src++;
while (ch=*src++)
if (Bt(char_bmp_white_space,ch)) {
if (!(flags & SUF_REM_SPACES)) {
if (flags & SUF_SINGLE_SPACE) {
*dst++ = CH_SPACE;
while ((ch=*src++) && Bt(char_bmp_white_space,ch));
src--;
} else
*dst++ = ch;
}
} else if (!(flags & SUF_REM_CTRL_CHARS) || ch>=CH_SHIFT_SPACE)
*dst++=ch;
*dst=0;
if (flags & SUF_REM_TRAILING)
while (dst!=_src && (!*dst || Bt(char_bmp_white_space,*dst)))
*dst-- =0;
if (flags & SUF_TO_UPPER)
for (dst=_src;*dst;dst++) {
ch=*dst;
if ('a'<=ch<='z')
*dst=ch-0x20;
}
if (flags & SUF_TO_LOWER)
for (dst=_src;*dst;dst++) {
ch=*dst;
if ('A'<=ch<='Z')
*dst=ch+0x20;
}
if (flags & SUF_SAFE_DOLLAR)
for (dst=_src;*dst;dst++) {
ch=*dst;
if (!Bt(char_bmp_safe_dollar,*dst))
*dst='.';
}
if (flags & SUF_S2T)
Spaces2Tabs(_src,_src);
return _src;
}
U8 *StrFirstOcc(U8 *src,U8 *marker)
{//Point to 1st occurrence of marker set in str.
I64 ch;
while ((ch=*src++) && !StrOcc(marker,ch));
if (ch)
return src-1;
else
return NULL;
}
U8 *StrFirstRem(U8 *src,U8 *marker,U8 *dst=NULL)
{//Remove first str segment and place in dst buf or NULL.
I64 ch;
U8 *ptr=src,*res=dst;
if (dst) {
while ((ch=*ptr++) && !StrOcc(marker,ch))
*dst++=ch;
*dst=0;
} else
while ((ch=*ptr++) && !StrOcc(marker,ch));
if (ch)
StrCpy(src,ptr);
else
*src=0;
return res;
}
U8 *StrLastOcc(U8 *src,U8 *marker)
{//Point to last occurrence of market set in str.
I64 ch;
U8 *res=NULL;
while (ch=*src++)
if (StrOcc(marker,ch))
res=src-1;
return res;
}
U8 *StrLastRem(U8 *src,U8 *marker,U8 *dst=NULL)
{//Remove last str segment and place in dst buf or NULL.
U8 *ptr;
if (ptr=StrLastOcc(src,marker)) {
if (dst)
StrCpy(dst,ptr+1);
*ptr=0;
} else {
if (dst)
StrCpy(dst,src);
*src=0;
}
return dst;
}
U8 *StrFind(U8 *needle,U8 *haystack_str,I64 flags=0)
{//Find needle_str in haystack_str with options.
Bool cont;
U8 *saved_haystack_str=haystack_str;
I64 plen=StrLen(needle);
do {
cont=FALSE;
if (flags & SFF_IGNORE_CASE)
haystack_str=StrIMatch(needle,haystack_str);
else
haystack_str=StrMatch(needle,haystack_str);
if (haystack_str && flags & SFF_WHOLE_LABELS_BEFORE &&
haystack_str!=saved_haystack_str &&
Bt(char_bmp_alpha_numeric,*(haystack_str-1))) {
haystack_str++;
if (*haystack_str)
cont=TRUE;
else
haystack_str=NULL;
}
if (haystack_str && flags & SFF_WHOLE_LABELS_AFTER &&
Bt(char_bmp_alpha_numeric,*(haystack_str+plen))) {
haystack_str++;
if (*haystack_str)
cont=TRUE;
else
haystack_str=NULL;
}
} while (cont);
return haystack_str;
}
Bool WildMatch(U8 *test_str,U8 *wild_str)
{//Wildcard match with '*' and '?'.
I64 ch1,ch2;
U8 *fall_back_src=NULL,*fall_back_wild=NULL;
while (TRUE) {
if (!(ch1=*test_str++)) {
if (*wild_str && *wild_str!='*')
return FALSE;
else
return TRUE;
} else {
if (!(ch2=*wild_str++))
return FALSE;
else {
if (ch2=='*') {
fall_back_wild=wild_str-1;
fall_back_src=test_str;
if (!(ch2=*wild_str++))
return TRUE;
while (ch2!=ch1)
if (!(ch1=*test_str++))
return FALSE;
} else
if (ch2!='?' && ch1!=ch2) {
if (fall_back_wild) {
wild_str=fall_back_wild;
test_str=fall_back_src;
fall_back_wild=NULL;
fall_back_src=NULL;
} else
return FALSE;
}
}
}
}
}
+187
View File
@@ -0,0 +1,187 @@
U8 *Tabs2Spaces(U8 *src)
{//MAlloc str with tabs to spaces.
I64 ch,i,j,l=StrLen(src)<<1+2,col=0;
U8 *dst=MAlloc(l),*tmp;
while (ch=*src++) {
if (ch=='\t') {
j=(col+8) & ~7;
for (i=col;i<j;i++) {
dst[i]=CH_SPACE;
if (i>=l-2) {
tmp=MAlloc(l<<1);
MemCpy(tmp,dst,i+1);
Free(dst);
l<<=1;
dst=tmp;
}
}
col=j;
} else {
dst[col]=ch;
if (col>=l-2) {
tmp=MAlloc(l<<1);
MemCpy(tmp,dst,col+1);
Free(dst);
l<<=1;
dst=tmp;
}
col++;
}
}
dst[col]=0;
return dst;
}
U8 *ScaleIndent(U8 *src,F64 indent_scale_factor)
{//MAlloced str. 8*0.25-->2 or 8*2.0-->16
I64 ch,i,col=0;
U8 *dst,*dst2;
while (ch=*src++) {
if (ch=='\t')
col=(col+8) & -0x8;
else if (ch==CH_SPACE)
col++;
else
break;
}
src--;
col=Round(indent_scale_factor*col);
dst=dst2=MAlloc(StrLen(src)+col/8+col&7+1);
for (i=col/8;i>0;i--)
*dst2++='\t';
for (i=col&7;i>0;i--)
*dst2++=CH_SPACE;
StrCpy(dst2,src);
return dst;
}
U8 *MStrUtil(U8 *src,I64 flags,F64 indent_scale_factor=0)
{//MAlloc $LK,"StrUtil",A="MN:StrUtil"$().
U8 *dst=StrNew(src),*dst2,*tmp;
StrUtil(dst,flags);
if (flags & SUF_T2S) {
tmp=Tabs2Spaces(dst);
Free(dst);
dst=tmp;
}
if (flags & SUF_SCALE_INDENT)
dst2=ScaleIndent(dst,indent_scale_factor);
else
dst2=StrNew(dst); //Shorten to just right size.
Free(dst);
return dst2;
}
U0 GetOutOfDollar()
{//If a $$ has been printed, print another $$ to exit mode.
CDoc *doc;
if (IsRaw) {
if (text.raw_flags&RWF_IN_DOLLAR)
'$$';
} else {
if (fp_doc_put && (doc=(*fp_doc_put)(Fs)) && doc->flags&DOCF_IN_DOLLAR)
'$$';
}
}
Bool YorN()
{//Wait for user to answer Y or N.
I64 ch;
"(y or n)? ";
while (TRUE) {
ch=ToUpper(GetChar(,FALSE));
if (ch=='Y') {
"$$PT$$YES$$FG$$\n";
return TRUE;
} else if (ch=='N') {
"$$PT$$NO$$FG$$\n";
return FALSE;
}
}
}
I64 PressAKey()
{//Print "Press a key" and wait for non-zero $LK,"ASCII",A="MN:CH_CTRLA"$ key.
"$$BK,1$$PRESS A KEY$$BK,0$$\n";
return GetChar(,FALSE);
}
Bool AreYouSure()
{//Print "Are you sure" and waits for Y or N.
"ARE YOU SURE ";
return YorN;
}
U0 Help()
{//Dbg help or master help index file.
if (IsDbgMode)
DbgHelp;
else
PopUp("Type(\"::/Doc/HelpIndex.DD\");DocTop;View;");
}
U0 ScanFlags(U8 *_dst_flags,U8 *lst,U8 *src)
{/*More than 64 flags. Flags passed by ref.
Examples:
$LK,"ScanFlags",A="FF:::/Adam/Opt/Utils/Diff.HC,ScanFlags:2"$(&fuf_flags,Define("ST_FILE_UTIL_FLAGS"),fu_flags);
I64 flags=0;
ScanFlags(&flags,"R\0L\0Dump\0Scan\0","+Dump-R"); //Sets Bit#2, Clears Bit#0.
*/
I64 i;
U8 *buf,*ptr;
if (src) {
buf=MAlloc(StrLen(src)+1);
while (*src) {
while (*src && *src!='+' && *src!='-')
src++;
if (*src=='+') {
src++;
if (*src) {
ptr=buf;
while (*src && *src!='+' && *src!='-' &&
*src!=CH_SPACE && *src!=CH_SHIFT_SPACE)
*ptr++=*src++;
*ptr=0;
i=LstMatch(buf,lst);
if (i>=0)
LBts(_dst_flags,i);
else {
Free(buf);
throw('ScanFlag');
}
}
} else if (*src=='-') {
src++;
if (*src) {
ptr=buf;
while (*src && *src!='+' && *src!='-' &&
*src!=CH_SPACE && *src!=CH_SHIFT_SPACE)
*ptr++=*src++;
*ptr=0;
i=LstMatch(buf,lst);
if (i>=0)
LBtr(_dst_flags,i);
else {
Free(buf);
throw('ScanFlag');
}
}
}
}
Free(buf);
}
}
U8 *StrPrintFlags(U8 *dst,U8 *lst,I64 flags)
{//Only 64 flags. Flags passed by value.
I64 i;
*dst=0;
while (flags) {
i=Bsf(flags);
Btr(&flags,i);
CatPrint(dst,"+%z",i,lst);
}
return dst;
}
+920
View File
@@ -0,0 +1,920 @@
U0 SPutChar(U8 **_dst,U8 ch,U8 **_buf)
{
I64 i;
U8 *dst=*_dst,*buf;
if (_buf) {
buf=*_buf;
i=dst-buf;
if (i>=MSize(buf)) {
buf=MAlloc(i<<1+1);
MemCpy(buf,*_buf,i);
Free(*_buf);
dst=buf+i;
*_buf=buf;
}
}
*dst++=ch;
*_dst=dst;
}
U0 OutStr(U8 *ptr,U8 **_buf,U8 **_dst,I64 len,I64 flags)
{
I64 i,j;
if (!ptr)
i=0;
else
i=StrLen(ptr);
if (flags&PRTF_TRUNCATE && i>len)
i=len;
if (flags&PRTF_LEFT_JUSTIFY) {
for (j=0;j<i;j++)
SPutChar(_dst,*ptr++,_buf);
for (j=0;j<len-i;j++)
SPutChar(_dst,CH_SPACE,_buf);
} else {
for (j=0;j<len-i;j++)
SPutChar(_dst,CH_SPACE,_buf);
for (j=len-i;j<len;j++)
SPutChar(_dst,*ptr++,_buf);
}
}
U8 *MPrintTime(CDate cdt)
{
CDateStruct ds;
Date2Struct(&ds,cdt+local_time_offset);
return MStrPrint("%02d:%02d:%02d",ds.hour,ds.min,ds.sec);
}
U8 *MPrintDate(CDate cdt)
{
CDateStruct ds;
Date2Struct(&ds,cdt+local_time_offset);
return MStrPrint("%02d/%02d/%02d",ds.mon,ds.day_of_mon,ds.year%100);
}
U8 *MPrintQ(U8 *ptr,I64 flags)
{
U8 **_buf,*buf,**_dst,*dst,buf2[8],*ptr2;
I64 ch;
buf=MAlloc(STR_LEN);
_buf=&buf;
dst=buf;
_dst=&dst;
if (ptr)
while (ch=*ptr++) {
switch (ch) {
case '$$':
if (flags&PRTF_DOLLAR) {
SPutChar(_dst,'\\',_buf);
SPutChar(_dst,'d',_buf);
} else {
SPutChar(_dst,ch,_buf);
SPutChar(_dst,ch,_buf);
}
break;
case '%':
SPutChar(_dst,ch,_buf);
if (flags&PRTF_SLASH)
SPutChar(_dst,ch,_buf);
break;
case '\n':
SPutChar(_dst,'\\',_buf);
SPutChar(_dst,'n',_buf);
break;
case '\r':
SPutChar(_dst,'\\',_buf);
SPutChar(_dst,'r',_buf);
break;
case '\t':
SPutChar(_dst,'\\',_buf);
SPutChar(_dst,'t',_buf);
break;
case '"':
case '\\':
SPutChar(_dst,'\\',_buf);
SPutChar(_dst,ch,_buf);
break;
default:
if (ch>=CH_SHIFT_SPACE && ch!=0x7F)
SPutChar(_dst,ch,_buf);
else {
StrPrint(buf2,"\\x%02X",ch);
ptr2=buf2;
while (*ptr2)
SPutChar(_dst,*ptr2++,_buf);
}
}
}
SPutChar(_dst,0,_buf);
return buf;
}
U8 *MPrintq(U8 *ptr,I64 flags)
{
U8 **_buf,*buf,**_dst,*dst;
I64 i,j,ch,ch1;
buf=MAlloc(STR_LEN);
_buf=&buf;
dst=buf;
_dst=&dst;
if (ptr)
while (ch=*ptr++) {
ch1=*ptr;
switch (ch) {
case '\\':
switch (ch1) {
start:
case '0':
SPutChar(_dst,0,_buf);
break;
case '\'':
SPutChar(_dst,'\'',_buf);
break;
case '\`':
SPutChar(_dst,'\`',_buf);
break;
case '"':
SPutChar(_dst,'"',_buf);
break;
case '\\':
SPutChar(_dst,'\\',_buf);
break;
case 'd':
SPutChar(_dst,'$$',_buf);
break;
case 'n':
SPutChar(_dst,'\n',_buf);
break;
case 'r':
SPutChar(_dst,'\r',_buf);
break;
case 't':
SPutChar(_dst,'\t',_buf);
break;
end:
ptr++;
break;
case 'x':
case 'X':
i=0;
ptr++;
for (j=0;j<2;j++) {
ch1=ToUpper(*ptr++);
if (Bt(char_bmp_hex_numeric,ch1)) {
if (ch1<='9')
i=i<<4+ch1-'0';
else
i=i<<4+ch1-'A'+10;
} else {
ptr--;
break;
}
}
SPutChar(_dst,i,_buf);
break;
default:
SPutChar(_dst,ch,_buf);
}
break;
case '$$':
SPutChar(_dst,ch,_buf);
if (ch1=='$$')
ptr++;
break;
case '%':
SPutChar(_dst,ch,_buf);
if (flags&PRTF_SLASH && ch1=='%')
ptr++;
break;
default:
SPutChar(_dst,ch,_buf);
}
}
SPutChar(_dst,0,_buf);
return buf;
}
U8 *sys_pos_pows_lets=" KMGTPEZY",
*sys_neg_pows_lets=" mænpfazy",
*sys_pos_pows_lst="kilo\0mega\0giga\0tera\0peta\0exa\0zetta\0yotta\0",
*sys_neg_pows_lst="milli\0micro\0nano\0pico\0femto\0atto\0zepto\0yocto\0";
#define TMP_BUF_LEN 256
#define SLOP 8
U8 *StrPrintJoin(U8 *dst,U8 *fmt,I64 argc,I64 *argv)
{/*$LK,"Print(\"\") Fmt Strings",A="FI:::/Doc/Print.DD"$
In float formatting, do not exceed 18-digits
before or after the decimal point
because the numbers before and after
the decimal point are stored
in 64-bits. Use exponentiated forms
to avoid this.
*/
I64 i,j,l,ch,k,k0,n,n0,len,dec_len,flags,old_flags,
aux_fmt_num,comma_cnt,comma_fmt_cnt,cur_arg=0;
U64 m;
F64 d,d1;
CDoc *doc;
U8 *ptr,**_buf,*buf,**_dst,tmp_buf[TMP_BUF_LEN],tmp_buf2[TMP_BUF_LEN*2];
if (!fmt)
throw('StrPrint');
if (dst) {
_buf=NULL;
buf=dst;
} else {
buf=MAlloc(STR_LEN);
_buf=&buf;
dst=buf;
}
_dst=&dst;
while (ch = *fmt++) {
if (ch=='%') {
flags=0;
if (*fmt=='-') {
flags|=PRTF_LEFT_JUSTIFY;
fmt++;
}
if (*fmt=='0') {
flags|=PRTF_PAD_ZERO;
fmt++;
}
len=0;
while ('0'<=*fmt<='9')
len=len*10+ *fmt++ -'0';
if (*fmt=='*') {
fmt++;
if (cur_arg>=argc)
throw('StrPrint');
len=argv[cur_arg++];
}
dec_len=0;
if (*fmt=='.') {
fmt++;
while ('0'<=*fmt<='9')
dec_len=dec_len*10+ *fmt++ -'0';
if (*fmt=='*') {
fmt++;
if (cur_arg>=argc)
throw('StrPrint');
dec_len=argv[cur_arg++];
}
flags|=PRTF_DECIMAL;
}
aux_fmt_num=0;
while (TRUE) {
switch (*fmt) {
start:
case '$$':
flags|=PRTF_DOLLAR;
break;
case '/':
flags|=PRTF_SLASH;
break;
case ',':
flags|=PRTF_COMMA;
break;
case 't':
flags|=PRTF_TRUNCATE;
break;
case 'l': //harmless
break;
end:
fmt++;
break;
case 'h':
fmt++;
flags|=PRTF_AUX_FMT_NUM;
if (*fmt=='?') {
fmt++;
flags|=PRTF_QUESTION;
} else {
if (*fmt=='*') {
fmt++;
if (cur_arg>=argc)
throw('StrPrint');
aux_fmt_num=argv[cur_arg++];
} else {
if (*fmt=='-') {
fmt++;
flags|=PRTF_NEG_AUX_FMT_NUM;
}
while ('0'<=*fmt<='9')
aux_fmt_num=aux_fmt_num*10+ *fmt++ -'0';
if (flags&PRTF_NEG_AUX_FMT_NUM)
aux_fmt_num=-aux_fmt_num;
}
}
break;
default:
goto sp_arg;
}
}
sp_arg:
k=0;
switch (*fmt++) {
start:
case 'F':
if (cur_arg>=argc)
throw('StrPrint');
if (flags&PRTF_DOLLAR) {
doc=argv[cur_arg++];
old_flags=doc->flags;
doc->flags|=DOCF_NO_CURSOR;
ptr=DocSave(doc);
doc->flags=old_flags;
} else
ptr=FileRead(argv[cur_arg++]);
break;
case 'Q':
if (cur_arg>=argc)
throw('StrPrint');
ptr=MPrintQ(argv[cur_arg++],flags);
break;
case 'q':
if (cur_arg>=argc)
throw('StrPrint');
ptr=MPrintq(argv[cur_arg++],flags);
break;
case 'D':
if (cur_arg>=argc)
throw('StrPrint');
ptr=MPrintDate(argv[cur_arg++]);
break;
case 'T':
if (cur_arg>=argc)
throw('StrPrint');
ptr=MPrintTime(argv[cur_arg++]);
break;
end:
OutStr(ptr,_buf,_dst,len,flags);
Free(ptr);
break;
start:
case 's':
if (cur_arg>=argc)
throw('StrPrint');
ptr=argv[cur_arg++];
break;
case 'S':
if (cur_arg>=argc)
throw('StrPrint');
ptr=Define(argv[cur_arg++]);
break;
case 'z':
if (cur_arg+1>=argc)
throw('StrPrint');
ptr=LstSub(argv[cur_arg],argv[cur_arg+1]);
cur_arg=cur_arg+2;
break;
case 'Z':
if (cur_arg+1>=argc)
throw('StrPrint');
ptr=DefineSub(argv[cur_arg],argv[cur_arg+1]);
cur_arg=cur_arg+2;
break;
end:
OutStr(ptr,_buf,_dst,len,flags);
break;
start:
case 'c':
if (cur_arg>=argc)
throw('StrPrint');
tmp_buf[0](I64)=argv[cur_arg++];
tmp_buf[8]=0;
break;
case 'C':
if (cur_arg>=argc)
throw('StrPrint');
tmp_buf[0](I64)=argv[cur_arg++];
tmp_buf[8]=0;
ptr=tmp_buf;
while (*ptr) {
*ptr=ToUpper(*ptr);
ptr++;
}
break;
end:
if (!(flags&PRTF_AUX_FMT_NUM))
aux_fmt_num=1;
while (aux_fmt_num-->0)
OutStr(tmp_buf,_buf,_dst,len,flags);
break;
case 'p':
if (cur_arg>=argc)
throw('StrPrint');
StrPrintFunSeg(tmp_buf,argv[cur_arg++],len,flags);
OutStr(tmp_buf,_buf,_dst,len,flags);
break;
case 'P':
if (cur_arg>=argc)
throw('StrPrint');
StrPrintFunSeg(tmp_buf,argv[cur_arg],len,flags);
if (!IsRaw || !_buf) {
StrPrint(tmp_buf2,"$$LK,\"%s\",A=\"AD:0x%X\"$$",
tmp_buf,argv[cur_arg]);
OutStr(tmp_buf2,_buf,_dst,len,flags);
} else
OutStr(tmp_buf,_buf,_dst,len,flags);
cur_arg++;
break;
case 'd':
if (cur_arg>=argc)
throw('StrPrint');
m=argv[cur_arg++];
if (m(I64)<0) {
flags|=PRTF_NEG;
m=-m;
}
sp_out_dec:
if (flags&PRTF_AUX_FMT_NUM) {
if (!len) len=12;
d=m;
goto sp_out_eng;
}
if (flags&PRTF_COMMA) {
comma_fmt_cnt=comma_cnt=3;
do {
tmp_buf[k++]=ModU64(&m,10)+'0';
if (!m) break;
if (!--comma_cnt) {
tmp_buf[k++]=',';
comma_cnt=3;
}
} while (k<TMP_BUF_LEN-SLOP);
sp_out_comma_num:
if (flags&PRTF_NEG)
i=1;
else
i=0;
if (len<0)
len=0;
if (flags&PRTF_TRUNCATE && k+i>len)
k=len-i;
if (k<0)
k=0;
if (flags&PRTF_PAD_ZERO) {
if (flags&PRTF_NEG)
SPutChar(_dst,'-',_buf);
comma_cnt=(len-k-i+comma_fmt_cnt-comma_cnt+1)
%(comma_fmt_cnt+1)+1;
for (;i<len-k;i++) {
if (!--comma_cnt) {
SPutChar(_dst,',',_buf);
comma_cnt=comma_fmt_cnt;
if (++i>=len-k)
break;
}
SPutChar(_dst,'0',_buf);
}
} else {
for (;i<len-k;i++)
SPutChar(_dst,CH_SPACE,_buf);
if (flags&PRTF_NEG)
SPutChar(_dst,'-',_buf);
}
} else {
do {
tmp_buf[k++]=ModU64(&m,10)+'0';
if (!m) break;
} while (k<TMP_BUF_LEN-SLOP);
sp_out_num:
if (flags&PRTF_NEG)
i=1;
else
i=0;
if (len<0)
len=0;
if (flags&PRTF_TRUNCATE && k+i>len)
k=len-i;
if (k<0)
k=0;
if (flags&PRTF_PAD_ZERO) {
if (flags&PRTF_NEG)
SPutChar(_dst,'-',_buf);
for (;i<len-k;i++)
SPutChar(_dst,'0',_buf);
} else {
for (;i<len-k;i++)
SPutChar(_dst,CH_SPACE,_buf);
if (flags&PRTF_NEG)
SPutChar(_dst,'-',_buf);
}
}
for (i=k-1;i>=0;i--)
SPutChar(_dst,tmp_buf[i],_buf);
break;
case 'u':
if (cur_arg>=argc)
throw('StrPrint');
m=argv[cur_arg++];
goto sp_out_dec;
case 'f':
if (cur_arg>=argc)
throw('StrPrint');
d=argv[cur_arg++](F64);
if (d<0) {
flags|=PRTF_NEG;
d=-d;
}
if (d==ì) {
sp_out_inf:
if (flags&PRTF_NEG)
i=1;
else
i=0;
k=1;
if (len<0)
len=0;
if (flags&PRTF_TRUNCATE && k+i>len)
k=len-i;
if (k<0)
k=0;
for (;i<len-k;i++)
SPutChar(_dst,CH_SPACE,_buf);
if (flags&PRTF_NEG)
SPutChar(_dst,'-',_buf);
for (i=0;i<k;i++)
SPutChar(_dst,'ì',_buf);
break;
}
sp_out_f:
if (dec_len<0)
dec_len=0;
n=Log10(d);
if (i=dec_len) {
if (flags&PRTF_COMMA)
i=i-i/4;
if (n+i>17) {
n+=i-17;
d*=Pow10I64(i-n);
} else {
n=0;
d*=Pow10I64(i);
}
i=dec_len;
} else if (n>17) {
n-=17;
d*=Pow10I64(-n);
} else
n=0;
m=Round(d);
if (flags&PRTF_COMMA) {
comma_cnt=i&3;
while (i-- && k<TMP_BUF_LEN-SLOP) {
if (i>2 && !comma_cnt--) {
tmp_buf[k++]=',';
comma_cnt=2;
if (!--i) break;
}
if (n) {
n--;
tmp_buf[k++]='0';
} else
tmp_buf[k++]=ModU64(&m,10)+'0';
if (!i) break;
}
} else {
while (i-- && k<TMP_BUF_LEN-SLOP) {
if (n) {
n--;
tmp_buf[k++]='0';
} else
tmp_buf[k++]=ModU64(&m,10)+'0';
}
}
if (dec_len)
tmp_buf[k++]='.';
if (flags&PRTF_COMMA) {
comma_cnt=3;
do {
if (n) {
n--;
tmp_buf[k++]='0';
} else
tmp_buf[k++]=ModU64(&m,10)+'0';
if (!m) break;
if (!--comma_cnt) {
tmp_buf[k++]=',';
comma_cnt=3;
}
} while (k<TMP_BUF_LEN-SLOP);
} else {
do {
if (n) {
n--;
tmp_buf[k++]='0';
} else
tmp_buf[k++]=ModU64(&m,10)+'0';
if (!m) break;
} while (k<TMP_BUF_LEN-SLOP);
}
goto sp_out_num;
case 'e':
if (!len) len=12;
flags|=PRTF_TRUNCATE;
if (cur_arg>=argc)
throw('StrPrint');
d=argv[cur_arg++](F64);
if (d<0) {
flags|=PRTF_NEG;
d=-d;
}
if (d==ì) goto sp_out_inf;
if (d)
n=Floor(Log10(d));
else
n=0;
sp_out_e:
d/=Pow10I64(n);
k0=k;
for (l=0;l<2;l++) {
n0=n;
if (n<0) {
n=-n;
flags|=PRTF_NEG_E;
} else
flags&=~PRTF_NEG_E;
i=3;
do tmp_buf[k++]=ModU64(&n,10)+'0';
while (n && i--);
if (flags&PRTF_NEG_E)
tmp_buf[k++]='-';
tmp_buf[k++]='e';
dec_len=len-k-2;
if (flags&PRTF_NEG)
dec_len--;
if (d) {
d1=d+Pow10I64(-dec_len)/2;
if (d1<1.0) {
d*=10;
n=n0-1;
k=k0;
} else if (d1>=10) {
d/=10;
n=n0+1;
k=k0;
} else
break;
} else
break;
}
goto sp_out_f;
case 'g':
if (!len) len=12;
flags|=PRTF_TRUNCATE;
if (cur_arg>=argc)
throw('StrPrint');
d=argv[cur_arg++](F64);
if (d<0) {
flags|=PRTF_NEG;
d=-d;
}
if (d==ì) goto sp_out_inf;
if (d)
n=Floor(Log10(d));
else
n=0;
if (n>=len-1-dec_len || n<-(dec_len-1))
goto sp_out_e;
else
goto sp_out_f;
case 'n':
if (!len) len=12;
flags|=PRTF_TRUNCATE;
if (cur_arg>=argc)
throw('StrPrint');
d=argv[cur_arg++](F64);
if (d<0) {
flags|=PRTF_NEG;
d=-d;
}
sp_out_eng: //Engineering notation
if (d==ì) goto sp_out_inf;
if (d)
n=FloorI64(Floor(Log10(d)),3);
else
n=0;
d/=Pow10I64(n);
if (n<0) {
n=-n;
flags|=PRTF_NEG_E;
}
if (flags&PRTF_AUX_FMT_NUM && -24<=n<=24) {
if (flags&PRTF_QUESTION) {
if (flags&PRTF_NEG_E)
i=-n/3;
else
i=n/3;
j=0;
} else {
if (flags&PRTF_NEG_E)
j=-n-aux_fmt_num;
else
j=n-aux_fmt_num;
d*=Pow10I64(j);
i=aux_fmt_num/3;
}
if (i<0)
tmp_buf[k++]=sys_neg_pows_lets[-i];
else if (i>0)
tmp_buf[k++]=sys_pos_pows_lets[i];
else if (len!=0)
tmp_buf[k++]=CH_SPACE;
if (!(flags&PRTF_DECIMAL)) {
dec_len=len-k-2;
if (flags&PRTF_NEG)
dec_len--;
if (j>0) {
if (flags&PRTF_COMMA)
dec_len-=4*j/3;
else
dec_len-=j;
}
d1=d+Pow10I64(-dec_len+1)/2;
if (d1>=10) {
dec_len--;
if (d1>=100)
dec_len--;
}
}
} else {
i=3;
do tmp_buf[k++]=ModU64(&n,10)+'0';
while (n && i--);
if (flags&PRTF_NEG_E)
tmp_buf[k++]='-';
tmp_buf[k++]='e';
if (!dec_len) {
dec_len=len-k-2;
if (flags&PRTF_NEG)
dec_len--;
d1=d+Pow10I64(-dec_len+1)/2;
if (d1>=10) {
dec_len--;
if (d1>=100)
dec_len--;
}
}
}
if (flags&PRTF_COMMA) {
if (len && dec_len>0 && !(dec_len&3))
tmp_buf[k++]=',';
dec_len-=dec_len/4;
}
goto sp_out_f;
case 'X':
if (cur_arg>=argc)
throw('StrPrint');
m=argv[cur_arg++];
if (flags&PRTF_COMMA) {
comma_fmt_cnt=comma_cnt=4;
do {
tmp_buf[k]= m&15 +'0';
if (tmp_buf[k]>'9') tmp_buf[k]+='A'-0x3A;
k++;
m>>=4;
if (!m) break;
if (!--comma_cnt) {
tmp_buf[k++]=',';
comma_cnt=4;
}
} while (k<TMP_BUF_LEN-SLOP);
goto sp_out_comma_num;
} else {
do {
tmp_buf[k]= m&15 +'0';
if (tmp_buf[k]>'9') tmp_buf[k]+='A'-0x3A;
k++;
m>>=4;
} while (m && k<TMP_BUF_LEN-SLOP);
goto sp_out_num;
}
case 'x':
if (cur_arg>=argc)
throw('StrPrint');
m=argv[cur_arg++];
if (flags&PRTF_COMMA) {
comma_fmt_cnt=comma_cnt=4;
do {
tmp_buf[k]= m&15 +'0';
if (tmp_buf[k]>'9') tmp_buf[k]+='a'-0x3A;
k++;
m>>=4;
if (!m) break;
if (!--comma_cnt) {
tmp_buf[k++]=',';
comma_cnt=4;
}
} while (k<TMP_BUF_LEN-SLOP);
goto sp_out_comma_num;
} else {
do {
tmp_buf[k]= m&15 +'0';
if (tmp_buf[k]>'9') tmp_buf[k]+='a'-0x3A;
k++;
m>>=4;
} while (m && k<TMP_BUF_LEN-SLOP);
goto sp_out_num;
}
case 'b':
case 'B':
if (cur_arg>=argc)
throw('StrPrint');
m=argv[cur_arg++];
if (flags&PRTF_COMMA) {
comma_fmt_cnt=comma_cnt=4;
do {
tmp_buf[k++]= m&1 +'0';
m>>=1;
if (!m) break;
if (!--comma_cnt) {
tmp_buf[k++]=',';
comma_cnt=4;
}
} while (k<TMP_BUF_LEN-SLOP);
goto sp_out_comma_num;
} else {
do {
tmp_buf[k++]= m&1 +'0';
m>>=1;
} while (m && k<TMP_BUF_LEN-SLOP);
goto sp_out_num;
}
case '%':
SPutChar(_dst,'%',_buf);
break;
}
} else
SPutChar(_dst,ch,_buf);
}
SPutChar(_dst,0,_buf);
return buf;
}
U8 *StrPrint(U8 *dst,U8 *fmt,...)
{//See $LK,"StrPrintJoin",A="MN:StrPrintJoin"$().
return StrPrintJoin(dst,fmt,argc,argv);
}
U8 *CatPrint(U8 *_dst,U8 *fmt,...)
{//StrCat(). See $LK,"StrPrintJoin",A="MN:StrPrintJoin"$().
U8 *dst=_dst;
while (*dst)
dst++;
StrPrintJoin(dst,fmt,argc,argv);
return _dst;
}
U0 Print(U8 *fmt,...)
{//$LK,"Print(\"\") Fmt Strings",A="FI:::/Doc/Print.DD"$. See $LK,"StrPrintJoin",A="MN:StrPrintJoin"$().
//Don't use this. $LK,"See Print() shortcut.",A="FF:::/Doc/HolyC.DD,DemoHolyC"$
U8 *buf=StrPrintJoin(NULL,fmt,argc,argv);
PutS(buf);//Don't use PutS(). $LK,"See Print() shortcut.",A="FF:::/Doc/HolyC.DD,DemoHolyC"$
Free(buf);
}
U8 *MStrPrint(U8 *fmt,...)
{//MAlloc StrPrint. See $LK,"StrPrintJoin",A="MN:StrPrintJoin"$().
U8 *res,*buf=StrPrintJoin(NULL,fmt,argc,argv);
res=StrNew(buf);
Free(buf);
return res;
}
U0 PrintErr(U8 *fmt,...)
{//Print "Err:" and msg in blinking red.
U8 *buf=StrPrintJoin(NULL,fmt,argc,argv);
GetOutOfDollar;
ST_ERR_ST "%s",buf;
Free(buf);
}
U0 PrintWarn(U8 *fmt,...)
{//Print "Warn:" and msg in blinking red.
U8 *buf=StrPrintJoin(NULL,fmt,argc,argv);
GetOutOfDollar;
ST_WARN_ST "%s",buf;
Free(buf);
}
+339
View File
@@ -0,0 +1,339 @@
I64 Str2I64(U8 *st,I64 radix=10,U8 **_end_ptr=NULL)
{//String to I64. Similar to strtoul().
//Allows radix change with "0x20" "0b1010" "0d123" "0o18".
//Be careful of Str2I64("0b101",16)-->0xB101.
Bool neg=FALSE;
I64 ch,res=0;
if (!st || !(2<=radix<=36)) {
if (_end_ptr) *_end_ptr=st;
return 0;
}
while (Bt(char_bmp_white_space,*st))
st++;
while (TRUE)
switch (*st) {
case '-':
st++;
neg=!neg;
break;
case '+':
st++;
break;
case '0':
st++;
ch=ToUpper(*st);
if (ch>='B' && (radix<=10 || ch>'A'+radix-11))
switch (ch) {
case 'B': radix=2; st++; break;
case 'D': radix=10; st++; break;
case 'X': radix=16; st++; break;
}
default:
goto ai_cont;
}
ai_cont:
while (ch=ToUpper(*st++)) {
if (radix>10) {
if ('0'<=ch<='9')
res=res*radix+ch-'0';
else if ('A'<=ch<='A'+radix-11)
res=res*radix+ch-'A'+10;
else
break;
} else if ('0'<=ch<='0'+radix-1)
res=res*radix+ch-'0';
else
break;
}
if (_end_ptr) *_end_ptr=st-1;
if (neg)
return -res;
else
return res;
}
F64 Str2F64(U8 *src,U8 **_end_ptr=NULL)
{/*String to F64.
Does not allow more than 18-digits
before or after the decimal point
because the numbers before and after
the decimal point are stored
in 64-bits. Use exponentiated forms
to avoid this.
*/
I64 i,j,k,ch;
F64 d;
Bool neg=FALSE,neg_e=FALSE;
ch=*src++;
while (Bt(char_bmp_white_space,ch))
ch=*src++;
if (ch=='-') {
neg=TRUE;
ch=*src++;
}
if (!StrNCmp(src-1,"inf",3)) {
d=ì;
src+=3;
goto a2f_end;
}
if (*src=='ì') {
d=ì;
src++;
goto a2f_end;
}
i=0;
while (TRUE) {
if (Bt(char_bmp_dec_numeric,ch))
i=i*10+ch-'0';
else {
if (ch=='.' || ch=='e' || ch=='E')
break;
d=i;
goto a2f_end;
}
ch=*src++;
}
if (ch=='.')
ch=*src++;
k=0;
while (TRUE) {
if (Bt(char_bmp_dec_numeric,ch)) {
i=i*10+ch-'0';
k++;
} else {
if (ch=='e' || ch=='E')
break;
d=i*Pow10I64(-k);
goto a2f_end;
}
ch=*src++;
}
ch=*src++;
if (ch=='-') {
neg_e=TRUE;
ch=*src++;
}
j=0;
while (TRUE) {
if (Bt(char_bmp_dec_numeric,ch))
j=j*10+ch-'0';
else {
if (neg_e)
d=i*Pow10I64(-j-k);
else
d=i*Pow10I64(j-k);
goto a2f_end;
}
ch=*src++;
}
a2f_end:
if (_end_ptr) *_end_ptr=src-1;
if (neg)
return -d;
else
return d;
}
CDate Str2Date(U8 *_src)
{/*"*+nnnn", "*-nnnn", "mm/dd", "mm/dd/yy"
It also supports some funs
SM() start of mon
EM() end of mon
SY() start of year
EY() end of year
Full expressions are not implimented
but you can do stuff like SM(*-7)+3
and it will return the 3rd day after
the start of mon for seven days before
today.
*/
CDate res=0;
CDateStruct ds,ds_now;
U8 *src=MStrUtil(_src,SUF_REM_SPACES|SUF_TO_UPPER),
*v=StrNew(src),
*ptr=src;
Bool start_mon=FALSE,end_mon=FALSE,
start_year=FALSE,end_year=FALSE;
MemSet(&ds,0,sizeof(CDateStruct));
if (!StrNCmp(ptr,"SM(",3)) {
ptr+=3;
start_mon=TRUE;
} else if (!StrNCmp(ptr,"EM(",3)) {
ptr+=3;
end_mon=TRUE;
} else if (!StrNCmp(ptr,"SY(",3)) {
ptr+=3;
start_year=TRUE;
} else if (!StrNCmp(ptr,"EY(",3)) {
ptr+=3;
end_year=TRUE;
}
if (*ptr=='*') {
ptr++;
if (*ptr=='+' || *ptr=='-')
res.date=Str2I64(ptr,,&ptr);
res+=Now+local_time_offset;
} else {
StrFirstRem(ptr,"/",v); //Put mon into v
ds.mon=Str2I64(v);
if (StrOcc(ptr,'/')) {
StrFirstRem(ptr,"/",v); //Put day into v leaving year in ptr
ds.day_of_mon=Str2I64(v);
ds.year=Str2I64(ptr,,&ptr);
if (ds.year<100) //if not 4 digit year
ds.year+=2000;
} else {
ds.day_of_mon=Str2I64(ptr,,&ptr);
Date2Struct(&ds_now,Now+local_time_offset);
ds.year=ds_now.year;
}
res=Struct2Date(&ds);
}
if (*ptr==')') ptr++;
if (start_mon)
res.date=FirstDayOfMon(res.date);
else if (end_mon)
res.date=LastDayOfMon(res.date);
else if (start_year)
res.date=FirstDayOfYear(res.date);
else if (end_year)
res.date=LastDayOfYear(res.date);
if (*ptr=='+' || *ptr=='-')
res.date+=Str2I64(ptr);
Free(src);
Free(v);
return res-local_time_offset;
}
U8 *StrScan(U8 *src,U8 *fmt,...)
{/*Opposite of sprintf(). Pass ptrs to data to be scanned-in.
For "%s", pass ptr to ptr (be careful because addr
of array is the same as array--create ptr to array
and take addr.
*/
U8 *buf,*ptr,**pptr;
Bool left_justify=FALSE;
I64 ch,cur_arg=0,i,len,*i_ptr,dec_len;
F64 *d_ptr;
if (!fmt)
throw('Scan');
while (ch = *fmt++) {
if (ch=='%') {
if (*fmt=='%') {
src++;
fmt++;
} else {
if (*fmt=='-') {
left_justify=TRUE;
fmt++;
} else
left_justify=FALSE;
len=0;
while ('0'<=*fmt<='9')
len=len*10+ (*fmt++ -'0');
if (*fmt=='*') {
fmt++;
if (cur_arg>=argc)
throw('Scan');
len=argv[cur_arg++];
}
ch=*fmt++;
if (ch && !len) {
ptr=src;
while (*ptr && *ptr!=*fmt)
ptr++;
len=ptr-src;
} else {
if (ch=='.') {
dec_len=0;
while ('0'<=*fmt<='9')
dec_len=dec_len*10+ (*fmt++-'0');
if (*fmt=='*') {
fmt++;
if (cur_arg>=argc)
throw('Scan');
dec_len=argv[cur_arg++];
}
ch=*fmt++;
}
}
buf=MAlloc(len+1);
for (i=0;i<len;i++)
buf[i]=*src++;
buf[i]=0;
switch (ch) {
case 's':
if (cur_arg>=argc)
throw('Scan');
pptr=argv[cur_arg++];
StrCpy(*pptr,buf);
break;
case 'c':
if (cur_arg>=argc)
throw('Scan');
ptr=argv[cur_arg++];
*ptr=*buf;
break;
case 'C':
if (cur_arg>=argc)
throw('Scan');
ptr=argv[cur_arg++];
*ptr=ToUpper(*buf);
break;
case 'z':
if (cur_arg+1>=argc)
throw('Scan');
i_ptr=argv[cur_arg++];
*i_ptr=LstMatch(buf,argv[cur_arg++]);
break;
case 'Z':
if (cur_arg+1>=argc)
throw('Scan');
i_ptr=argv[cur_arg++];
*i_ptr=DefineMatch(buf,argv[cur_arg++]);
break;
case 'd':
if (cur_arg>=argc)
throw('Scan');
i_ptr=argv[cur_arg++];
*i_ptr=Str2I64(buf);
break;
case 'X':
if (cur_arg>=argc)
throw('Scan');
i_ptr=argv[cur_arg++];
*i_ptr=Str2I64(buf,16);
break;
case 'b':
if (cur_arg>=argc)
throw('Scan');
i_ptr=argv[cur_arg++];
*i_ptr=Str2I64(buf,2);
break;
case 'e':
case 'f':
case 'g':
case 'n':
if (cur_arg>=argc)
throw('Scan');
d_ptr=argv[cur_arg++];
*d_ptr=Str2F64(buf);
break;
case 'D':
if (cur_arg>=argc)
throw('Scan');
i_ptr=argv[cur_arg++];
*i_ptr=Str2Date(buf);
break;
}
Free(buf);
}
} else
src++;
}
return src;
}