Orion
Barry Importing existing Orion kernel d41a53c (2 years, 4 months ago)diff --git a/drivers/drivers.c b/drivers/drivers.c new file mode 100644 index 0000000..5ae8c4b --- /dev/null +++ b/drivers/drivers.c @@ -0,0 +1,102 @@ +/* + * This is the main file of the Driver core, it finds the devices attached to + * the system and also triggers any initialisation required for them. + */ + +#include <stdint.h> +#include <stddef.h> +#include "drivers.h" +#include "pci.h" +#include "../vfs/vfs.h" +#include "../screen.h" + +/* Structure for a Device */ +typedef struct Device { + uint16_t vendor, device; + char *name; + void (*init)(uint8_t, uint8_t, uint8_t); +} Device; + +Device devices[] = { + /* Intel system devices */ + {0x8086, 0x1237, "Intel i440FX Chipset", NULL}, + {0x8086, 0x7000, "Intel PIIX3 PCI-to-ISA Bridge (Triton II)", NULL}, + {0x8086, 0x7010, "Intel PIIX3 IDE Interface (Triton II)", ide_init}, + {0x8086, 0x7020, "Intel PIIX3 USB (Natoma/Triton II)", NULL}, + {0x8086, 0x7113, "Intel PIIX4/4E/4M Power Management Controller", NULL}, + + /* Network devices */ + {0x10ec, 0x8139, "Realtek RTL8139 10/100 NIC", rtl8139_init}, + {0x8086, 0x100e, "Intel Pro 1000/MT NIC", NULL}, + + /* VGA devices */ + {0x1234, 0x1111, "QEMU/Bochs VBE Framebuffer", bga_init}, +}; + +Driver *drivers = NULL; + +/* Register a driver */ +void +register_driver(Driver *driver) +{ + Driver *prev; +search: + if (!driver->major) /* Zero not allowed */ + driver->major = 1; + + /* Maintain an ordered (by major) list of drivers */ + if (!drivers) { + drivers = driver; + return; + } + if (drivers->major > driver->major) { + driver->next = drivers; + drivers = driver; + return; + } + + for (prev = drivers; prev->next; prev = prev->next) { + /* If major is taken, find next available slot */ + if (prev->major == driver->major) { + driver->major++; + if (!driver->major) /* Overflow */ + goto search; + } + if (prev->major < driver->major + && prev->next->major > driver->major) + break; + } + driver->next = prev->next; + prev->next = driver; +} + +/* Initialise devices */ +void +init_drivers(void) +{ + uint16_t bus, slot, func; + uint16_t vendor, device; + uint32_t dev; + kprintf("Enumerating PCI devices"); + for (bus = 0; bus < 256; bus++) + for (slot = 0; slot < 32; slot++) + for (func = 0; func < 8; func++) + if ((vendor = pci_read_word(bus, slot, func, 0)) != 0xFFFF) { + device = pci_read_word(bus, slot, func, 2); + for (dev = 0; dev < sizeof(devices)/sizeof(devices[0]); dev++) { + if (devices[dev].vendor == vendor + && devices[dev].device == device) { + kprintf(" PCI(%d,%d,%d) \"%s\"", + bus, slot, func, devices[dev].name); + if (devices[dev].init) + devices[dev].init(bus, slot, func); + break; + } + } + if (devices[dev].vendor != vendor + || devices[dev].device != device) { + kprintf(" PCI(%d,%d,%d) = %#x:%#x", + bus, slot, func, vendor, device); + } + } +} diff --git a/drivers/drivers.h b/drivers/drivers.h new file mode 100644 index 0000000..47cd243 --- /dev/null +++ b/drivers/drivers.h @@ -0,0 +1,30 @@ +#ifndef KERNEL_DRIVERS_H +#define KERNEL_DRIVERS_H + +#include <sys/types.h> +#include "../vfs/vfs.h" + +#define MKDEV(maj, min) ((dev_t) (((maj & 0xFFFF) << 16) | (min & 0xFFFF))) +#define MAJOR(dev) ((dev >> 16) & 0xFFFF) +#define MINOR(dev) (dev & 0xFFFF) + +typedef struct Driver Driver; + +/* Structure for a Driver */ +struct Driver { + unsigned short major; + FileOps *ops; + Driver *next; +}; + +extern Driver *drivers; + +void init_drivers(void); +void register_driver(Driver *driver); + +/* Drivers */ +void ide_init(uint8_t bus, uint8_t slot, uint8_t func); +void rtl8139_init(uint8_t bus, uint8_t dev, uint8_t func); +void bga_init(uint8_t bus, uint8_t slot, uint8_t func); + +#endif diff --git a/drivers/ide/ide.c b/drivers/ide/ide.c new file mode 100644 index 0000000..9e3b73a --- /dev/null +++ b/drivers/ide/ide.c @@ -0,0 +1,685 @@ +/* + * This file is the driver for the PCI IDE devices, which handles access to + * ATA/ATAPI devices. It detects the drives connected to the system, and + * handles any access to them - with the ability to do DMA if possible. This + * driver will access the drives in the best available way, presenting a uniform + * interface for any other code to use. It also adds a device node to the DevFS + * mount for every device, to provide access to the rest of the OS easily. + */ + +#include <stdint.h> +#include <stddef.h> +#include <fcntl.h> +#include <sys/stat.h> +#include <string.h> +#include <errno.h> +#include <time.h> +#include "../drivers.h" +#include "../pci.h" +#include "../../mem/frame.h" +#include "../../proc/proc.h" +#include "../../vfs/vfs.h" +#include "../../io.h" +#include "../../screen.h" + +struct partition { + uint8_t drive; + uint8_t shead, ssect, scyl; + uint8_t type; + uint8_t ehead, esect, ecyl; + uint32_t lba; + uint32_t size; +}; + +size_t ata_read(File *file, char *buf, size_t size, off_t offset); +size_t ata_write(File *file, char *buf, size_t size, off_t offset); +int ata_open(File *file); + +FileOps ideFileOps = { + .read = ata_read, + .write = ata_write, + .open = ata_open, +}; + +Driver ideDriver = { + .major = 2, + .ops = &ideFileOps, + .next = NULL, +}; + +page_t ataDmaArea; + +uint8_t ide_read(uint8_t chan, uint8_t reg); +void ide_write(uint8_t chan, uint8_t reg, uint8_t data); + +/* Status */ +#define ATA_SR_BSY 0x80 /* Busy */ +#define ATA_SR_DRDY 0x40 /* Drive ready */ +#define ATA_SR_DF 0x20 /* Drive write fault */ +#define ATA_SR_DSC 0x10 /* Drive seek complete */ +#define ATA_SR_DRQ 0x08 /* Data request ready */ +#define ATA_SR_CORR 0x04 /* Corrected data */ +#define ATA_SR_IDX 0x02 /* Index */ +#define ATA_SR_ERR 0x01 /* Error */ + +/* Error */ +#define ATA_ER_BBK 0x80 /* Bad block */ +#define ATA_ER_UNC 0x40 /* Uncorrectable data */ +#define ATA_ER_MC 0x20 /* Media changed */ +#define ATA_ER_IDNF 0x10 /* ID mark not found */ +#define ATA_ER_MCR 0x08 /* Media change request */ +#define ATA_ER_ABRT 0x04 /* Command aborted */ +#define ATA_ER_T0NF 0x02 /* Track 0 not found */ +#define ATA_ER_AMNF 0x01 /* No address mark */ + +/* Command */ +#define ATA_CMD_READ_PIO 0x20 +#define ATA_CMD_READ_PIO_EXT 0x24 +#define ATA_CMD_READ_DMA 0xC8 +#define ATA_CMD_READ_DMA_EXT 0x25 +#define ATA_CMD_WRITE_PIO 0x30 +#define ATA_CMD_WRITE_PIO_EXT 0x34 +#define ATA_CMD_WRITE_DMA 0xCA +#define ATA_CMD_WRITE_DMA_EXT 0x35 +#define ATA_CMD_CACHE_FLUSH 0xE7 +#define ATA_CMD_CACHE_FLUSH_EXT 0xEA +#define ATA_CMD_PACKET 0xA0 +#define ATA_CMD_IDENTIFY_PACKET 0xA1 +#define ATA_CMD_IDENTIFY 0xEC + +#define ATAPI_CMD_READ 0xA8 +#define ATAPI_CMD_EJECT 0x1B + +#define ATA_IDENT_DEVICETYPE 0 +#define ATA_IDENT_CYLINDERS 2 +#define ATA_IDENT_HEADS 6 +#define ATA_IDENT_SECTORS 12 +#define ATA_IDENT_SERIAL 20 +#define ATA_IDENT_MODEL 54 +#define ATA_IDENT_CAPABILITIES 98 +#define ATA_IDENT_FIELDVALID 106 +#define ATA_IDENT_MAX_LBA 120 +#define ATA_IDENT_COMMANDSETS 164 +#define ATA_IDENT_MAX_LBA_EXT 200 + +#define IDE_ATA 0 +#define IDE_ATAPI 1 +#define ATA_MASTER 0 +#define ATA_SLAVE 1 +#define ATA_PRIMARY 0 +#define ATA_SECONDARY 1 +#define ATA_READ 0 +#define ATA_WRITE 1 + +/* Registers */ +#define ATA_REG_DATA 0x0 +#define ATA_REG_ERROR 0x1 +#define ATA_REG_FEATURES 0x1 +#define ATA_REG_SECCOUNT0 0x2 +#define ATA_REG_LBA0 0x3 +#define ATA_REG_LBA1 0x4 +#define ATA_REG_LBA2 0x5 +#define ATA_REG_HDDEVSEL 0x6 +#define ATA_REG_COMMAND 0x7 +#define ATA_REG_STATUS 0x7 +#define ATA_REG_SECCOUNT1 0x8 +#define ATA_REG_LBA3 0x9 +#define ATA_REG_LBA4 0xA +#define ATA_REG_LBA5 0xB +#define ATA_REG_CONTROL 0xC +#define ATA_REG_ALTSTATUS 0xC +#define ATA_REG_DEVADDRESS 0xD + +struct IDEChanRegs { + uint16_t base; /* IO base */ + uint16_t ctrl; /* Control base */ + uint16_t bmide; /* Bus Master IDE */ + uint8_t noint; /* No interrupt */ +} channels[2]; + +uint8_t ideBuf[2048] = {0}; +volatile unsigned static char ideIrqInvoked = 0; +unsigned static char atapiPacket[12] = {0xA8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + +struct IDEDevice { + uint8_t reserved; + uint8_t channel; + uint8_t drive; + uint16_t type; + uint16_t signature; + uint16_t capabilities; + uint32_t commandSets; + uint32_t size; + uint8_t model[41]; +} ideDevices[4]; + +/* Read channel */ +uint8_t +ide_read(uint8_t chan, uint8_t reg) +{ + uint8_t result; + if (reg > 0x07 && reg < 0x0C) + ide_write(chan, ATA_REG_CONTROL, 0x80 | channels[chan].noint); + if (reg < 0x08) + result = inb(channels[chan].base + reg - 0x00); + else if (reg < 0x0C) + result = inb(channels[chan].base + reg - 0x06); + else if (reg < 0x0E) + result = inb(channels[chan].ctrl + reg - 0x0A); + else if (reg < 0x16) + result = inb(channels[chan].bmide + reg - 0x0E); + if (reg > 0x07 && reg < 0x0C) + ide_write(chan, ATA_REG_CONTROL, channels[chan].noint); + return result; +} + +/* Write channel */ +void +ide_write(uint8_t chan, uint8_t reg, uint8_t data) +{ + if (reg > 0x07 && reg < 0x0C) + ide_write(chan, ATA_REG_CONTROL, 0x80 | channels[chan].noint); + if (reg < 0x08) + outb(channels[chan].base + reg - 0x00, data); + else if (reg < 0x0C) + outb(channels[chan].base + reg - 0x06, data); + else if (reg < 0x0E) + outb(channels[chan].ctrl + reg - 0x0A, data); + else if (reg < 0x16) + outb(channels[chan].bmide + reg - 0x0E, data); + if (reg > 0x07 && reg < 0x0C) + ide_write(chan, ATA_REG_CONTROL, channels[chan].noint); +} + +/* Read identification space */ +void +ide_read_buffer(uint8_t chan, uint8_t reg, void *buffer, uint32_t quads) +{ + if (reg > 0x07 && reg < 0x0C) + ide_write(chan, ATA_REG_CONTROL, 0x80 | channels[chan].noint); + asm volatile("pushw %es; movw %ds, %ax; movw %ax, %es"); + if (reg < 0x08) + insl(channels[chan].base + reg - 0x00, buffer, quads); + else if (reg < 0x0C) + insl(channels[chan].base + reg - 0x06, buffer, quads); + else if (reg < 0x0E) + insl(channels[chan].ctrl + reg - 0x0A, buffer, quads); + else if (reg < 0x16) + insl(channels[chan].bmide + reg - 0x0E, buffer, quads); + asm volatile("popw %es"); + if (reg > 0x07 && reg < 0x0C) + ide_write(chan, ATA_REG_CONTROL, channels[chan].noint); +} + +/* Poll for status after command */ +uint8_t +ide_polling(uint8_t chan, uint32_t check) +{ + uint8_t i, state; + /* Wait for BSY to set */ + for (i = 0; i < 4; i++) + ide_read(chan, ATA_REG_ALTSTATUS); + /* Wait for BSY to clear */ + while (ide_read(chan, ATA_REG_STATUS) & ATA_SR_BSY); + + if (check) { + state = ide_read(chan, ATA_REG_STATUS); + if (state & ATA_SR_ERR) + return 2; + if (state & ATA_SR_DF) + return 1; + if ((state & ATA_SR_DRQ) == 0) + return 3; + } + + return 0; +} + +/* Print an IDE error */ +uint8_t +ide_print_error(uint32_t drive, uint8_t err) +{ + if (err == 0) + return err; + + uint8_t st; + kprintf("IDE:"); + if (err == 1) { + kprintf(" - Device fault"); + err = 19; + } else if (err == 2) { + st = ide_read(ideDevices[drive].channel, ATA_REG_ERROR); + if (st & ATA_ER_AMNF) { + kprintf(" - No address mark found"); + err = 7; + } + if (st & ATA_ER_T0NF) { + kprintf(" - No media or media error"); + err = 3; + } + if (st & ATA_ER_ABRT) { + kprintf(" - Command aborted"); + err = 20; + } + if (st & ATA_ER_MCR) { + kprintf(" - No media or media error"); + err = 3; + } + if (st & ATA_ER_IDNF) { + kprintf(" - ID mark not found"); + err = 21; + } + if (st & ATA_ER_MC) { + kprintf(" - No media or media error"); + err = 3; + } + if (st & ATA_ER_UNC) { + kprintf(" - Uncorrectable data error"); + err = 22; + } + if (st & ATA_ER_BBK) { + kprintf(" - Bad sectors"); + err = 13; + } + } else if (err == 3) { + kprintf(" - Read nothing"); + err = 23; + } else if (err == 4) { + kprintf(" - Write protected"); + err = 8; + } + kprintf(" - [%s %s] %s", + (char *[]){"Primary","Secondary"}[ideDevices[drive].channel], + (char *[]){"Master","Slave"}[ideDevices[drive].drive], + ideDevices[drive].model); + return err; +} + +/* Initialise an IDE drive */ +void +ide_drive_init(uint32_t bar0, uint32_t bar1, uint32_t bar2, + uint32_t bar3, uint32_t bar4) +{ + channels[ATA_PRIMARY].base = (bar0 & ~3) + 0x1F0 * (!bar0); + channels[ATA_PRIMARY].ctrl = (bar1 & ~3) + 0x3F6 * (!bar1); + channels[ATA_SECONDARY].base = (bar2 & ~3) + 0x170 * (!bar2); + channels[ATA_SECONDARY].ctrl = (bar3 & ~3) + 0x376 * (!bar3); + channels[ATA_PRIMARY].bmide = (bar4 & ~3) + 0; + channels[ATA_SECONDARY].bmide = (bar4 & ~3) + 8; + /* Disable IRQs */ + ide_write(ATA_PRIMARY, ATA_REG_CONTROL, 2); + ide_write(ATA_SECONDARY, ATA_REG_CONTROL, 2); + + uint32_t count = 0; + uint8_t i, j, k, err, type, status; + for (i = 0; i < 2; i++) + for (j = 0; j < 2; j++) { + err = 0; + type = IDE_ATA; + ideDevices[count].reserved = 0; + ide_write(i, ATA_REG_HDDEVSEL, 0xA0 | (j << 4)); + sleep(1); + ide_write(i, ATA_REG_COMMAND, ATA_CMD_IDENTIFY); + sleep(1); + if (ide_read(i, ATA_REG_STATUS) == 0) + continue; + + while (1) { + status = ide_read(i, ATA_REG_STATUS); + if ((status & ATA_SR_ERR)) { + err = 1; + break; + } + if (!(status & ATA_SR_BSY) && (status & ATA_SR_DRQ)) + break; + } + + if (err) { + uint8_t cl = ide_read(i, ATA_REG_LBA1); + uint8_t ch = ide_read(i, ATA_REG_LBA2); + + if (cl == 0x14 && ch == 0xEB) + type = IDE_ATAPI; + else if (cl == 0x69 && ch == 0x96) + type = IDE_ATAPI; + else + continue; + + ide_write(i, ATA_REG_COMMAND, ATA_CMD_IDENTIFY_PACKET); + sleep(1); + } + + ide_read_buffer(i, ATA_REG_DATA, ideBuf, 128); + + uint16_t sig, cap, set; + sig = *((uint16_t *) (ideBuf + ATA_IDENT_DEVICETYPE)); + cap = *((uint16_t *) (ideBuf + ATA_IDENT_CAPABILITIES)); + set = *((uint16_t *) (ideBuf + ATA_IDENT_COMMANDSETS)); + ideDevices[count].reserved = 1; + ideDevices[count].type = type; + ideDevices[count].channel = i; + ideDevices[count].drive = j; + ideDevices[count].signature = sig; + ideDevices[count].capabilities = cap; + ideDevices[count].commandSets = set; + + uint32_t size; + if (ideDevices[count].commandSets & (1 << 26)) + size = *((uint32_t *) (ideBuf + ATA_IDENT_MAX_LBA_EXT)); + else + size = *((uint32_t *) (ideBuf + ATA_IDENT_MAX_LBA)); + ideDevices[count].size = size; + for (k = 0; k < 40; k += 2) { + ideDevices[count].model[k] = + ideBuf[ATA_IDENT_MODEL + k + 1]; + ideDevices[count].model[k + 1] = + ideBuf[ATA_IDENT_MODEL + k]; + } + ideDevices[count].model[40] = 0; + count++; + } +} + +/* Wait for an IRQ to arrive */ +void +ide_wait_irq(void) +{ + while (!ideIrqInvoked); + ideIrqInvoked = 0; +} + +/* Access an ATA drive */ +uint8_t +ide_ata_access(uint8_t write, uint8_t drive, uint32_t lba, uint8_t sectors, + uint16_t selector, uint32_t edi) +{ + uint8_t lbaMode, dma, cmd; + uint8_t lbaIO[6]; + uint32_t chan = ideDevices[drive].channel; + uint32_t slave = ideDevices[drive].drive; + uint32_t bus = channels[chan].base; + uint32_t words = 256; + uint16_t cyl, i; + uint8_t head, sect, err; + + ide_write(chan, ATA_REG_CONTROL, + channels[chan].noint = (ideIrqInvoked = 0) + 2); + + if (lba >= 0x10000000) { + /* LBA48 */ + lbaMode = 2; + lbaIO[0] = (lba & 0x000000FF) >> 0; + lbaIO[1] = (lba & 0x0000FF00) >> 8; + lbaIO[2] = (lba & 0x00FF0000) >> 16; + lbaIO[3] = (lba & 0xFF000000) >> 24; + lbaIO[4] = 0; + lbaIO[5] = 0; + head = 0; + } else if (ideDevices[drive].capabilities & 0x200) { + /* LBA28 */ + lbaMode = 1; + lbaIO[0] = (lba & 0x000000FF) >> 0; + lbaIO[1] = (lba & 0x0000FF00) >> 8; + lbaIO[2] = (lba & 0x00FF0000) >> 16; + lbaIO[3] = 0; + lbaIO[4] = 0; + lbaIO[5] = 0; + head = (lba & 0x0F000000) >> 24; + } else { + /* CHS */ + lbaMode = 0; + sect = (lba % 63) + 1; + cyl = (lba + 1 - sect) / (16 * 63); + lbaIO[0] = sect; + lbaIO[1] = (cyl >> 0) & 0xFF; + lbaIO[2] = (cyl >> 8) & 0xFF; + lbaIO[3] = 0; + lbaIO[4] = 0; + lbaIO[5] = 0; + head = (lba + 1 - sect) % (16 * 63) / 63; + } + + dma = 0; /* XXX */ + + while (ide_read(chan, ATA_REG_STATUS) & ATA_SR_BSY); + + if (lbaMode == 0) + ide_write(chan, ATA_REG_HDDEVSEL, 0xA0 | (slave << 4) | head); + else + ide_write(chan, ATA_REG_HDDEVSEL, 0xE0 | (slave << 4) | head); + + if (lbaMode == 2) { + ide_write(chan, ATA_REG_SECCOUNT1, 0); + ide_write(chan, ATA_REG_LBA3, lbaIO[3]); + ide_write(chan, ATA_REG_LBA4, lbaIO[4]); + ide_write(chan, ATA_REG_LBA5, lbaIO[5]); + } + ide_write(chan, ATA_REG_SECCOUNT0, sectors); + ide_write(chan, ATA_REG_LBA0, lbaIO[0]); + ide_write(chan, ATA_REG_LBA1, lbaIO[1]); + ide_write(chan, ATA_REG_LBA2, lbaIO[2]); + + if (lbaMode == 0 && !dma && !write) cmd = ATA_CMD_READ_PIO; + if (lbaMode == 1 && !dma && !write) cmd = ATA_CMD_READ_PIO; + if (lbaMode == 2 && !dma && !write) cmd = ATA_CMD_READ_PIO_EXT; + if (lbaMode == 0 && dma && !write) cmd = ATA_CMD_READ_DMA; + if (lbaMode == 1 && dma && !write) cmd = ATA_CMD_READ_DMA; + if (lbaMode == 2 && dma && !write) cmd = ATA_CMD_READ_DMA_EXT; + if (lbaMode == 0 && !dma && write) cmd = ATA_CMD_WRITE_PIO; + if (lbaMode == 1 && !dma && write) cmd = ATA_CMD_WRITE_PIO; + if (lbaMode == 2 && !dma && write) cmd = ATA_CMD_WRITE_PIO_EXT; + if (lbaMode == 0 && dma && write) cmd = ATA_CMD_WRITE_DMA; + if (lbaMode == 1 && dma && write) cmd = ATA_CMD_WRITE_DMA; + if (lbaMode == 2 && dma && write) cmd = ATA_CMD_WRITE_DMA_EXT; + ide_write(chan, ATA_REG_COMMAND, cmd); + + if (dma) { + if (write) { + /* TODO */ + } else { + /* TODO */ + } + } else { + if (write) { + for (i = 0; i < sectors; i++) { + ide_polling(chan, 0); + outsw(bus, (void *) edi, words); + } + ide_write(chan, ATA_REG_COMMAND, (uint8_t []) { + ATA_CMD_CACHE_FLUSH, + ATA_CMD_CACHE_FLUSH, + ATA_CMD_CACHE_FLUSH_EXT, + }[lbaMode]); + ide_polling(chan, 0); + } else { + for (i = 0; i < sectors; i++) { + if (err = ide_polling(chan, 1)) + return err; + insw(bus, (void *) edi, words); + edi += words * 2; + } + } + } + + return 0; +} + +/* IDE IRQ handler */ +void +ide_irq(InterruptFrame *frame) +{ + ideIrqInvoked = 1; +} + +/* Initialise an IDE drive */ +void +ide_init(uint8_t bus, uint8_t slot, uint8_t func) +{ + register_driver(&ideDriver); + + uint8_t class, subclass, progif, header; + class = pci_read_byte(bus, slot, func, 11); + subclass = pci_read_byte(bus, slot, func, 10); + progif = pci_read_byte(bus, slot, func, 9); + header = pci_read_byte(bus, slot, func, 14); + + uint8_t primaryNative = 0, primaryChange = 0, + secondaryNative = 0, secondaryChange = 0, + busMaster = 0; + if (progif & (1 << 0)) + primaryNative = 1; + if (progif & (1 << 1)) + primaryChange = 1; + if (progif & (1 << 2)) + secondaryNative = 1; + if (progif & (1 << 3)) + secondaryChange = 1; + if (progif & (1 << 7)) + busMaster = 1; + + uint32_t bar0 = 0x1F0, bar1 = 0x3F6, + bar2 = 0x170, bar3 = 0x376, + bar4 = 0x00; + + if (primaryNative) { + bar0 = pci_read_dword(bus, slot, func, 0x10); + bar1 = pci_read_dword(bus, slot, func, 0x14); + } + if (secondaryNative) { + bar2 = pci_read_dword(bus, slot, func, 0x18); + bar3 = pci_read_dword(bus, slot, func, 0x1C); + } + if (busMaster) + bar4 = pci_read_dword(bus, slot, func, 0x20); + + register_interrupt(14, ide_irq); + ataDmaArea = alloc_frames(1); + + ide_drive_init(0x1F0, 0x3F6, 0x170, 0x376, 0x00); + uint8_t i, j; + char name[16]; + for (i = 0; i < 4; i++) { + if (!ideDevices[i].reserved) + continue; + sprintf(name, "/dev/%cd%c", + (char []){'h','c'}[ideDevices[i].type], + (char []){'a','b'}[ideDevices[i].channel]); + mknod(name, S_IFBLK | 0600, MKDEV(ideDriver.major, i * 16)); + kprintf(" %s drive [%s] %d MB - %s", + (char *[]){"ATA", "ATAPI"}[ideDevices[i].type], + name, ideDevices[i].size / 1024 / 2, + ideDevices[i].model); + /* Attempt to read partition table */ + if (ideDevices[i].type != 0) + continue; + ide_ata_access(0, i, 0, 0x02, 1, ataDmaArea); + struct partition *part; + for (j = 0; j < 4; j++) { + part = (void *) ataDmaArea + 446 + (j * 16); + if (!part->type) + continue; + sprintf(name, "/dev/%cd%c%d", + (char []){'h','c'}[ideDevices[i].type], + (char []){'a','b'}[ideDevices[i].channel], + j + 1); + int asdf = mknod(name, S_IFBLK | 0600, + MKDEV(ideDriver.major, (i * 16) + (j + 1))); + kprintf(" Partition %d: %#.8x - %#.8x", + j+1, part->lba*512, + (part->lba + part->size) * 512); + } + } +} + +/* Read a drive */ +size_t +ata_read(File *file, char *buf, size_t size, off_t offset) +{ + uint16_t min, bufOffset = offset % 512; + size_t count = 0; + uint16_t dev = MINOR(file->inode->dev) / 16, + parti = MINOR(file->inode->dev) % 16; + uint32_t lba; + struct partition *part; + if (parti) { + ide_ata_access(0, dev, 0, 1, 0x02, ataDmaArea); + part = (void *) ataDmaArea + 446 + ((parti - 1) * 16); + if (offset > (part->lba + part->size) * 512) + return 0; + if (offset + size > (part->lba + part->size) * 512) + size = ((part->lba + part->size) * 512) - offset; + } else { + if (offset > ideDevices[dev].size * 512) + return 0; + if (offset + size > ideDevices[dev].size * 512) + size = (ideDevices[dev].size * 512) - offset; + } + while (size + bufOffset) { + min = (size > 0x1000) ? 0x1000 : size; + lba = (parti ? part->lba : 0) + ((offset + count) / 512); + ide_ata_access(0, dev, lba, 8, 0x02, ataDmaArea); + memcpy((void *) (buf + count), + (void *) ataDmaArea + bufOffset, + min); + size -= min; + count += min; + bufOffset = 0; + } + return count; +} + +/* Write a drive */ +size_t +ata_write(File *file, char *buf, size_t size, off_t offset) +{ + uint16_t min; + size_t count = 0; + uint16_t dev = MINOR(file->inode->dev) / 16, + parti = MINOR(file->inode->dev) % 16; + uint32_t lba; + struct partition *part; + if (parti) { + ide_ata_access(0, dev, 0, 1, 0x02, ataDmaArea); + part = (void *) ataDmaArea + 446 + ((parti - 1) * 16); + if (offset > (part->lba + part->size) * 512) + return 0; + if (offset + size > (part->lba + part->size) * 512) + size = ((part->lba + part->size) * 512) - offset; + } else { + if (offset > ideDevices[dev].size * 512) + return 0; + if (offset + size > ideDevices[dev].size * 512) + size = (ideDevices[dev].size * 512) - offset; + } + while (size) { + min = (size > 0x1000) ? 0x1000 : size; + memcpy((void *) ataDmaArea, +// (void *) (((uint32_t) (buf + count) / 512) * 512), + (void *) (buf + count), + min); + lba = (parti ? part->lba : 0) + ((offset + count) / 512); + ide_ata_access(1, dev, lba, 8, 0x02, ataDmaArea); + size -= min; + count += min; + } + return count; + /* + * TODO: Currently, offset is sector-aligned, which we don't always + * want. This should be fixed by basically checking the offset + * for this and reading into the dma buffer before we write to the + * adjusted offset in the buffer, this way the surrounding data + * isn't deleted by accident with bad alignment. + */ +} + +/* Open a drive */ +int +ata_open(File *file) +{ + if (ideDevices[MINOR(file->inode->dev)/16].reserved) + return 0; + if (ideDevices[MINOR(file->inode->dev)/16].type != 0) + return -EINVAL; + return -ENODEV; +} + diff --git a/drivers/net/rtl8139.c b/drivers/net/rtl8139.c new file mode 100644 index 0000000..e801845 --- /dev/null +++ b/drivers/net/rtl8139.c @@ -0,0 +1,148 @@ +/* + * The is the RTL8139 driver. It is a simple driver for a simple network card. + * It will just abstract the hardware away, and allows the network system to + * utilise it + */ + +#include <stdint.h> +#include <stddef.h> +#include <string.h> +#include "../pci.h" +#include "../../mem/heap.h" +#include "../../proc/proc.h" +#include "../../net/net.h" +#include "../../io.h" +#include "../../screen.h" + +#define RTL_PORT_MAC 0x00 +#define RTL_PORT_RX_PTR 0x38 +#define RTL_PORT_RBSTART 0x30 +#define RTL_PORT_IMR 0x3C +#define RTL_PORT_ISR 0x3E +#define RTL_PORT_CMD 0x37 +#define RTL_PORT_RXMISS 0x4C +#define RTL_PORT_TCR 0x40 +#define RTL_PORT_RCR 0x44 +#define RTL_PORT_CONFIG 0x52 +#define RTL_RX_BUF_SIZE (8192+16+1500) +#define RTL_TX_BUF_SIZE (1536) + +#define RTL_CFG_AAP (1 << 0) /* Accept all packets */ +#define RTL_CFG_APM (1 << 1) /* Accept packets to NIC's MAC address */ +#define RTL_CFG_AM (1 << 2) /* Accept multicast packets */ +#define RTL_CFG_AB (1 << 3) /* Accept broadcast packets */ + +#define RTL_ISR_ROK (1 << 0) /* Receive Okay */ +#define RTL_ISR_TOK (1 << 2) /* Transmit Okay */ + +static NetIF *netif; + +void *txBuf, *rxBuf; +uint8_t txIndex = 0; +uint32_t rxIndex = 0; +uint16_t port; + +uint16_t txStartRegs[] = {0x20, 0x24, 0x28, 0x2C}; +uint16_t txControlRegs[] = {0x10, 0x14, 0x18, 0x1C}; + +void rtl8139_transmit(void *data, size_t len); +void rtl8139_receive(void); + +/* Handle the RTL8139 interrupt */ +void +rtl8139_irq(InterruptFrame *frame) +{ + uint16_t status; + /* Loop until everything has been handled */ + while (1) { + status = inw(port + RTL_PORT_ISR); + outw(port + RTL_PORT_ISR, status); + if (!status) + break; + if (status & RTL_ISR_ROK) + rtl8139_receive(); + } +} + +/* Transmit a frame */ +void +rtl8139_transmit(void *data, size_t len) +{ + memcpy(txBuf, data, len); + outl(port + txStartRegs[txIndex], (uintptr_t) txBuf); + outl(port + txControlRegs[txIndex], len); + txIndex++; + if (txIndex > 3) + txIndex = 0; +} + +/* Receive a frame */ +void +rtl8139_receive(void) +{ + uint8_t *frame, *buf = rxBuf; + uint32_t index = rxIndex; + uint32_t offset, len; + + /* While the buffer is not empty */ + while ((inb(port + RTL_PORT_CMD) & 0x01) == 0) { + offset = index % RTL_RX_BUF_SIZE; + len = (buf[3 + index] << 8) + buf[2 + index]; + + frame = kmalloc(len); + memcpy(frame, &buf[offset + 4], len); + ethernet_receive_frame(netif, frame, len); + kfree(frame); + + index = (index + len + 7) & ~3; + outw(port + RTL_PORT_RX_PTR, index - 16); + } + + rxIndex = index; +} + +/* Get the RTL8139 MAC Address */ +void +rtl8139_get_mac(char *buf) +{ + uint8_t i; + for (i = 0; i < 6; i++) + buf[i] = inb(port + RTL_PORT_MAC + i); +} + +/* Initialise the RTL8139 Network card */ +void +rtl8139_init(uint8_t bus, uint8_t dev, uint8_t func) +{ + /* Enable bus mastering */ + uint16_t command = pci_read_word(bus, dev, func, 4); + if (!(command & (1 << 2))) + pci_write_word(bus, dev, func, 4, command | (1 << 2)); + + /* Turn device on */ + port = pci_read_word(bus, dev, func, 0x10) & ~3; + outb(port + RTL_PORT_CONFIG, 0x00); + /* Software reset */ + outb(port + RTL_PORT_CMD, 0x10); + while ((inb(port + RTL_PORT_CMD) & 0x10) != 0); + /* Initialise buffers */ + txBuf = kmalloc(RTL_RX_BUF_SIZE); + rxBuf = kmalloc(RTL_TX_BUF_SIZE); + /* TODO: use dedicated DMA area */ + outl(port + RTL_PORT_RBSTART, (uintptr_t) rxBuf); + /* IMR & ISR */ + outw(port + RTL_PORT_IMR, 0x05); + + /* Configure receive buffer */ + outl(port + RTL_PORT_RCR, (1 << 7) | + RTL_CFG_AB | RTL_CFG_AM | RTL_CFG_APM | RTL_CFG_AAP); + /* Enable RX and TX */ + outb(port + RTL_PORT_CMD, 0x0C); + + /* Register interrupt handler */ + uint8_t irq = pci_read_byte(bus, dev, func, 0x3C); + register_interrupt(irq, rtl8139_irq); + + /* Setup Network Interface */ + netif = net_create_interface(1, rtl8139_transmit, rtl8139_get_mac); +} diff --git a/drivers/pci.c b/drivers/pci.c new file mode 100644 index 0000000..22db76e --- /dev/null +++ b/drivers/pci.c @@ -0,0 +1,55 @@ +/* + * This file contains the routines for accessing the PCI devices. It just wraps + * the IO functions necessary to read/write the PCI Configuration Space. It + * uses PCI Configuration Space Access Mechanism #1, which is the most supported + * access mechanism. + */ + +#include <stdint.h> +#include "pci.h" +#include "../io.h" + +/* Read PCI config */ +uint8_t +pci_read_byte(int bus, int dev, int func, int off) +{ + outl(0xCF8, (1 << 31) | (bus << 16) | (dev << 11) | + (func << 8) | (off & 0xFC)); + return inb(0xCFC + (off & 3)); +} +uint16_t +pci_read_word(int bus, int dev, int func, int off) +{ + outl(0xCF8, (1 << 31) | (bus << 16) | (dev << 11) | + (func << 8) | (off & 0xFC)); + return inw(0xCFC + (off & 2)); +} +uint32_t +pci_read_dword(int bus, int dev, int func, int off) +{ + outl(0xCF8, (1 << 31) | (bus << 16) | (dev << 11) | + (func << 8) | (off & 0xFC)); + return inl(0xCFC); +} +/* Write PCI config */ +void +pci_write_byte(int bus, int dev, int func, int off, uint8_t value) +{ + outl(0xCF8, (1 << 31) | (bus << 16) | (dev << 11) | + (func << 8) | (off & 0xFC)); + outb(0xCFC + (off & 3), value); +} +void +pci_write_word(int bus, int dev, int func, int off, uint16_t value) +{ + outl(0xCF8, (1 << 31) | (bus << 16) | (dev << 11) | + (func << 8) | (off & 0xFC)); + outw(0xCFC + (off & 2), value); +} +void +pci_write_dword(int bus, int dev, int func, int off, uint32_t value) +{ + outl(0xCF8, (1 << 31) | (bus << 16) | (dev << 11) | + (func << 8) | (off & 0xFC)); + outl(0xCFC, value); +} diff --git a/drivers/pci.h b/drivers/pci.h new file mode 100644 index 0000000..44b65ae --- /dev/null +++ b/drivers/pci.h @@ -0,0 +1,11 @@ +#ifndef KERNEL_PCI_H +#define KERNEL_PCI_H + +uint8_t pci_read_byte(int bus, int dev, int func, int off); +uint16_t pci_read_word(int bus, int dev, int func, int off); +uint32_t pci_read_dword(int bus, int dev, int func, int off); +void pci_write_byte(int bus, int dev, int func, int off, uint8_t value); +void pci_write_word(int bus, int dev, int func, int off, uint16_t value); +void pci_write_dword(int bus, int dev, int func, int off, uint32_t value); + +#endif diff --git a/drivers/tty/font.c b/drivers/tty/font.c new file mode 100644 index 0000000..bb35673 --- /dev/null +++ b/drivers/tty/font.c @@ -0,0 +1,260 @@ +#include <stdint.h> + +uint8_t font[4096] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x7e, 0x81, 0xa5, 0x81, 0x81, 0xbd, 0x99, 0x81, 0x81, 0x7e, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x7e, 0xff, 0xdb, 0xff, 0xff, 0xc3, 0xe7, 0xff, 0xff, 0x7e, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x6c, 0xfe, 0xfe, 0xfe, 0xfe, 0x7c, 0x38, 0x10, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x7c, 0xfe, 0x7c, 0x38, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x18, 0x3c, 0x3c, 0xe7, 0xe7, 0xe7, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x18, 0x3c, 0x7e, 0xff, 0xff, 0x7e, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x3c, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe7, 0xc3, 0xc3, 0xe7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x66, 0x42, 0x42, 0x66, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xc3, 0x99, 0xbd, 0xbd, 0x99, 0xc3, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x00, 0x00, 0x1e, 0x0e, 0x1a, 0x32, 0x78, 0xcc, 0xcc, 0xcc, 0xcc, 0x78, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x3c, 0x66, 0x66, 0x66, 0x66, 0x3c, 0x18, 0x7e, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x3f, 0x33, 0x3f, 0x30, 0x30, 0x30, 0x30, 0x70, 0xf0, 0xe0, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x7f, 0x63, 0x7f, 0x63, 0x63, 0x63, 0x63, 0x67, 0xe7, 0xe6, 0xc0, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x18, 0x18, 0xdb, 0x3c, 0xe7, 0x3c, 0xdb, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfe, 0xf8, 0xf0, 0xe0, 0xc0, 0x80, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x02, 0x06, 0x0e, 0x1e, 0x3e, 0xfe, 0x3e, 0x1e, 0x0e, 0x06, 0x02, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x18, 0x7e, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x7f, 0xdb, 0xdb, 0xdb, 0x7b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x7c, 0xc6, 0x60, 0x38, 0x6c, 0xc6, 0xc6, 0x6c, 0x38, 0x0c, 0xc6, 0x7c, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xfe, 0xfe, 0xfe, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x18, 0x7e, 0x3c, 0x18, 0x7e, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x7e, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x0c, 0xfe, 0x0c, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x60, 0xfe, 0x60, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xc0, 0xc0, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x24, 0x66, 0xff, 0x66, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x38, 0x7c, 0x7c, 0xfe, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xfe, 0xfe, 0x7c, 0x7c, 0x38, 0x38, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x18, 0x3c, 0x3c, 0x3c, 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x66, 0x66, 0x66, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x6c, 0x6c, 0xfe, 0x6c, 0x6c, 0x6c, 0xfe, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x00, + 0x18, 0x18, 0x7c, 0xc6, 0xc2, 0xc0, 0x7c, 0x06, 0x06, 0x86, 0xc6, 0x7c, 0x18, 0x18, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xc2, 0xc6, 0x0c, 0x18, 0x30, 0x60, 0xc6, 0x86, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x38, 0x6c, 0x6c, 0x38, 0x76, 0xdc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x30, 0x30, 0x30, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0c, 0x18, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x18, 0x0c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x30, 0x18, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x18, 0x30, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x3c, 0xff, 0x3c, 0x66, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x7e, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x30, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x02, 0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0, 0x80, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x3c, 0x66, 0xc3, 0xc3, 0xdb, 0xdb, 0xc3, 0xc3, 0x66, 0x3c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x18, 0x38, 0x78, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x7e, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x7c, 0xc6, 0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0, 0xc6, 0xfe, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x7c, 0xc6, 0x06, 0x06, 0x3c, 0x06, 0x06, 0x06, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0c, 0x1c, 0x3c, 0x6c, 0xcc, 0xfe, 0x0c, 0x0c, 0x0c, 0x1e, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xfe, 0xc0, 0xc0, 0xc0, 0xfc, 0x06, 0x06, 0x06, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x38, 0x60, 0xc0, 0xc0, 0xfc, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xfe, 0xc6, 0x06, 0x06, 0x0c, 0x18, 0x30, 0x30, 0x30, 0x30, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0x7e, 0x06, 0x06, 0x06, 0x0c, 0x78, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x18, 0x18, 0x30, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x06, 0x0c, 0x18, 0x30, 0x60, 0x30, 0x18, 0x0c, 0x06, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x60, 0x30, 0x18, 0x0c, 0x06, 0x0c, 0x18, 0x30, 0x60, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0x0c, 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xde, 0xde, 0xde, 0xdc, 0xc0, 0x7c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x10, 0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xfc, 0x66, 0x66, 0x66, 0x7c, 0x66, 0x66, 0x66, 0x66, 0xfc, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x3c, 0x66, 0xc2, 0xc0, 0xc0, 0xc0, 0xc0, 0xc2, 0x66, 0x3c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xf8, 0x6c, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x6c, 0xf8, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xfe, 0x66, 0x62, 0x68, 0x78, 0x68, 0x60, 0x62, 0x66, 0xfe, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xfe, 0x66, 0x62, 0x68, 0x78, 0x68, 0x60, 0x60, 0x60, 0xf0, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x3c, 0x66, 0xc2, 0xc0, 0xc0, 0xde, 0xc6, 0xc6, 0x66, 0x3a, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x3c, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x1e, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0xcc, 0xcc, 0xcc, 0x78, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xe6, 0x66, 0x66, 0x6c, 0x78, 0x78, 0x6c, 0x66, 0x66, 0xe6, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xf0, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x62, 0x66, 0xfe, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xc3, 0xe7, 0xff, 0xff, 0xdb, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xc6, 0xe6, 0xf6, 0xfe, 0xde, 0xce, 0xc6, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xfc, 0x66, 0x66, 0x66, 0x7c, 0x60, 0x60, 0x60, 0x60, 0xf0, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xd6, 0xde, 0x7c, 0x0c, 0x0e, 0x00, 0x00, + 0x00, 0x00, 0xfc, 0x66, 0x66, 0x66, 0x7c, 0x6c, 0x66, 0x66, 0x66, 0xe6, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0x60, 0x38, 0x0c, 0x06, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xff, 0xdb, 0x99, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0x66, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xdb, 0xdb, 0xff, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xc3, 0xc3, 0x66, 0x3c, 0x18, 0x18, 0x3c, 0x66, 0xc3, 0xc3, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xc3, 0xc3, 0xc3, 0x66, 0x3c, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xff, 0xc3, 0x86, 0x0c, 0x18, 0x30, 0x60, 0xc1, 0xc3, 0xff, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x3c, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x3c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x80, 0xc0, 0xe0, 0x70, 0x38, 0x1c, 0x0e, 0x06, 0x02, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x3c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x3c, 0x00, 0x00, 0x00, 0x00, + 0x10, 0x38, 0x6c, 0xc6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, + 0x30, 0x30, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xe0, 0x60, 0x60, 0x78, 0x6c, 0x66, 0x66, 0x66, 0x66, 0x7c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc0, 0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x1c, 0x0c, 0x0c, 0x3c, 0x6c, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x38, 0x6c, 0x64, 0x60, 0xf0, 0x60, 0x60, 0x60, 0x60, 0xf0, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x7c, 0x0c, 0xcc, 0x78, 0x00, + 0x00, 0x00, 0xe0, 0x60, 0x60, 0x6c, 0x76, 0x66, 0x66, 0x66, 0x66, 0xe6, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x18, 0x18, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x06, 0x06, 0x00, 0x0e, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x66, 0x66, 0x3c, 0x00, + 0x00, 0x00, 0xe0, 0x60, 0x60, 0x66, 0x6c, 0x78, 0x78, 0x6c, 0x66, 0xe6, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xe6, 0xff, 0xdb, 0xdb, 0xdb, 0xdb, 0xdb, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xdc, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xdc, 0x66, 0x66, 0x66, 0x66, 0x66, 0x7c, 0x60, 0x60, 0xf0, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x7c, 0x0c, 0x0c, 0x1e, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xdc, 0x76, 0x66, 0x60, 0x60, 0x60, 0xf0, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0x60, 0x38, 0x0c, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x10, 0x30, 0x30, 0xfc, 0x30, 0x30, 0x30, 0x30, 0x36, 0x1c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0xc3, 0xc3, 0xc3, 0x66, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0xc3, 0xc3, 0xdb, 0xdb, 0xff, 0x66, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0x66, 0x3c, 0x18, 0x3c, 0x66, 0xc3, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7e, 0x06, 0x0c, 0xf8, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xcc, 0x18, 0x30, 0x60, 0xc6, 0xfe, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0e, 0x18, 0x18, 0x18, 0x70, 0x18, 0x18, 0x18, 0x18, 0x0e, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x70, 0x18, 0x18, 0x18, 0x0e, 0x18, 0x18, 0x18, 0x18, 0x70, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xdc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x6c, 0xc6, 0xc6, 0xc6, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x3c, 0x66, 0xc2, 0xc0, 0xc0, 0xc0, 0xc2, 0x66, 0x3c, 0x0c, 0x06, 0x7c, 0x00, 0x00, + 0x00, 0x00, 0xcc, 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x0c, 0x18, 0x30, 0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x10, 0x38, 0x6c, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xcc, 0x00, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x60, 0x30, 0x18, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x38, 0x6c, 0x38, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x3c, 0x66, 0x60, 0x60, 0x66, 0x3c, 0x0c, 0x06, 0x3c, 0x00, 0x00, 0x00, + 0x00, 0x10, 0x38, 0x6c, 0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xc6, 0x00, 0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x60, 0x30, 0x18, 0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x66, 0x00, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x18, 0x3c, 0x66, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x60, 0x30, 0x18, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xc6, 0x00, 0x10, 0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00, + 0x38, 0x6c, 0x38, 0x00, 0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00, + 0x18, 0x30, 0x60, 0x00, 0xfe, 0x66, 0x60, 0x7c, 0x60, 0x60, 0x66, 0xfe, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x6e, 0x3b, 0x1b, 0x7e, 0xd8, 0xdc, 0x77, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x3e, 0x6c, 0xcc, 0xcc, 0xfe, 0xcc, 0xcc, 0xcc, 0xcc, 0xce, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x10, 0x38, 0x6c, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xc6, 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x60, 0x30, 0x18, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x30, 0x78, 0xcc, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x60, 0x30, 0x18, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xc6, 0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7e, 0x06, 0x0c, 0x78, 0x00, + 0x00, 0xc6, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xc6, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x18, 0x18, 0x7e, 0xc3, 0xc0, 0xc0, 0xc0, 0xc3, 0x7e, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x38, 0x6c, 0x64, 0x60, 0xf0, 0x60, 0x60, 0x60, 0x60, 0xe6, 0xfc, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xc3, 0x66, 0x3c, 0x18, 0xff, 0x18, 0xff, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xfc, 0x66, 0x66, 0x7c, 0x62, 0x66, 0x6f, 0x66, 0x66, 0x66, 0xf3, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x0e, 0x1b, 0x18, 0x18, 0x18, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x18, 0xd8, 0x70, 0x00, 0x00, + 0x00, 0x18, 0x30, 0x60, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x0c, 0x18, 0x30, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x18, 0x30, 0x60, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x18, 0x30, 0x60, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x76, 0xdc, 0x00, 0xdc, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00, + 0x76, 0xdc, 0x00, 0xc6, 0xe6, 0xf6, 0xfe, 0xde, 0xce, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x3c, 0x6c, 0x6c, 0x3e, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x38, 0x6c, 0x6c, 0x38, 0x00, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x30, 0x30, 0x00, 0x30, 0x30, 0x60, 0xc0, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xc0, 0xc0, 0xc0, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x06, 0x06, 0x06, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xc0, 0xc0, 0xc2, 0xc6, 0xcc, 0x18, 0x30, 0x60, 0xce, 0x9b, 0x06, 0x0c, 0x1f, 0x00, 0x00, + 0x00, 0xc0, 0xc0, 0xc2, 0xc6, 0xcc, 0x18, 0x30, 0x66, 0xce, 0x96, 0x3e, 0x06, 0x06, 0x00, 0x00, + 0x00, 0x00, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x3c, 0x3c, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x36, 0x6c, 0xd8, 0x6c, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xd8, 0x6c, 0x36, 0x6c, 0xd8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, + 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, + 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, + 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x18, 0xf8, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xf6, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x18, 0xf8, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x36, 0x36, 0x36, 0x36, 0x36, 0xf6, 0x06, 0xf6, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x06, 0xf6, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x36, 0xf6, 0x06, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x18, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x18, 0x1f, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x37, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x37, 0x30, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x30, 0x37, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x36, 0xf7, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0xf7, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x37, 0x30, 0x37, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x36, 0x36, 0x36, 0x36, 0x36, 0xf7, 0x00, 0xf7, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x18, 0x18, 0x18, 0x18, 0x18, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x18, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x18, 0x1f, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xff, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x18, 0x18, 0x18, 0x18, 0x18, 0xff, 0x18, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, + 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xdc, 0xd8, 0xd8, 0xd8, 0xdc, 0x76, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x78, 0xcc, 0xcc, 0xcc, 0xd8, 0xcc, 0xc6, 0xc6, 0xc6, 0xcc, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xfe, 0xc6, 0xc6, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xfe, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xfe, 0xc6, 0x60, 0x30, 0x18, 0x30, 0x60, 0xc6, 0xfe, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0xd8, 0xd8, 0xd8, 0xd8, 0xd8, 0x70, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x66, 0x7c, 0x60, 0x60, 0xc0, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x76, 0xdc, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x7e, 0x18, 0x3c, 0x66, 0x66, 0x66, 0x3c, 0x18, 0x7e, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0x6c, 0x38, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x38, 0x6c, 0xc6, 0xc6, 0xc6, 0x6c, 0x6c, 0x6c, 0x6c, 0xee, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x1e, 0x30, 0x18, 0x0c, 0x3e, 0x66, 0x66, 0x66, 0x66, 0x3c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0xdb, 0xdb, 0xdb, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x03, 0x06, 0x7e, 0xdb, 0xdb, 0xf3, 0x7e, 0x60, 0xc0, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x1c, 0x30, 0x60, 0x60, 0x7c, 0x60, 0x60, 0x60, 0x30, 0x1c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xfe, 0x00, 0x00, 0xfe, 0x00, 0x00, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x7e, 0x18, 0x18, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x30, 0x18, 0x0c, 0x06, 0x0c, 0x18, 0x30, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x0c, 0x18, 0x30, 0x60, 0x30, 0x18, 0x0c, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0e, 0x1b, 0x1b, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xd8, 0xd8, 0xd8, 0x70, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x7e, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xdc, 0x00, 0x76, 0xdc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x38, 0x6c, 0x6c, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x0f, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0xec, 0x6c, 0x6c, 0x3c, 0x1c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xd8, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x70, 0xd8, 0x30, 0x60, 0xc8, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; diff --git a/drivers/tty/tty.c b/drivers/tty/tty.c new file mode 100644 index 0000000..c65aeaf --- /dev/null +++ b/drivers/tty/tty.c @@ -0,0 +1,424 @@ +/* + * This file contains the implementation of the TTY Device. Generates a device + * /dev/tty, which displays to the default text video output. This file handles + * all the formatting required for a TTY. + */ + +#include <unistd.h> +#include <fcntl.h> +#include <string.h> +#include <sys/fb.h> +#include <termios.h> +#include "../drivers.h" +#include "../../task/task.h" +#include "../../proc/proc.h" +#include "../../mem/heap.h" +#include "../../io.h" + +size_t tty_read(File *file, char *buf, size_t size, off_t offset); +size_t tty_write(File *file, char *buf, size_t size, off_t offset); +int tty_ioctl(File *file, unsigned long request, uintptr_t argp); +int tty_open(File *file); + +FileOps ttyFileOps = { + .read = tty_read, + .write = tty_write, + .ioctl = tty_ioctl, + .open = tty_open, +}; + +Driver ttyDriver = { + .major = 5, + .ops = &ttyFileOps, + .next = NULL, +}; + +extern uint8_t font[]; + +Termios tty; +uintptr_t vgaLfb; +int vgaWidth, vgaHeight, vgaBpp; +int ttyMode; +int ttyX, ttyY; +int ttyW = 80, ttyH = 25; +char ttyAttr = 0x07; +char *lineBuf, *line; +int lineBufLen = 0, lineLen = 0; +unsigned char shift = 0, ctrl = 0; + +uint32_t colours[] = { + 0x000000, + 0x0000FF, + 0x00FF00, + 0x00FFFF, + 0xFF0000, + 0xFF00FF, + 0x884422, + 0xCCCCCC, + 0x666666, + 0x6666FF, + 0x66FF66, + 0x66FFFF, + 0xFF6666, + 0xFF66FF, + 0xFFFF66, + 0xFFFFFF, +}; + +TaskQueue ttyWait; + +/* Map of keys on the keyboard */ +char kbmap[128] = { + 0, 27, + '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '-', '=', '\b', + '\t', 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p', '[', ']', '\n', + 0, 'a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';', '\'', '`', + 0, '#', 'z', 'x', 'c', 'v', 'b', 'n', 'm', ',', '.', '/', 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 +}; +char skbmap[128] = { + 0, 27, + '!', '"', '$', '$', '%', '^', '&', '*', '(', ')', '_', '+', '\b', + '\t', 'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I', 'O', 'P', '{', '}', '\n', + 0, 'A', 'S', 'D', 'F', 'G', 'H', 'J', 'K', 'L', ':', '@', '|', + 0, '~', 'Z', 'X', 'C', 'V', 'B', 'N', 'M', '<', '>', '?', 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 +}; + +/* Convert a string to a number */ +static int +number(char *str) +{ + int num = 0, col = 1, len; + for (len = 0; str[len] >= '0' && str[len] <= '9'; len++); + while (len--) { + num += (str[len] - '0') * col; + col *= 10; + } + return num; +} + +/* Put a pixel on the screen */ +static void +putpixel(int x, int y, uint32_t colour) +{ + /* This splits the framebuffer into bytes to be BPP agnostic */ + uint8_t *screen = (uint8_t *) vgaLfb; + unsigned where = x*(vgaBpp/8) + y*vgaWidth*(vgaBpp/8); + screen[where + 0] = (colour >> 0) & 0xFF; /* BLUE */ + screen[where + 1] = (colour >> 8) & 0xFF; /* GREEN */ + screen[where + 2] = (colour >> 16) & 0xFF; /* RED */ +} + +/* Draw a character to the framebuffer using the font */ +static void +draw_char(unsigned char c, int x, int y, uint32_t fgcolour, uint32_t bgcolour) +{ + int cx, cy; + unsigned char *glyph = font + ((int) c * 16); + for (cy = 0; cy < 16; cy++) { + for (cx = 0; cx < 8; cx++) { + putpixel(x + 7 - cx, y + cy, + (glyph[cy] & (1 << cx)) ? fgcolour : bgcolour); + } + } +} + +/* Set the ANSI attribute */ +static void +set_ansi_attribute(int mode, int foreground, int background) +{ + char bold; + + switch (mode) { + case 0: /* RESET */ + ttyAttr = 0x07; + return; + case 1: + bold = 1; + break; + } + + switch (foreground) { + case 0: /* DEFAULT */ + ttyAttr = (ttyAttr & 0xF0) + 7 + (bold ? 8 : 0); + break; + case 30: /* BLACK */ + ttyAttr = (ttyAttr & 0xF0) + 0; + break; + case 31: /* RED */ + ttyAttr = (ttyAttr & 0xF0) + 4 + (bold ? 8 : 0); + break; + case 32: /* GREEN */ + ttyAttr = (ttyAttr & 0xF0) + 2 + (bold ? 8 : 0); + break; + case 33: /* YELLOW */ + ttyAttr = (ttyAttr & 0xF0) + 14; + break; + case 34: /* BLUE */ + ttyAttr = (ttyAttr & 0xF0) + 1 + (bold ? 8 : 0); + break; + case 35: /* MAGENTA */ + ttyAttr = (ttyAttr & 0xF0) + 5 + (bold ? 8 : 0); + break; + case 36: /* CYAN */ + ttyAttr = (ttyAttr & 0xF0) + 3 + (bold ? 8 : 0); + break; + } + +} + +/* Parse ANSI escape codes */ +static size_t +ansi_escape(char *buf) +{ + int len; + char *end; + for (len = 0; buf[len] < 'A' || buf[len] > 'z'; len++); + end = buf + len + 1; + switch (buf[len]) { + case 'H': + /* Set the cursor position */ + ttyX = 0; + ttyY = 0; + break; + case 'J': + /* 2J clears screen */ + int jmode = 0; + jmode = number(buf); + if (jmode == 2) { + if (ttyMode == 0) + memset((void *) 0xB8000, '\0', ttyW * ttyH * 2); + else + memset((void *) vgaLfb, '\0', + vgaWidth * vgaHeight * (vgaBpp / 8)); + } + break; + case 'm': + /* Set attribute */ + int mode = 0, foreground = 0, background = 0; + mode = number(buf); + while (*buf >= '0' && *buf <= '9') buf++; + buf++; + if (buf == end) + goto set; + foreground = number(buf); + while (*buf >= '0' && *buf <= '9') buf++; + buf++; + if (buf == end) + goto set; + background = number(buf); +set: + set_ansi_attribute(mode, foreground, background); + break; + } + + return len + 1; +} + +/* Print a character to the screen */ +void +print_char(char c) +{ + char *screen = (char *) 0xB8000; + + if (ttyMode == 0) + screen[(((ttyY * ttyW) + ttyX) * 2) + 1] = ttyAttr; + else + draw_char(' ', ttyX*8, ttyY*16, 0xFFFFFF, 0x000000); + + /* Characters */ + if (!(tty.lflag & ECHO) && c != '\n') + goto curctl; + switch (c) { + case '\r': + ttyX = 0; + break; + case '\n': + ttyX = 0; + ttyY++; + break; + case '\b': + ttyX--; + if (ttyMode == 0) + screen[((ttyY * ttyW) + ttyX) * 2] = ' '; + else + draw_char(' ', ttyX*8, ttyY*16, colours[ttyAttr & 0xF], + colours[ttyAttr >> 4]); + break; + case '\t': + ttyX += 8 - (ttyX % 8); + break; + default: + if (ttyMode == 0) + screen[((ttyY * ttyW) + ttyX) * 2] = c; + else + draw_char(c, ttyX*8, ttyY*16, colours[ttyAttr & 0xF], + colours[ttyAttr >> 4]); + ttyX++; + } + + /* Control cursor */ +curctl: + if (ttyX >= ttyW) { + ttyX = 0; + ttyY++; + } + if (ttyX < 0) { + ttyX = ttyW - 1; + ttyY--; + } + if (ttyY >= ttyH) { + if (ttyMode == 0) { + memcpy(screen, screen + (ttyW*2), ttyW * (ttyH-1) * 2); + memset(screen + (ttyW * 2 * (ttyH-1)), 0, ttyW * 2); + } else { + memcpy((void *) vgaLfb, (void *) vgaLfb + (vgaWidth*(vgaBpp/8)*16), + vgaWidth*(vgaBpp/8)*(vgaHeight-16)); + memset((void *) vgaLfb + (vgaWidth*(vgaBpp/8)*(vgaHeight-16)), + '\0', vgaWidth*(vgaBpp/8)*16); + } + ttyY--; + } + if (ttyY < 0) + ttyY++; + + if (ttyMode == 0) + screen[(((ttyY * ttyW) + ttyX) * 2) + 1] = + ((ttyAttr & 0x0F) << 4) + ((ttyAttr >> 4) & 0x0F); + else + draw_char(' ', ttyX*8, ttyY*16, 0x000000, 0x888888); +} + +/* Handle the keyboard interrupt */ +void +keyboard_handler(InterruptFrame *frame) +{ + char c; + unsigned char key; + int i; + for (i = 0; i < 1000; i++) { + if ((inb(0x64) & 1) == 0) + continue; + key = inb(0x60); + break; + } + if (key == 0x1D) + ctrl = 128; + if (key == 0x9D) + ctrl = 0; + if (key == 0x2A || key == 0x36) + shift = 128; + if (key == 0xAA || key == 0xB6) + shift = 0; + + if (key >= 128) + return; + if (shift) + c = skbmap[key]; + else + c = kbmap[key]; + if (!c) + return; + + if (c == '\b' && lineBufLen == 0) + return; + if (c == '\b') + lineBuf[lineBufLen--] = '\0'; + else + lineBuf[lineBufLen++] = c; + print_char(c); + if (c == '\n') { + memcpy(line, lineBuf, lineBufLen); + memset(lineBuf, 0, lineBufLen); + lineLen = lineBufLen; + lineBufLen = 0; + for (Task *tmp = ttyWait.start; tmp; tmp = tmp->next) + unblock_task(pop_from_queue(&ttyWait)); + } +} + +/* Initialise the TTY */ +void +init_tty(void) +{ + register_driver(&ttyDriver); + mknod("/dev/tty", S_IFCHR | 0666, MKDEV(ttyDriver.major, 0)); + + tty.lflag = ICANON | ECHO; + + int fd = open("/dev/fb", O_RDWR); + if (fd < 0) { + ttyMode = 0; + int x, y; + uint16_t *screen = (uint16_t *) 0xB8000; + for (y = 0; y < 25; y++) + for (x = 0; x < 80; x++) + screen[(y * 80) + x] = 0x0000; + } else { + FBVarInfo vinfo; + FBFixInfo finfo; + ioctl(fd, FBIOGET_VSCREENINFO, &vinfo); + ioctl(fd, FBIOGET_FSCREENINFO, &finfo); + close(fd); + vgaWidth = vinfo.xres; + vgaHeight = vinfo.yres; + vgaBpp = vinfo.bpp; + vgaLfb = finfo.fbmem; + + ttyMode = 1; + ttyW = vgaWidth/8; + ttyH = vgaHeight/16; + } + + lineBuf = kmalloc(4096); + line = kmalloc(4096); + register_interrupt(1, keyboard_handler); +} + +/* Read from the TTY */ +size_t +tty_read(File *file, char *buf, size_t size, off_t offset) +{ + if (!lineLen) { + add_to_queue(&ttyWait, current); + block_task(WAITING_FOR_READ); + } + size_t count = (size < lineLen) ? size : lineLen; + memcpy(buf, line, count); + if (size < lineLen) { + memcpy(line, line + size, lineLen - size); + lineLen -= size; + } else { + memset(line, 0, lineLen); + lineLen = 0; + } + return count; +} + +/* Write to the TTY */ +size_t +tty_write(File *file, char *buf, size_t size, off_t offset) +{ + size_t skip, count = 0; + while (size--) { + if (buf[0] == '\033' && buf[1] == '[') { + skip = ansi_escape(buf + 2); + buf += skip + 2; + size -= skip + 1; + continue; + } + print_char(*buf++); + count++; + } + return count; +} + +/* Open the TTY */ +int +tty_open(File *file) +{ + return 0; +} diff --git a/drivers/tty/tty_ioctl.c b/drivers/tty/tty_ioctl.c new file mode 100644 index 0000000..5889c66 --- /dev/null +++ b/drivers/tty/tty_ioctl.c @@ -0,0 +1,39 @@ +/* + * This file implements the TTY ioctl() backend. It stores many of the settings + * which are used throughout the rest of the TTY driver. + */ + +#include <stdint.h> +#include <stddef.h> +#include <string.h> +#include <termios.h> +#include "../../vfs/vfs.h" + +extern Termios tty; + +extern int ttyW, ttyH; +extern int vgaWidth, vgaHeight; + +int +tty_ioctl(File *file, unsigned long request, uintptr_t argp) +{ + Termios *ts; + Winsize *ws; + switch (request) { + case TCGETS: + ts = (void *) argp; + memcpy(ts, &tty, sizeof(Termios)); + return 0; + case TCSETS: + ts = (void *) argp; + memcpy(&tty, ts, sizeof(Termios)); + return 0; + case TCGWINSZ: + ws = (void *) argp; + ws->rows = ttyH; + ws->cols = ttyW; + ws->xres = vgaWidth; + ws->yres = vgaHeight; + return 0; + } +} diff --git a/drivers/vga/bga.c b/drivers/vga/bga.c new file mode 100644 index 0000000..aff91aa --- /dev/null +++ b/drivers/vga/bga.c @@ -0,0 +1,131 @@ +/* + * This file implements the driver for the Bochs Graphics Adapter video card. + * It is a simple card available in virtual machines. It creates a framebuffer + * device node, and handles the reading/writing to it, and also mapping the + * framebuffer into memory. + */ + +#include <stdint.h> +#include <string.h> +#include <sys/fb.h> +#include "../drivers.h" +#include "../pci.h" +#include "../../mem/paging.h" +#include "../../vfs/vfs.h" +#include "../../io.h" + +size_t bga_write(File *file, char *buf, size_t size, off_t offset); +int bga_ioctl(File *file, unsigned long request, uintptr_t argp); + +FileOps bgaFileOps = { + .write = bga_write, + .ioctl = bga_ioctl, +}; + +Driver bgaDriver = { + .major = 3, + .ops = &bgaFileOps, + .next = NULL, +}; + +static uint32_t bgaWidth, bgaHeight, bgaBpp; +static uintptr_t lfb; + +enum BGAIndex { + BGA_INDEX_ID, + BGA_INDEX_XRES, + BGA_INDEX_YRES, + BGA_INDEX_BPP, + BGA_INDEX_ENABLE, + BGA_INDEX_BANK, + BGA_INDEX_VIRT_WIDTH, + BGA_INDEX_VIRT_HEIGHT, + BGA_INDEX_XOFF, + BGA_INDEX_YOFF, +}; + +/* Write a BGA register */ +void +bga_write_register(uint16_t index, uint16_t data) +{ + outw(0x1CE, index); + outw(0x1CF, data); +} + +/* Set the video mode */ +void +bga_set_mode(uint32_t width, uint32_t height, uint32_t bpp) +{ + bgaWidth = width; + bgaHeight = height; + bgaBpp = bpp; + bga_write_register(BGA_INDEX_ENABLE, 0); + bga_write_register(BGA_INDEX_XRES, width); + bga_write_register(BGA_INDEX_YRES, height); + bga_write_register(BGA_INDEX_BPP, bpp); + bga_write_register(BGA_INDEX_ENABLE, 1 | 0x40); + /* 0x40 for framebuffer */ +} + +/* Initialise the BGA card */ +void +bga_init(uint8_t bus, uint8_t slot, uint8_t func) +{ + register_driver(&bgaDriver); + + const int width = 1280; + const int height = 720; + const int bpp = 32; + bga_set_mode(width, height, bpp); + lfb = pci_read_dword(bus, slot, func, 0x10) & 0xFFFFFFF0; + for (uintptr_t i = 0; i < width*height*(bpp/8); i += 0x1000) + *get_page((void *) lfb + i) = (0xFD000000 + i) | PTE_PRESENT + | PTE_WRITE | PTE_GLOBAL; + /* use the MMAP method to map pages of it into a page dir */ + mknod("/dev/fb", S_IFCHR | 0600, MKDEV(bgaDriver.major, 0)); +} + +/* Write to the BGA framebuffer */ +size_t +bga_write(File *file, char *buf, size_t size, off_t offset) +{ + size_t max, count = 0; + page_t oldpg; + while (size) { + max = (size < 0x1000) ? size : 0x1000; + acquire(&quickPageLock); + oldpg = quick_page(lfb + PG_ADDR(offset) + count); + memcpy(QUICK_PAGE, buf + count, max); + quick_page(oldpg); + release(&quickPageLock); + count += max; + size -= max; + } + return count; +} + +/* Control the BGA framebuffer/device */ +int +bga_ioctl(File *file, unsigned long request, uintptr_t argp) +{ + FBVarInfo *vinfo; + FBFixInfo *finfo; + + switch (request) { + case FBIOGET_VSCREENINFO: + vinfo = (void *) argp; + vinfo->xres = bgaWidth; + vinfo->yres = bgaHeight; + vinfo->bpp = bgaBpp; + return 0; + case FBIOPUT_VSCREENINFO: + vinfo = (void *) argp; + bga_set_mode(vinfo->xres, vinfo->yres, vinfo->bpp); + return 0; + case FBIOGET_FSCREENINFO: + finfo = (void *) argp; + finfo->fbmem = 0xFD000000; // lfb; + finfo->fbmemLen = bgaWidth*bgaHeight*(bgaBpp/8); + return 0; + } +}