From 2f562758ad12517afcafd2c9fbf1fc14f83b6793 Mon Sep 17 00:00:00 2001 From: xamidev <121681048+xamidev@users.noreply.github.com> Date: Sun, 18 Aug 2024 12:45:24 +0200 Subject: [PATCH] Re-add: ATA PIO driver (w/o paging) --- README.md | 6 +- src/drivers/ata.c | 77 +++++++++ src/drivers/ata.h | 7 + src/kernel/kmain.c | 3 + src/libc/stdio.c | 378 +++++++++++++++++++++++++-------------------- src/libc/stdio.h | 23 +-- 6 files changed, 315 insertions(+), 179 deletions(-) create mode 100644 src/drivers/ata.c create mode 100644 src/drivers/ata.h diff --git a/README.md b/README.md index f21eb20..097ad27 100644 --- a/README.md +++ b/README.md @@ -79,6 +79,7 @@ Two other documents are available to help you understand the project better. One - the Intel [64 and IA-32 Architectures Software Developer Manuals](https://www.intel.com/content/www/us/en/developer/articles/technical/intel-sdm.html) - [Bran's Kernel Development Tutorial](http://www.osdever.net/bkerndev/index.php) - Ralf Brown's Interrupt List +- the [little book about OS development](https://littleosbook.github.io/) by Erik Helin and Adam Renberg ### ⚠️ Disclaimer @@ -90,8 +91,9 @@ This is a hobbyist operating system kernel and it comes without any warranty wha - [X] Common basic structures (IDT, GDT, ISRs, IRQs) - [X] Common drivers (framebuffer, keyboard, serial, timer) - [X] Kernel-space utilities (shell, simple programs) -- [ ] FAT32 filesystem -- [ ] Paging/Page Frame Allocation +- [ ] Filesystem (FAT32 or VFS ramdisk) +- [ ] Changing the default VGA font +- [X] Paging/Page Frame Allocation - [ ] TCP/IP Network stack - [ ] Getting to Ring-3 (userspace) - [ ] Multitasking (via round robin scheduling) diff --git a/src/drivers/ata.c b/src/drivers/ata.c new file mode 100644 index 0000000..4582d6a --- /dev/null +++ b/src/drivers/ata.c @@ -0,0 +1,77 @@ +#include "../libc/stdint.h" +#include "../kernel/io.h" +#include "../libc/stdio.h" + +#define ATA_PRIMARY_IO 0x1F0 +#define ATA_PRIMARY_CTRL 0x3F6 +#define ATA_CMD_READ_PIO 0x20 +#define ATA_CMD_WRITE_PIO 0x30 +#define ATA_IDENTIFY 0xEC + +#define ATA_REG_DATA 0x00 +#define ATA_REG_ERROR 0x01 +#define ATA_REG_SECCOUNT0 0x02 +#define ATA_REG_LBA0 0x03 +#define ATA_REG_LBA1 0x04 +#define ATA_REG_LBA2 0x05 +#define ATA_REG_HDDEVSEL 0x06 +#define ATA_REG_COMMAND 0x07 +#define ATA_REG_STATUS 0x07 + +#define ATA_SR_BSY 0x80 +#define ATA_SR_DRDY 0x40 +#define ATA_SR_DRQ 0x08 +#define ATA_SR_ERR 0x01 + +static inline uint16_t inw(uint16_t port) { + uint16_t result; + asm volatile("inw %1, %0" : "=a"(result) : "dN"(port)); + return result; +} + +static inline void outw(uint16_t port, uint16_t data) { + asm volatile("outw %1, %0" : : "dN"(port), "a"(data)); +} + +void ata_wait_bsy() { + while (inb(ATA_PRIMARY_IO + ATA_REG_STATUS) & ATA_SR_BSY); +} + +void ata_wait_drq() { + while (!(inb(ATA_PRIMARY_IO + ATA_REG_STATUS) & ATA_SR_DRQ)); +} + +void ata_select_drive(uint8_t drive) { + outb(ATA_PRIMARY_IO + ATA_REG_HDDEVSEL, 0xE0 | (drive << 4)); +} + +void ata_read_sector(uint32_t lba, uint8_t* buffer) { + ata_wait_bsy(); + ata_select_drive(0); + + outb(ATA_PRIMARY_IO + ATA_REG_SECCOUNT0, 1); + outb(ATA_PRIMARY_IO + ATA_REG_LBA0, (uint8_t)lba); + outb(ATA_PRIMARY_IO + ATA_REG_LBA1, (uint8_t)(lba >> 8)); + outb(ATA_PRIMARY_IO + ATA_REG_LBA2, (uint8_t)(lba >> 16)); + outb(ATA_PRIMARY_IO + ATA_REG_HDDEVSEL, 0xE0 | ((lba >> 24) & 0x0F)); + + outb(ATA_PRIMARY_IO + ATA_REG_COMMAND, ATA_CMD_READ_PIO); + + ata_wait_bsy(); + ata_wait_drq(); + + for (int i = 0; i < 256; i++) { + ((uint16_t*)buffer)[i] = inw(ATA_PRIMARY_IO + ATA_REG_DATA); + } +} + +// Works only w/o paging +void test_read_sector() { + uint8_t buffer[512]; + ata_read_sector(0, buffer); + + for (int i = 0; i < 512; i++) { + if (i%25==0) puts("\n"); + printf("%02x ", buffer[i]); + } +} diff --git a/src/drivers/ata.h b/src/drivers/ata.h new file mode 100644 index 0000000..550645c --- /dev/null +++ b/src/drivers/ata.h @@ -0,0 +1,7 @@ +#ifndef ATA_H +#define ATA_H + +void ata_read_sector(uint32_t lba, uint8_t* buffer); +void test_read_sector(); + +#endif diff --git a/src/kernel/kmain.c b/src/kernel/kmain.c index 38807de..fed80c0 100644 --- a/src/kernel/kmain.c +++ b/src/kernel/kmain.c @@ -4,6 +4,7 @@ #include "idt.h" #include "system.h" #include "paging.h" +#include "../drivers/ata.h" char* ascii_title = "\n" @@ -39,6 +40,8 @@ void kmain(unsigned int multiboot_info_address) init_paging(); printf("Hello, paging world!\n"); + //test_read_sector(); + uint32_t *ptr = (uint32_t*)0xA0000000; uint32_t do_page_fault = *ptr; diff --git a/src/libc/stdio.c b/src/libc/stdio.c index 31d1c7f..0b5f63f 100644 --- a/src/libc/stdio.c +++ b/src/libc/stdio.c @@ -221,201 +221,247 @@ void dtostrf(double val, char *buffer, int precision) void printf(const char* fmt, ...) { - int* argp = (int*) &fmt; - int state = PRINTF_STATE_START; - int length = PRINTF_LENGTH_START; - int radix = 10; - bool sign = false; + int* argp = (int*)&fmt; + int state = PRINTF_STATE_START; + int length = PRINTF_LENGTH_START; + int radix = 10; + bool sign = false; + int width = 0; + char pad_char = ' '; - argp++; - while (*fmt) - { - switch(state) { - case PRINTF_STATE_START: - if (*fmt == '%') + argp++; + while (*fmt) + { + switch (state) { - state = PRINTF_STATE_LENGTH; - } - else { - putc(*fmt); - } - break; - case PRINTF_STATE_LENGTH: - if (*fmt == 'h') - { - length = PRINTF_LENGTH_SHORT; - state = PRINTF_STATE_SHORT; - } - else if (*fmt == 'l') - { - length = PRINTF_LENGTH_LONG; - state = PRINTF_STATE_LONG; - } - else { - goto PRINTF_STATE_SPEC_; - } - break; - case PRINTF_STATE_SHORT: - if (*fmt == 'h') - { - length = PRINTF_LENGTH_SHORT_SHORT; - state = PRINTF_STATE_SPEC; - } - else { - goto PRINTF_STATE_SPEC_; - } - break; - case PRINTF_STATE_LONG: - if (*fmt == 'l') - { - length = PRINTF_LENGTH_LONG_LONG; - state = PRINTF_STATE_SPEC; - } - else { - goto PRINTF_STATE_SPEC_; - } - break; - case PRINTF_STATE_SPEC: + case PRINTF_STATE_START: + if (*fmt == '%') + { + state = PRINTF_STATE_LENGTH; + width = 0; + pad_char = ' '; + } + else + { + putc(*fmt); + } + break; + + case PRINTF_STATE_LENGTH: + if (*fmt == '0') + { + pad_char = '0'; + state = PRINTF_STATE_WIDTH; + } + else if (*fmt >= '1' && *fmt <= '9') + { + width = *fmt - '0'; + state = PRINTF_STATE_WIDTH; + } + else if (*fmt == 'h') + { + length = PRINTF_LENGTH_SHORT; + state = PRINTF_STATE_SHORT; + } + else if (*fmt == 'l') + { + length = PRINTF_LENGTH_LONG; + state = PRINTF_STATE_LONG; + } + else + { + goto PRINTF_STATE_SPEC_; + } + break; + + case PRINTF_STATE_WIDTH: + if (*fmt >= '0' && *fmt <= '9') + { + width = width * 10 + (*fmt - '0'); + } + else + { + goto PRINTF_STATE_SPEC_; + } + break; + + case PRINTF_STATE_SHORT: + if (*fmt == 'h') + { + length = PRINTF_LENGTH_SHORT_SHORT; + state = PRINTF_STATE_SPEC; + } + else + { + goto PRINTF_STATE_SPEC_; + } + break; + + case PRINTF_STATE_LONG: + if (*fmt == 'l') + { + length = PRINTF_LENGTH_LONG_LONG; + state = PRINTF_STATE_SPEC; + } + else + { + goto PRINTF_STATE_SPEC_; + } + break; + + case PRINTF_STATE_SPEC: PRINTF_STATE_SPEC_: - switch(*fmt) - { - case 'c': - putc((char)*argp); - argp++; - break; - case 's': - puts(*(const char **)argp); - argp++; - break; - case '%': - putc('%'); - break; - case 'd': - case 'i': - radix = 10; - sign = true; - argp = printf_number(argp, length, sign, radix); - break; - case 'u': + switch (*fmt) + { + case 'c': + putc((char)*argp); + argp++; + break; + case 's': + puts(*(const char**)argp); + argp++; + break; + case '%': + putc('%'); + break; + case 'd': + case 'i': + radix = 10; + sign = true; + argp = printf_number(argp, length, sign, radix, width, pad_char); + break; + case 'u': + radix = 10; + sign = false; + argp = printf_number(argp, length, sign, radix, width, pad_char); + break; + case 'X': + case 'x': + case 'p': + radix = 16; + sign = false; + argp = printf_number(argp, length, sign, radix, width, pad_char); + break; + case 'o': + radix = 8; + sign = false; + argp = printf_number(argp, length, sign, radix, width, pad_char); + break; + case 'f': { + double* dargp = (double*)argp; + double d = *(double*)dargp; + char buffer[64]; + dtostrf(d, buffer, 6); + puts(buffer); + argp += 2; + break; + } + default: + break; + } + state = PRINTF_STATE_START; + length = PRINTF_LENGTH_START; radix = 10; sign = false; - argp = printf_number(argp, length, sign, radix); - break; - case 'X': - case 'x': - case 'p': - radix = 16; - sign = false; - argp = printf_number(argp, length, sign, radix); - break; - case 'o': - radix = 8; - sign = false; - argp = printf_number(argp, length, sign, radix); - break; - case 'f': { - // Handle floating-point numbers - double* dargp = (double*)argp; - double d = *(double*)dargp; - char buffer[64]; - dtostrf(d, buffer, 6); // Default precision: 6 - puts(buffer); - argp += 2; // Incrementing by 2 to move past the double argument - break; - } - default: + width = 0; + pad_char = ' '; break; } - state = PRINTF_STATE_START; - length = PRINTF_LENGTH_START; - radix = 10; - sign = false; - break; + fmt++; } - fmt++; - } } const char charset[] = "0123456789abcdef"; -int* printf_number(int* argp, int length, bool sign, int radix) +int* printf_number(int* argp, int length, bool sign, int radix, int width, char pad_char) { - char buffer[32]; - unsigned long long number; - int number_sign = 1; - int pos = 0; + char buffer[32]; + unsigned long long number; + int number_sign = 1; + int pos = 0; - switch(length) - { + switch (length) + { case PRINTF_LENGTH_SHORT_SHORT: case PRINTF_LENGTH_SHORT: case PRINTF_LENGTH_START: - if (sign) - { - int n = *argp; - if (n < 0) + if (sign) { - n = -n; - number_sign = -1; + int n = *argp; + if (n < 0) + { + n = -n; + number_sign = -1; + } + number = (unsigned long long)n; } - number = (unsigned long long) n; - } - else { - number = *(unsigned int*) argp; - } - argp++; - break; + else + { + number = *(unsigned int*)argp; + } + argp++; + break; case PRINTF_LENGTH_LONG: - if (sign) - { - long int n = *(long int*)argp; - if (n < 0) + if (sign) { - n = -n; - number_sign = -1; + long int n = *(long int*)argp; + if (n < 0) + { + n = -n; + number_sign = -1; + } + number = (unsigned long long)n; } - number = (unsigned long long) n; - } - else { - number = *(unsigned long int*) argp; - } - argp += 2; - break; + else + { + number = *(unsigned long int*)argp; + } + argp += 2; + break; case PRINTF_LENGTH_LONG_LONG: - if (sign) - { - long long int n = *(long long int*)argp; - if (n < 0) + if (sign) { - n = -n; - number_sign = -1; + long long int n = *(long long int*)argp; + if (n < 0) + { + n = -n; + number_sign = -1; + } + number = (unsigned long long)n; } - number = (unsigned long long) n; - } - else { - number = *(unsigned long long int*) argp; - } - argp += 4; - break; - } + else + { + number = *(unsigned long long int*)argp; + } + argp += 4; + break; + } - do { - uint32_t rem; - x86_div64_32(number, radix, &number, &rem); - buffer[pos++] = charset[rem]; - } while (number > 0); + do + { + uint32_t rem; + x86_div64_32(number, radix, &number, &rem); + buffer[pos++] = charset[rem]; + } while (number > 0); - if (sign && number_sign < 0) - { - buffer[pos++] = '-'; - } + if (sign && number_sign < 0) + { + buffer[pos++] = '-'; + } - while (--pos >= 0) - { - putc(buffer[pos]); - } + int padding = width - pos; - return argp; + while (padding-- > 0) + { + putc(pad_char); + } + + while (--pos >= 0) + { + putc(buffer[pos]); + } + + return argp; } int getch() diff --git a/src/libc/stdio.h b/src/libc/stdio.h index e7882fb..018107e 100644 --- a/src/libc/stdio.h +++ b/src/libc/stdio.h @@ -23,20 +23,21 @@ void scroll(int lines); void putc(char c); void colorputc(char c, unsigned int color); -#define PRINTF_STATE_START 0 -#define PRINTF_STATE_LENGTH 1 -#define PRINTF_STATE_SHORT 2 -#define PRINTF_STATE_LONG 3 -#define PRINTF_STATE_SPEC 4 +#define PRINTF_STATE_START 0 +#define PRINTF_STATE_LENGTH 1 +#define PRINTF_STATE_SHORT 2 +#define PRINTF_STATE_LONG 3 +#define PRINTF_STATE_SPEC 4 +#define PRINTF_STATE_WIDTH 5 -#define PRINTF_LENGTH_START 0 -#define PRINTF_LENGTH_SHORT_SHORT 1 -#define PRINTF_LENGTH_SHORT 2 -#define PRINTF_LENGTH_LONG 3 -#define PRINTF_LENGTH_LONG_LONG 4 +#define PRINTF_LENGTH_START 0 +#define PRINTF_LENGTH_SHORT_SHORT 1 +#define PRINTF_LENGTH_SHORT 2 +#define PRINTF_LENGTH_LONG 3 +#define PRINTF_LENGTH_LONG_LONG 4 void printf(const char* fmt, ...); -int* printf_number(int* argp, int length, bool sign, int radix); +int* printf_number(int* argp, int length, bool sign, int radix, int width, char pad_char); int getch(); void get_input(char *buffer, int size);