summaryrefslogtreecommitdiff
path: root/kernel/fs/hd.c
diff options
context:
space:
mode:
authorJake Mannens <jake72360@gmail.com>2018-07-14 03:42:12 +1000
committerJake Mannens <jake72360@gmail.com>2018-07-14 03:42:12 +1000
commit35685c20a5dc299edf6f3b76ed898a2e71d0e457 (patch)
tree0c4ef9eb71eedb2a3d414b6454f86529400a717e /kernel/fs/hd.c
parentbe74842e37ad54f4fd18ae647e2bdf3e435a0fb8 (diff)
con_init() is now called during the kernel's boot sequence in kboot()
rather than in kmain() as some subsystems may now require early console I/O. Added 16-bit read/write I/O functions to asm/io.h. These functions are inw() and outw() respectively. Added the file kernel/fs.h which will contain definitions relating to filesystem functions. Defined the type off_t as a signed 32-bit value in sys/types.h. This type will be required for filesystem functionality. Added the directory 'kernel/fs' to the project's source tree. The kernel's makefile has been updated accordingly. This directory will contain any source files relating to filesystem functionality (both assembly and C files). Added the file 'fs/hd.c' to the kernel's source tree. This file currently contains three main functions (which are defined in kernel/hd.h). These functions are as follows; hd_init() to enumerate and initialize the hard disks, hd_read() to read sectors from the disk and hd_write() to write sectors to the disk. Currently, all transfers are done in ATA PIO mode using polling, however this will change in future. The function hd_init() is called during the kernel's boot sequence in kboot(). Added the file hd.img to the project's root directory. This is a 20MB raw image file that will be used by Qemu as a 20MB hard disk. The main makefile has been updated to tell Qemu to use this file on launch.
Diffstat (limited to 'kernel/fs/hd.c')
-rw-r--r--kernel/fs/hd.c132
1 files changed, 132 insertions, 0 deletions
diff --git a/kernel/fs/hd.c b/kernel/fs/hd.c
new file mode 100644
index 0000000..706d503
--- /dev/null
+++ b/kernel/fs/hd.c
@@ -0,0 +1,132 @@
+#include <asm/io.h>
+#include <kernel/con.h>
+#include <kernel/kernel.h>
+#include <stdint.h>
+
+#define ST_ERR 1
+#define ST_DRQ 8
+#define ST_SRV 16
+#define ST_DF 32
+#define ST_RDY 64
+#define ST_BSY 128
+
+/* sector buffer */
+static char sbuf[512];
+
+void hd_init(void) {
+ int i;
+ uint8_t s;
+ uint16_t *buf = (uint16_t*) sbuf;
+
+ /* select the master drive */
+ outb(0x1F6, 0xA0);
+ /* send the IDENTIFY command */
+ outb(0x1F7, 0xEC);
+
+ while(1) {
+ s = inb(0x1F7);
+ if(!s) {
+ printk("[hd] Master drive not detected on primary bus!\n");
+ panic();
+ }
+ if(s & ST_ERR) {
+ if(!inb(0x1F4) && !inb(0x1F5))
+ continue;
+ printk("[hd] IDENTIFY command error!\n");
+ panic();
+ }
+ if(s & ST_DRQ && !(s & ST_ERR))
+ break;
+ }
+
+ printk("[hd] Master drive detected on primary bus! (status: 0x%02x)\n", s);
+
+ for(i = 0; i < 256; i++)
+ buf[i] = inw(0x1F0);
+}
+
+int hd_read(void *buf, uint32_t lba, uint8_t c) {
+ int n;
+ uint8_t s;
+ uint16_t *p = buf;
+
+ if(!c)
+ return 0;
+
+ /* select the master disk on the primary bus */
+ outb(0x1F6, 0xE0 | ((lba >> 24) & 0xF));
+ /* set the number of sectors to be read */
+ outb(0x1F2, c);
+ /* set the LBA address for the read operation */
+ outb(0x1F3, lba);
+ outb(0x1F4, lba >> 8);
+ outb(0x1F5, lba >> 16);
+ /* send the READ command */
+ outb(0x1F7, 0x20);
+
+ while(c--) {
+ /* wait for the drive */
+ while(1) {
+ /* poll the drive's status */
+ s = inb(0x1F7);
+ if(s & ST_DF) {
+ printk("[hd] Drive failure!\n");
+ panic();
+ }
+ if(s & ST_ERR)
+ return -1;
+ if(!(s & ST_BSY) && s & ST_DRQ)
+ break;
+ }
+
+ /* buffer is full, copy it's data */
+ n = 256;
+ while(n--)
+ *(p++) = inw(0x1F0);
+ }
+
+ return 0;
+}
+
+int hd_write(void *buf, uint32_t lba, uint8_t c) {
+ int n;
+ uint8_t s;
+ uint16_t *p = buf;
+
+ if(!c)
+ return 0;
+
+ /* select the master disk on the primary bus */
+ outb(0x1F6, 0xE0 | ((lba >> 24) & 0xF));
+ /* set the number of sectors to be written */
+ outb(0x1F2, c);
+ /* set the LBA address for the write operation */
+ outb(0x1F3, lba);
+ outb(0x1F4, lba >> 8);
+ outb(0x1F5, lba >> 16);
+ /* send the WRITE command */
+ outb(0x1F7, 0x30);
+
+ while(c--) {
+ /* wait for the drive */
+ while(1) {
+ /* poll the drive's status */
+ s = inb(0x1F7);
+ if(s & ST_DF) {
+ printk("[hd] Drive failure!\n");
+ panic();
+ }
+ if(s & ST_ERR)
+ return -1;
+ if(!(s & ST_BSY) && s & ST_DRQ)
+ break;
+ }
+
+ /* refill the drive's buffer */
+ n = 256;
+ while(n--)
+ outw(0x1F0, *(p++));
+ }
+
+ return 0;
+}