From 12553eeeb1aac14d73d9c17b9e3e00041aa47f85 Mon Sep 17 00:00:00 2001 From: Alec Murphy Date: Fri, 14 Jan 2022 11:29:08 -0500 Subject: [PATCH] Add files to repository --- Install.HC | 48 ++++ README.md | 38 ++- Src/BootHelper.HC | 26 ++ Src/DskATA.HC | 601 ++++++++++++++++++++++++++++++++++++++++++++++ Src/DskATAId.HC | 301 +++++++++++++++++++++++ Src/DskAddDev.HC | 238 ++++++++++++++++++ Src/KMain.HC | 238 ++++++++++++++++++ 7 files changed, 1489 insertions(+), 1 deletion(-) create mode 100644 Install.HC create mode 100644 Src/BootHelper.HC create mode 100644 Src/DskATA.HC create mode 100644 Src/DskATAId.HC create mode 100644 Src/DskAddDev.HC create mode 100644 Src/KMain.HC diff --git a/Install.HC b/Install.HC new file mode 100644 index 0000000..2f8182b --- /dev/null +++ b/Install.HC @@ -0,0 +1,48 @@ +U0 Install() { + "Primary IDE base0 (0x01F0): "; + U8 *pri_base0 = GetStr; + if (!StrCmp(pri_base0, "")) + pri_base0 = "0x01F0"; + "Primary IDE base1 (0x03F6): "; + U8 *pri_base1 = GetStr; + if (!StrCmp(pri_base1, "")) + pri_base1 = "0x03F6"; + "Secondary IDE base0 (0x0170): "; + U8 *sec_base0 = GetStr; + if (!StrCmp(sec_base0, "")) + sec_base0 = "0x0170"; + "Secondary IDE base1 (0x0376): "; + U8 *sec_base1 = GetStr; + if (!StrCmp(sec_base1, "")) + sec_base1 = "0x0376"; + Copy("T:/KMain.HC", "::/Kernel/KMain.HC"); + Copy("T:/Src/DskAddDev.HC", "::/Kernel/BlkDev/DskAddDev.HC.Z"); + Copy("T:/Src/DskATA.HC", "::/Kernel/BlkDev/DskATA.HC.Z"); + Copy("T:/Src/BootHelper.HC", "::/Home/BootHelper.HC.Z"); + CDoc *doc1 = DocNew("::/Kernel/BlkDev/DskATAId.HC.Z"); + CDoc *doc2 = DocRead("T:/Src/DskATAId.HC"); + DocPrint(doc1, "#define BMIK_PRI_BASE0 %s\n", pri_base0); + DocPrint(doc1, "#define BMIK_PRI_BASE1 %s\n", pri_base1); + DocPrint(doc1, "#define BMIK_SEC_BASE0 %s\n", sec_base0); + DocPrint(doc1, "#define BMIK_SEC_BASE1 %s\n", sec_base1); + DocInsDoc(doc1, doc2); + DocDel(doc2); + DocWrite(doc1); + DocDel(doc1); + doc1 = DocNew("::/Home/Once.HC.Z"); + doc2 = DocRead("::/Home/Once.HC.Z"); + DocPrint(doc1, "#include \"BootHelper\"\n\n"); + DocInsDoc(doc1, doc2); + DocDel(doc2); + DocWrite(doc1); + DocDel(doc1); + XTalkWait(Fs, "Cd;\n"); + XTalkWait(Fs, "BootHDIns;\n"); + XTalkWait(Fs, "\n"); + XTalkWait(Fs, "C\ns"); + XTalkWait(Fs, "0x01F0\n"); + XTalkWait(Fs, "0x03F6\n"); + XTalkWait(Fs, "0\n\n\n"); +} + +Install; \ No newline at end of file diff --git a/README.md b/README.md index 3da3e59..d9ce97b 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,39 @@ # bmik -Bare-Metal Installation Kit - Easily install TempleOS on bare-metal \ No newline at end of file +Bare-Metal Installation Kit - Easily install TempleOS on bare-metal + +# Details + +The goal for this project is to provide an easy way to create a hard disk image that can be booted on bare-metal hardware and QEMU seamlessly, to allow for transfer of files between PCs while developing software projects. + +The intended usage is to create a disk image that can be copied to a hard disk mounted in a removable enclosure, and the hard disk transferred between the virtual environment and a bare-metal machine. + +# Usage + +- Create a raw disk image, at least large enough to hold 2*1G TempleOS RedSea partitions + partition table `qemu-img create -f raw disk_img.raw 4G` + +- Run the VM install wizard, then re-run install wizard w/o VM option from each partition and choose RedSea format for each install + +OR + +- Use the provided disk image `disk_img.raw.xz` which skips these steps for you. + +THEN + +- Clone the repo, add files to `bmik.ISO.C` + +- `qemu-system-x86_64 -drive format=raw,file=disk_img.raw -m 1024 -cdrom bmik.ISO.C` + +FINALLY, for each partition: + +- Mount the CDROM, if it is not mounted already `Mount;` - drive letter 'T', 'p' for probe, number '2' for Secondary IDE + +- `Cd("T:"); #include "Install";` + +- Enter your Primary/Secondary base0, base1 I/O ports from `lspci -v` + +- Reboot + +# Done + +`dd` the resulting `disk_img.raw` to your target HDD, and you now have a TempleOS RedSea installation with 2 partitions, bootable on bare-metal and QEMU. \ No newline at end of file diff --git a/Src/BootHelper.HC b/Src/BootHelper.HC new file mode 100644 index 0000000..328d718 --- /dev/null +++ b/Src/BootHelper.HC @@ -0,0 +1,26 @@ +// This script will clean up non-existent removable drives when booting in QEMU + +U0 BootHelper() { + I64 i; + Bool is_qemu = FALSE; + U8 *drv_model = DrvModelNum(':'); + if (!MemCmp("QEMU", drv_model, 4)) + is_qemu = TRUE; + Free(drv_model); + if (is_qemu) { + // Remove non-existent removable drives + for (i = 'T'; i < 'X'; i++) { + if (Let2Drv(i, 0)) + DrvDel(Let2Drv(i)); + } + // Add default QEMU CDROM + CBlkDev *bd = CAlloc(sizeof(CBlkDev)); + bd = BlkDevNextFreeSlot('T', 5); + bd->unit = 0; + bd->base0 = 0x170; + bd->base1 = 0x374; + BlkDevAdd(bd, , 0, 0); + } +} + +BootHelper; diff --git a/Src/DskATA.HC b/Src/DskATA.HC new file mode 100644 index 0000000..3493ebf --- /dev/null +++ b/Src/DskATA.HC @@ -0,0 +1,601 @@ +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); + 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 BlkWrite() 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; +} diff --git a/Src/DskATAId.HC b/Src/DskATAId.HC new file mode 100644 index 0000000..1719aae --- /dev/null +++ b/Src/DskATAId.HC @@ -0,0 +1,301 @@ +Bool BootDVDProbe(CBlkDev *bd) { + U8 *img = CAlloc(DVD_BLK_SIZE); + I64 i; + Bool res = FALSE; + "Port:%04X,%04XUnit:%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 = BMIK_PRI_BASE0; + d2 = BMIK_PRI_BASE1; + if (bd->base0 = d1 & ~7) { + bd->unit = 0; + if (BootDVDProbe(bd)) + return TRUE; + bd->unit = 1; + if (BootDVDProbe(bd)) + return TRUE; + } + + d1 = BMIK_SEC_BASE0; + d2 = BMIK_SEC_BASE1; + 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$$HardDrive$$LTBLUE$$ATA"; + else + "$$RED$$CD/DVDDrive$$LTBLUE$$ATAPI"; + "%s$$FG$$\n", msg; + if (base0 == blkdev.ins_base0 && unit == blkdev.ins_unit) + "$$PURPLE$$(Drive originally installed from.)$$FG$$\n"; + "Base0:0x%04XBase1:0x%04XUnit:%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 = BMIK_PRI_BASE0; + d2 = BMIK_PRI_BASE1; + 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 = BMIK_SEC_BASE0; + d2 = BMIK_SEC_BASE1; + ATARepEntry(d1, d2, 0, "Secondary IDE", _head, &num_hints); + ATARepEntry(d1, d2, 1, "Secondary IDE", _head, &num_hints); + } + } + } + if (!cnt) { + d1 = BMIK_PRI_BASE0; + d2 = BMIK_PRI_BASE1; + ATARepEntry(d1, d2, 0, "Primary IDE", _head, &num_hints); + ATARepEntry(d1, d2, 1, "Primary IDE", _head, &num_hints); + + d1 = BMIK_SEC_BASE0; + d2 = BMIK_SEC_BASE1; + 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 MountIDEAuto() { // 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.mount_ide_auto_cnt = res; + return res; +} diff --git a/Src/DskAddDev.HC b/Src/DskAddDev.HC new file mode 100644 index 0000000..231e5fe --- /dev/null +++ b/Src/DskAddDev.HC @@ -0,0 +1,238 @@ +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_CLUS; + 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_CLUS) { + 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 { + StreamPrint("MountIDEAuto;"); + StreamPrint("#exe {Option(OPTf_WARN_PAREN,OFF);}"); + StreamDoc(kernel_cfg->add_dev); + StreamPrint("#exe {Option(OPTf_WARN_PAREN,ON);}"); +}; +} diff --git a/Src/KMain.HC b/Src/KMain.HC new file mode 100644 index 0000000..4a56930 --- /dev/null +++ b/Src/KMain.HC @@ -0,0 +1,238 @@ +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->mount_ide_auto_hd_let) + kernel_cfg->mount_ide_auto_hd_let = 'C'; + if (!kernel_cfg->mount_ide_auto_cd_let) + kernel_cfg->mount_ide_auto_cd_let = 'T'; + StreamPrint("blkdev.first_hd_drv_let=%d;", kernel_cfg->mount_ide_auto_hd_let); + StreamPrint("blkdev.first_dvd_drv_let=%d;", + kernel_cfg->mount_ide_auto_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); + +QueInit(&scrncast.snd_head); +scrncast.t0_now = Now; +scrncast.t0_tS = tS; +scrncast.ona = scrncast.snd_head.ona = 0; + +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); + + TimeCal; + + KbdMsInit; + MsInit; + KbdInit; + Spawn(&MsHardDrvrInstall); + + BlkDevsInitAll; + "DskChg(':');\n"; + DskChg(':'); +#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);"); +} +; + +"Loading Compiler\n"; +Cd("/Compiler"); +Load("Compiler", LDF_SILENT); +LBts(&sys_run_level, RLf_COMPILER); + +DbgMode(OFF); +cnts.time_stamp_freq_initial = TimeCal; +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); +} +; +}