mirror of
https://github.com/RGBCube/serenity
synced 2025-05-31 23:48:11 +00:00
Import the "gerbert" kernel I worked on earlier this year.
It's a lot crappier than I remembered it. It's gonna need a lot of work.
This commit is contained in:
parent
f608629704
commit
9396108034
55 changed files with 4600 additions and 0 deletions
195
Kernel/Disk.cpp
Normal file
195
Kernel/Disk.cpp
Normal file
|
@ -0,0 +1,195 @@
|
|||
#include "types.h"
|
||||
#include "Task.h"
|
||||
#include "IPC.h"
|
||||
#include "VGA.h"
|
||||
#include "Disk.h"
|
||||
#include "kmalloc.h"
|
||||
#include "StdLib.h"
|
||||
#include "IO.h"
|
||||
#include "i386.h"
|
||||
#include "DataBuffer.h"
|
||||
#include "PIC.h"
|
||||
|
||||
//#define DISK_DEBUG
|
||||
|
||||
extern "C" void handle_interrupt();
|
||||
|
||||
namespace Disk {
|
||||
|
||||
ide_drive_t drive[4];
|
||||
static volatile bool interrupted;
|
||||
|
||||
#define IRQ_FIXED_DISK 14
|
||||
|
||||
extern "C" void ide_ISR();
|
||||
|
||||
asm(
|
||||
".globl ide_ISR \n"
|
||||
"ide_ISR: \n"
|
||||
" pusha\n"
|
||||
" pushw %ds\n"
|
||||
" pushw %es\n"
|
||||
" pushw %ss\n"
|
||||
" pushw %ss\n"
|
||||
" popw %ds\n"
|
||||
" popw %es\n"
|
||||
" call handle_interrupt\n"
|
||||
" popw %es\n"
|
||||
" popw %ds\n"
|
||||
" popa\n"
|
||||
" iret\n"
|
||||
);
|
||||
|
||||
static void enableIRQ()
|
||||
{
|
||||
PIC::enable(IRQ_FIXED_DISK);
|
||||
}
|
||||
|
||||
static void disableIRQ()
|
||||
{
|
||||
PIC::disable(IRQ_FIXED_DISK);
|
||||
}
|
||||
|
||||
static bool waitForInterrupt()
|
||||
{
|
||||
#ifdef DISK_DEBUG
|
||||
kprintf("disk: waiting for interrupt...\n");
|
||||
#endif
|
||||
// FIXME: Add timeout.
|
||||
while (!interrupted) {
|
||||
yield();
|
||||
}
|
||||
#ifdef DISK_DEBUG
|
||||
kprintf("disk: got interrupt!\n");
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
void interrupt()
|
||||
{
|
||||
IRQHandlerScope scope(IRQ_FIXED_DISK);
|
||||
#ifdef DISK_DEBUG
|
||||
BYTE status = IO::in8(0x1f7);
|
||||
kprintf("disk:interrupt: DRQ=%u BUSY=%u DRDY=%u\n", (status & DRQ) != 0, (status & BUSY) != 0, (status & DRDY) != 0);
|
||||
#endif
|
||||
interrupted = true;
|
||||
}
|
||||
|
||||
void initialize()
|
||||
{
|
||||
disableIRQ();
|
||||
interrupted = false;
|
||||
registerInterruptHandler(IRQ_VECTOR_BASE + IRQ_FIXED_DISK, ide_ISR);
|
||||
|
||||
while (IO::in8(IDE0_STATUS) & BUSY);
|
||||
|
||||
IO::out8(0x1F6, 0xA0); // 0xB0 for 2nd device
|
||||
IO::out8(IDE0_COMMAND, IDENTIFY_DRIVE);
|
||||
|
||||
enableIRQ();
|
||||
waitForInterrupt();
|
||||
|
||||
RefPtr<DataBuffer> wbuf = DataBuffer::createUninitialized(512);
|
||||
BYTE* byteBuffer = new BYTE[512];
|
||||
BYTE* b = byteBuffer;
|
||||
WORD* wbufbase = (WORD*)wbuf->data();
|
||||
WORD* w = (WORD*)wbuf->data();
|
||||
|
||||
for (DWORD i = 0; i < 256; ++i) {
|
||||
WORD data = IO::in16(IDE0_DATA);
|
||||
*(w++) = data;
|
||||
*(b++) = MSB(data);
|
||||
*(b++) = LSB(data);
|
||||
}
|
||||
|
||||
// "Unpad" the device name string.
|
||||
for (DWORD i = 93; i > 54 && byteBuffer[i] == ' '; --i)
|
||||
byteBuffer[i] = 0;
|
||||
|
||||
drive[0].cylinders = wbufbase[1];
|
||||
drive[0].heads = wbufbase[3];
|
||||
drive[0].sectors_per_track = wbufbase[6];
|
||||
|
||||
kprintf(
|
||||
"ide0: Master=\"%s\", C/H/Spt=%u/%u/%u\n",
|
||||
byteBuffer + 54,
|
||||
drive[0].cylinders,
|
||||
drive[0].heads,
|
||||
drive[0].sectors_per_track
|
||||
);
|
||||
|
||||
delete byteBuffer;
|
||||
}
|
||||
|
||||
struct CHS {
|
||||
DWORD cylinder;
|
||||
WORD head;
|
||||
WORD sector;
|
||||
};
|
||||
|
||||
static CHS lba2chs(BYTE drive_index, DWORD lba)
|
||||
{
|
||||
ide_drive_t& d = drive[drive_index];
|
||||
CHS chs;
|
||||
chs.cylinder = lba / (d.sectors_per_track * d.heads);
|
||||
chs.head = (lba / d.sectors_per_track) % d.heads;
|
||||
chs.sector = (lba % d.sectors_per_track) + 1;
|
||||
return chs;
|
||||
}
|
||||
|
||||
bool readSectors(DWORD startSector, WORD count, BYTE* outbuf)
|
||||
{
|
||||
#ifdef DISK_DEBUG
|
||||
kprintf("%s: Disk::readSectors request (%u sector(s) @ %u)\n",
|
||||
current->name().characters(),
|
||||
count,
|
||||
startSector);
|
||||
#endif
|
||||
Task::checkSanity("Disk::readSectors");
|
||||
|
||||
disableIRQ();
|
||||
|
||||
CHS chs = lba2chs(IDE0_DISK0, startSector);
|
||||
|
||||
while (IO::in8(IDE0_STATUS) & BUSY);
|
||||
|
||||
#ifdef DISK_DEBUG
|
||||
kprintf("ide0: Reading %u sector(s) @ LBA %u (%u/%u/%u)\n", count, startSector, chs.cylinder, chs.head, chs.sector);
|
||||
#endif
|
||||
|
||||
IO::out8(0x1F2, count == 256 ? 0 : LSB(count));
|
||||
IO::out8(0x1F3, chs.sector);
|
||||
IO::out8(0x1F4, LSB(chs.cylinder));
|
||||
IO::out8(0x1F5, MSB(chs.cylinder));
|
||||
|
||||
IO::out8(0x1F6, 0xA0 | chs.head); /* 0xB0 for 2nd device */
|
||||
|
||||
IO::out8(0x3F6, 0x08);
|
||||
while (!(IO::in8(IDE0_STATUS) & DRDY));
|
||||
|
||||
IO::out8(IDE0_COMMAND, READ_SECTORS);
|
||||
interrupted = false;
|
||||
enableIRQ();
|
||||
waitForInterrupt();
|
||||
|
||||
BYTE status = IO::in8(0x1f7);
|
||||
if (status & DRQ) {
|
||||
#ifdef DISK_DEBUG
|
||||
kprintf("Retrieving %u bytes (status=%b), outbuf=%p...\n", count * 512, status, outbuf);
|
||||
#endif
|
||||
for (DWORD i = 0; i < (count * 512); i += 2) {
|
||||
WORD w = IO::in16(IDE0_DATA);
|
||||
outbuf[i] = LSB(w);
|
||||
outbuf[i+1] = MSB(w);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
extern "C" void handle_interrupt()
|
||||
{
|
||||
Disk::interrupt();
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue