chore: reorganize file directories
We have reorganized all the file directories that previously looked ugly as hell (cough cough arch/x86_64 cough) Now it looks much cleaner Signed-off-by: kaguya <vpshinomiya@protonmail.com>
This commit is contained in:
@@ -0,0 +1,158 @@
|
||||
#include "ata.h"
|
||||
#include "arch/x86_64/cpu/io.h"
|
||||
#include "libk/stdio.h"
|
||||
#include <stdbool.h>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#define ATA_PRIMARY_DATA 0x1F0
|
||||
#define ATA_PRIMARY_ERROR 0x1F1
|
||||
#define ATA_PRIMARY_SECCOUNT 0x1F2
|
||||
#define ATA_PRIMARY_LBALOW 0x1F3
|
||||
#define ATA_PRIMARY_LBAMID 0x1F4
|
||||
#define ATA_PRIMARY_LBAHIGH 0x1F5
|
||||
#define ATA_PRIMARY_DRIVE 0x1F6
|
||||
#define ATA_PRIMARY_STATUS 0x1F7
|
||||
#define ATA_PRIMARY_COMMAND 0x1F7
|
||||
|
||||
#define ATA_STATUS_BSY 0x80
|
||||
#define ATA_STATUS_DRDY 0x40
|
||||
#define ATA_STATUS_DRQ 0x08
|
||||
#define ATA_STATUS_ERR 0x01
|
||||
|
||||
#define ATA_CMD_IDENTIFY 0xEC
|
||||
#define ATA_CMD_READ_SECTORS 0x20
|
||||
|
||||
static void ata_wait_ready(void)
|
||||
{
|
||||
while (x86_64_inb(ATA_PRIMARY_STATUS) & ATA_STATUS_BSY) {}
|
||||
while (!(x86_64_inb(ATA_PRIMARY_STATUS) & ATA_STATUS_DRDY)) {}
|
||||
}
|
||||
|
||||
static bool ata_poll(void)
|
||||
{
|
||||
// 400 ns delay
|
||||
for (int i = 0; i < 4; i++)
|
||||
x86_64_inb(ATA_PRIMARY_STATUS);
|
||||
|
||||
uint8_t status;
|
||||
|
||||
while ((status = x86_64_inb(ATA_PRIMARY_STATUS)) & ATA_STATUS_BSY);
|
||||
if (status & ATA_STATUS_ERR) return false;
|
||||
|
||||
while (!(status & ATA_STATUS_DRQ)) {
|
||||
status = x86_64_inb(ATA_PRIMARY_STATUS);
|
||||
if (status & ATA_STATUS_ERR) return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void ata_init(void)
|
||||
{
|
||||
x86_64_outb(0x3F6, 0x02); // disable interrupts on primary controller
|
||||
ata_wait_ready();
|
||||
x86_64_outb(ATA_PRIMARY_DRIVE, 0xA0); // select master
|
||||
ata_wait_ready();
|
||||
printf("ATA: Primary master (hda) initialized\n");
|
||||
}
|
||||
|
||||
void ata_identify(void)
|
||||
{
|
||||
static uint16_t buffer[256];
|
||||
|
||||
x86_64_outb(ATA_PRIMARY_DRIVE, 0xA0);
|
||||
x86_64_outb(ATA_PRIMARY_SECCOUNT, 0);
|
||||
x86_64_outb(ATA_PRIMARY_LBALOW, 0);
|
||||
x86_64_outb(ATA_PRIMARY_LBAMID, 0);
|
||||
x86_64_outb(ATA_PRIMARY_LBAHIGH, 0);
|
||||
x86_64_outb(ATA_PRIMARY_COMMAND, ATA_CMD_IDENTIFY);
|
||||
|
||||
if (x86_64_inb(ATA_PRIMARY_STATUS) == 0) {
|
||||
printf("ATA: No primary master drive detected\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!ata_poll()) {
|
||||
printf("ATA poll failed at ATA_IDENTIFY\n");
|
||||
}
|
||||
|
||||
if (x86_64_inb(ATA_PRIMARY_STATUS) & ATA_STATUS_ERR) {
|
||||
printf("ATA: Identify error\n");
|
||||
return;
|
||||
}
|
||||
|
||||
x86_64_insw(ATA_PRIMARY_DATA, buffer, 256);
|
||||
|
||||
printf("ATA: Disk model: ");
|
||||
for (int i = 27; i <= 46; i++) {
|
||||
uint16_t w = buffer[i];
|
||||
char high = w >> 8;
|
||||
char low = w & 0xFF;
|
||||
printf("%c%c", high, low); // swap bytes
|
||||
}
|
||||
printf("\n");
|
||||
printf("ATA: Total sectors: %lu\n", (uint64_t)buffer[60] | ((uint64_t)buffer[61] << 16));
|
||||
}
|
||||
|
||||
bool ata_read_sectors(uint64_t lba, uint8_t sector_count, void* buffer)
|
||||
{
|
||||
if (sector_count == 0) return true;
|
||||
|
||||
ata_wait_ready();
|
||||
|
||||
x86_64_outb(ATA_PRIMARY_DRIVE, 0xE0 | ((lba >> 24) & 0x0F));
|
||||
x86_64_outb(ATA_PRIMARY_SECCOUNT, sector_count);
|
||||
x86_64_outb(ATA_PRIMARY_LBALOW, (uint8_t)lba);
|
||||
x86_64_outb(ATA_PRIMARY_LBAMID, (uint8_t)(lba >> 8));
|
||||
x86_64_outb(ATA_PRIMARY_LBAHIGH, (uint8_t)(lba >> 16));
|
||||
|
||||
x86_64_outb(ATA_PRIMARY_COMMAND, ATA_CMD_READ_SECTORS);
|
||||
|
||||
uint16_t* buf = buffer;
|
||||
for (uint8_t i = 0; i < sector_count; i++) {
|
||||
if (!ata_poll()) {
|
||||
printf("ATA poll failed at ATA_read_sectors\n");
|
||||
}
|
||||
|
||||
if (x86_64_inb(ATA_PRIMARY_STATUS) & ATA_STATUS_ERR) {
|
||||
printf("ATA read error at LBA %lu\n", lba + i);
|
||||
return false;
|
||||
}
|
||||
|
||||
x86_64_insw(ATA_PRIMARY_DATA, buf, 256); // 512 bytes
|
||||
buf += 256;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ata_write_sectors(uint64_t lba, uint8_t sector_count, void* buffer) {
|
||||
if (sector_count == 0) return true;
|
||||
|
||||
|
||||
|
||||
ata_wait_ready();
|
||||
x86_64_outb(ATA_PRIMARY_DRIVE, 0xE0 | ((lba >> 24) & 0x0F));
|
||||
x86_64_outb(ATA_PRIMARY_SECCOUNT, sector_count);
|
||||
x86_64_outb(ATA_PRIMARY_LBALOW, (uint8_t)lba);
|
||||
x86_64_outb(ATA_PRIMARY_LBAMID, (uint8_t)(lba >> 8));
|
||||
x86_64_outb(ATA_PRIMARY_LBAHIGH, (uint8_t)(lba >> 16));
|
||||
x86_64_outb(ATA_PRIMARY_COMMAND, 0x30); // write sectors
|
||||
|
||||
uint16_t* buf = buffer;
|
||||
for (uint8_t i = 0; i < sector_count; i++) {
|
||||
if (!ata_poll()) {
|
||||
|
||||
return false;
|
||||
}
|
||||
x86_64_outsw(ATA_PRIMARY_DATA, buf, 256);
|
||||
buf += 256;
|
||||
}
|
||||
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
void ata_init(void);
|
||||
void ata_identify(void);
|
||||
|
||||
// Read `sector_count` 512-byte sectors starting at LBA `lba` into `buffer`.
|
||||
// Buffer must be large enough (sector_count * 512).
|
||||
bool ata_read_sectors(uint64_t lba, uint8_t sector_count, void* buffer);
|
||||
|
||||
bool ata_write_sectors(uint64_t lba, uint8_t sector_count, void* buffer);
|
||||
@@ -0,0 +1,137 @@
|
||||
#include "pci.h"
|
||||
#include "arch/x86_64/cpu/io.h"
|
||||
#include "libk/stdio.h"
|
||||
|
||||
#define PCI_CFG_ADDR 0x0CF8
|
||||
#define PCI_CFG_DATA 0x0CFC
|
||||
|
||||
static uint32_t pci_pack_addr(pci_address_t addr, uint16_t offset)
|
||||
{
|
||||
return (1u << 31) |
|
||||
((uint32_t)addr.bus << 16) |
|
||||
((uint32_t)addr.device << 11) |
|
||||
((uint32_t)addr.function << 8) |
|
||||
(offset & 0xFCu);
|
||||
}
|
||||
|
||||
uint8_t pci_read8(pci_address_t addr, uint16_t offset)
|
||||
{
|
||||
x86_64_outl(PCI_CFG_ADDR, pci_pack_addr(addr, offset));
|
||||
return (uint8_t)(x86_64_inl(PCI_CFG_DATA) >> ((offset & 3) * 8));
|
||||
}
|
||||
|
||||
uint16_t pci_read16(pci_address_t addr, uint16_t offset)
|
||||
{
|
||||
x86_64_outl(PCI_CFG_ADDR, pci_pack_addr(addr, offset));
|
||||
return (uint16_t)(x86_64_inl(PCI_CFG_DATA) >> ((offset & 2) * 8));
|
||||
}
|
||||
|
||||
uint32_t pci_read32(pci_address_t addr, uint16_t offset)
|
||||
{
|
||||
x86_64_outl(PCI_CFG_ADDR, pci_pack_addr(addr, offset));
|
||||
return x86_64_inl(PCI_CFG_DATA);
|
||||
}
|
||||
|
||||
void pci_write8(pci_address_t addr, uint16_t offset, uint8_t val)
|
||||
{
|
||||
uint32_t tmp = pci_read32(addr, offset & ~3u);
|
||||
uint8_t shift = (offset & 3) * 8;
|
||||
tmp = (tmp & ~(0xFFu << shift)) | ((uint32_t)val << shift);
|
||||
x86_64_outl(PCI_CFG_ADDR, pci_pack_addr(addr, offset));
|
||||
x86_64_outl(PCI_CFG_DATA, tmp);
|
||||
}
|
||||
|
||||
void pci_write16(pci_address_t addr, uint16_t offset, uint16_t val)
|
||||
{
|
||||
uint32_t tmp = pci_read32(addr, offset & ~3u);
|
||||
uint8_t shift = (offset & 2) * 8;
|
||||
tmp = (tmp & ~(0xFFFFu << shift)) | ((uint32_t)val << shift);
|
||||
x86_64_outl(PCI_CFG_ADDR, pci_pack_addr(addr, offset));
|
||||
x86_64_outl(PCI_CFG_DATA, tmp);
|
||||
}
|
||||
|
||||
void pci_write32(pci_address_t addr, uint16_t offset, uint32_t val)
|
||||
{
|
||||
x86_64_outl(PCI_CFG_ADDR, pci_pack_addr(addr, offset));
|
||||
x86_64_outl(PCI_CFG_DATA, val);
|
||||
}
|
||||
|
||||
static void pci_read_bars(pci_device_t* dev)
|
||||
{
|
||||
for (int i = 0; i < 6; i++) {
|
||||
uint16_t off = 0x10 + i * 4;
|
||||
dev->bar[i] = pci_read32(dev->addr, off);
|
||||
// If it's a 64-bit BAR we skip the next one (simple version)
|
||||
if ((dev->bar[i] & 0x7) == 0x4)
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
void pci_init(void)
|
||||
{
|
||||
printf("[PCI] Scanning bus 0...\n");
|
||||
pci_print_all();
|
||||
}
|
||||
|
||||
void pci_print_all(void)
|
||||
{
|
||||
for (uint8_t bus = 0; bus < 1; bus++) { // start with bus 0 only
|
||||
for (uint8_t dev = 0; dev < 32; dev++) {
|
||||
for (uint8_t func = 0; func < 8; func++) {
|
||||
pci_address_t addr = {bus, dev, func};
|
||||
|
||||
uint16_t vendor = pci_read16(addr, 0x00);
|
||||
if (vendor == 0xFFFF) {
|
||||
if (func == 0) break; // no device
|
||||
continue;
|
||||
}
|
||||
|
||||
uint16_t device_id = pci_read16(addr, 0x02);
|
||||
uint16_t class_sub = pci_read16(addr, 0x0A);
|
||||
uint8_t prog_if = pci_read8 (addr, 0x09);
|
||||
uint8_t revision = pci_read8 (addr, 0x08);
|
||||
|
||||
pci_device_t d = {
|
||||
.addr = addr,
|
||||
.vendor_id = vendor,
|
||||
.device_id = device_id,
|
||||
.class_code = class_sub,
|
||||
.prog_if = prog_if,
|
||||
.revision = revision,
|
||||
};
|
||||
pci_read_bars(&d);
|
||||
|
||||
printf("[PCI] %02x:%02x.%x %04x:%04x class %04x rev %02x\n",
|
||||
bus, dev, func, vendor, device_id, class_sub, revision);
|
||||
|
||||
if (func == 0 && (pci_read8(addr, 0x0E) & 0x80) == 0)
|
||||
break; // not multifunction
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool pci_find_hda(pci_device_t* out_dev)
|
||||
{
|
||||
// Same scan as above, but stop at first HDA device
|
||||
for (uint8_t bus = 0; bus < 256; bus++) {
|
||||
for (uint8_t dev = 0; dev < 32; dev++) {
|
||||
for (uint8_t func = 0; func < 8; func++) {
|
||||
pci_address_t addr = {bus, dev, func};
|
||||
uint16_t vendor = pci_read16(addr, 0x00);
|
||||
if (vendor == 0xFFFF) continue;
|
||||
|
||||
uint16_t class_sub = pci_read16(addr, 0x0A);
|
||||
if (((class_sub >> 8) == PCI_CLASS_AUDIO) && ((class_sub & 0xFF) == PCI_SUBCLASS_HDA)) {
|
||||
out_dev->addr = addr;
|
||||
out_dev->vendor_id = vendor;
|
||||
out_dev->device_id = pci_read16(addr, 0x02);
|
||||
out_dev->class_code = class_sub;
|
||||
pci_read_bars(out_dev);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
#pragma once
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
typedef struct {
|
||||
uint8_t bus;
|
||||
uint8_t device;
|
||||
uint8_t function;
|
||||
} pci_address_t;
|
||||
|
||||
typedef struct {
|
||||
pci_address_t addr;
|
||||
uint16_t vendor_id;
|
||||
uint16_t device_id;
|
||||
uint16_t class_code; // (class << 8) | subclass
|
||||
uint8_t prog_if;
|
||||
uint8_t revision;
|
||||
uint32_t bar[6];
|
||||
bool is_multifunction;
|
||||
} pci_device_t;
|
||||
|
||||
#define PCI_CLASS_AUDIO 0x04
|
||||
#define PCI_SUBCLASS_HDA 0x03
|
||||
|
||||
// Read/write config space
|
||||
uint8_t pci_read8 (pci_address_t addr, uint16_t offset);
|
||||
uint16_t pci_read16(pci_address_t addr, uint16_t offset);
|
||||
uint32_t pci_read32(pci_address_t addr, uint16_t offset);
|
||||
|
||||
void pci_write8 (pci_address_t addr, uint16_t offset, uint8_t val);
|
||||
void pci_write16(pci_address_t addr, uint16_t offset, uint16_t val);
|
||||
void pci_write32(pci_address_t addr, uint16_t offset, uint32_t val);
|
||||
|
||||
// Scan and print all PCI devices
|
||||
void pci_init(void);
|
||||
void pci_print_all(void);
|
||||
|
||||
// Find first HDA controller (returns true if found)
|
||||
bool pci_find_hda(pci_device_t* out_dev);
|
||||
Reference in New Issue
Block a user