Frist Sata push
This commit is contained in:
parent
5c90823d61
commit
ec4c75872c
5 changed files with 422 additions and 478 deletions
1
Makefile
1
Makefile
|
|
@ -11,6 +11,7 @@ KERNEL_SOURCES_x86_64 := \
|
|||
src/x86_64/uart.c \
|
||||
src/x86_64/mem.c \
|
||||
src/x86_64/asm.c \
|
||||
src/x86_64/sata.c \
|
||||
# end of x86_64 specific kernel sources list
|
||||
|
||||
# Architecture-agnostic kernel sources.
|
||||
|
|
|
|||
|
|
@ -0,0 +1,83 @@
|
|||
#ifndef SATA_H
|
||||
#define SATA_H
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <sys/io.h>
|
||||
|
||||
#define HBA_GHC_RESET (1 << 0)
|
||||
#define HBA_GHC_AE (1 << 31)
|
||||
|
||||
typedef volatile struct __attribute__((packed)) SATA_DEVICE {
|
||||
uint16_t vendor_id;
|
||||
uint16_t device_id;
|
||||
uint16_t command;
|
||||
uint16_t status;
|
||||
uint8_t revision_id;
|
||||
uint8_t class_code[3];
|
||||
uint8_t cache_line_size;
|
||||
uint8_t master_latency_timer;
|
||||
uint8_t header_type;
|
||||
uint8_t bist;
|
||||
uint32_t bars[5];
|
||||
uint32_t abar;
|
||||
uint32_t reserved0;
|
||||
uint16_t subsystem_vendor_id;
|
||||
uint16_t subsystem_id;
|
||||
uint32_t expansion_rom_base;
|
||||
uint8_t cap_ptr;
|
||||
uint8_t reserved1[7];
|
||||
uint8_t interrupt_line;
|
||||
uint8_t interrupt_pin;
|
||||
uint8_t min_grant;
|
||||
uint8_t max_latency;
|
||||
} SATA_DEVICE;
|
||||
|
||||
typedef volatile struct __attribute__((packed)) HBA_PORT {
|
||||
uint32_t clb;
|
||||
uint32_t clbu;
|
||||
uint32_t fb;
|
||||
uint32_t fbu;
|
||||
uint32_t is;
|
||||
uint32_t ie;
|
||||
uint32_t cmd;
|
||||
uint32_t reserved0;
|
||||
uint32_t tfd;
|
||||
uint32_t sig;
|
||||
uint32_t ssts;
|
||||
uint32_t sctl;
|
||||
uint32_t serr;
|
||||
uint32_t sact;
|
||||
uint32_t ci;
|
||||
uint32_t sntf;
|
||||
uint32_t fbs;
|
||||
uint8_t reserved1[0x80 - 0x44];
|
||||
} HBA_PORT;
|
||||
|
||||
typedef volatile struct __attribute__((packed)) HBA_MEM {
|
||||
uint32_t cap;
|
||||
uint32_t ghc;
|
||||
uint32_t is;
|
||||
uint32_t pi;
|
||||
uint32_t vs;
|
||||
uint32_t ccc_ctl;
|
||||
uint32_t ccc_ports;
|
||||
uint32_t em_loc;
|
||||
uint32_t em_ctl;
|
||||
uint32_t cap2;
|
||||
uint32_t bohc;
|
||||
uint8_t reserved0[0x60 - 0x2C];
|
||||
uint8_t reserved1[0xA0 - 0x60];
|
||||
uint8_t vendor[0x100 - 0xA0];
|
||||
HBA_PORT ports[32];
|
||||
} HBA_MEM;
|
||||
|
||||
/* Function prototypes */
|
||||
uint32_t pci_read(uint8_t bus, uint8_t device, uint8_t function,
|
||||
uint8_t offset);
|
||||
int check_PCI_devices(SATA_DEVICE *list_of_devices, int range);
|
||||
void *map_physical_region(uintptr_t phys_addr, size_t size);
|
||||
int reset_hba(volatile HBA_MEM *hba);
|
||||
void check_number_off_active_ports(volatile HBA_MEM *hba);
|
||||
|
||||
#endif // SATA_//H
|
||||
168
src/kernel.c
168
src/kernel.c
|
|
@ -29,120 +29,124 @@
|
|||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "x86_64/mem.h"
|
||||
#include "x86_64/asm.h"
|
||||
#include "bootboot.h"
|
||||
#include "pci.h"
|
||||
#include "std.h"
|
||||
#include "tar.h"
|
||||
#include "x86_64/asm.h"
|
||||
#include "x86_64/mem.h"
|
||||
#include "x86_64/sata.h"
|
||||
|
||||
/* imported virtual addresses, see linker script */
|
||||
extern BOOTBOOT bootboot; // see bootboot.h
|
||||
extern unsigned char environment[4096]; // configuration, UTF-8 text key=value pairs
|
||||
extern uint8_t fb; // linear framebuffer mapped
|
||||
extern unsigned char
|
||||
environment[4096]; // configuration, UTF-8 text key=value pairs
|
||||
extern uint8_t fb; // linear framebuffer mapped
|
||||
|
||||
void print_virtio_blk_bars() {
|
||||
uint16_t bdf;
|
||||
if (pci_search(0x1AF4, 0x1001, &bdf) && pci_search(0x1AF4, 0x1042, &bdf)) {
|
||||
PANIC("couldn't find virtio_blk device!");
|
||||
}
|
||||
puts("found virtio_blk device at bdf ");
|
||||
putu16x(bdf);
|
||||
printf(".\n");
|
||||
// read BARs
|
||||
for (int i = 0; i < 6; i++) {
|
||||
struct pci_bar_desc desc = pci_bar_desc_read(bdf, i);
|
||||
pci_bar_desc_print(&desc);
|
||||
}
|
||||
uint16_t bdf;
|
||||
if (pci_search(0x1AF4, 0x1001, &bdf) && pci_search(0x1AF4, 0x1042, &bdf)) {
|
||||
PANIC("couldn't find virtio_blk device!");
|
||||
}
|
||||
puts("found virtio_blk device at bdf ");
|
||||
putu16x(bdf);
|
||||
printf(".\n");
|
||||
// read BARs
|
||||
for (int i = 0; i < 6; i++) {
|
||||
struct pci_bar_desc desc = pci_bar_desc_read(bdf, i);
|
||||
pci_bar_desc_print(&desc);
|
||||
}
|
||||
}
|
||||
|
||||
void check_initrd() {
|
||||
putln();
|
||||
uint64_t printed_in_line = 0;
|
||||
for (uint64_t off = 0; off < bootboot.initrd_size; off++) {
|
||||
uint8_t byte = ((uint8_t*)bootboot.initrd_ptr)[off];
|
||||
putln();
|
||||
uint64_t printed_in_line = 0;
|
||||
for (uint64_t off = 0; off < bootboot.initrd_size; off++) {
|
||||
uint8_t byte = ((uint8_t *)bootboot.initrd_ptr)[off];
|
||||
|
||||
putu8x(byte);
|
||||
putc(' ');
|
||||
putu8x(byte);
|
||||
putc(' ');
|
||||
|
||||
if (++printed_in_line % 32 == 0) {
|
||||
printed_in_line = 0;
|
||||
putln();
|
||||
}
|
||||
if (++printed_in_line % 32 == 0) {
|
||||
printed_in_line = 0;
|
||||
putln();
|
||||
}
|
||||
putln();
|
||||
}
|
||||
putln();
|
||||
}
|
||||
|
||||
/******************************************
|
||||
SATA_DEVICE list_of_devices[100];
|
||||
|
||||
/*:*****************************************
|
||||
* Entry point, called by BOOTBOOT Loader *
|
||||
******************************************/
|
||||
void _start() {
|
||||
/*** NOTE: this code runs on all cores in parallel ***/
|
||||
int x, y, s = bootboot.fb_scanline, w = bootboot.fb_width, h = bootboot.fb_height;
|
||||
|
||||
if (s) {
|
||||
// cross-hair to see screen dimension detected correctly
|
||||
for (y = 0; y < h; y++) {
|
||||
*((uint32_t *)(&fb + s * y + (w * 2))) = 0x000FFFFF;
|
||||
}
|
||||
for (x = 0; x < w; x++) {
|
||||
*((uint32_t *)(&fb + s * (h / 2) + x * 4)) = 0x00FFFFFF;
|
||||
}
|
||||
/*** NOTE: this code runs on all cores in parallel ***/
|
||||
int x, y, s = bootboot.fb_scanline, w = bootboot.fb_width,
|
||||
h = bootboot.fb_height;
|
||||
|
||||
// red, green, blue boxes in order
|
||||
for (y = 0; y < 20; y++) {
|
||||
for (x = 0; x < 20; x++) {
|
||||
*((uint32_t *)(&fb + s * (y + 20) + (x + 20) * 4)) = 0x00FF0000;
|
||||
}
|
||||
}
|
||||
for (y = 0; y < 20; y++) {
|
||||
for (x = 0; x < 20; x++) {
|
||||
*((uint32_t *)(&fb + s * (y + 20) + (x + 50) * 4)) = 0x0000FF00;
|
||||
}
|
||||
}
|
||||
for (y = 0; y < 20; y++) {
|
||||
for (x = 0; x < 20; x++) {
|
||||
*((uint32_t *)(&fb + s * (y + 20) + (x + 80) * 4)) = 0x000000FF;
|
||||
}
|
||||
}
|
||||
if (s) {
|
||||
// cross-hair to see screen dimension detected correctly
|
||||
for (y = 0; y < h; y++) {
|
||||
*((uint32_t *)(&fb + s * y + (w * 2))) = 0x000FFFFF;
|
||||
}
|
||||
for (x = 0; x < w; x++) {
|
||||
*((uint32_t *)(&fb + s * (h / 2) + x * 4)) = 0x00FFFFFF;
|
||||
}
|
||||
|
||||
// memory stuff
|
||||
init_gdt();
|
||||
init_idt();
|
||||
|
||||
printf("Test after init\n");
|
||||
|
||||
// __asm__("int $0x80" :: );
|
||||
|
||||
struct tar_header hd;
|
||||
int res = tar_get_file("hello.txt", &hd);
|
||||
ASSERT(res == 1);
|
||||
puts(hd.name);
|
||||
putu32x(hd.size);
|
||||
putln();
|
||||
for (uint64_t i = 0; i < hd.size; i++) {
|
||||
putc(((char *)hd.data)[i]);
|
||||
// red, green, blue boxes in order
|
||||
for (y = 0; y < 20; y++) {
|
||||
for (x = 0; x < 20; x++) {
|
||||
*((uint32_t *)(&fb + s * (y + 20) + (x + 20) * 4)) = 0x00FF0000;
|
||||
}
|
||||
}
|
||||
putln();
|
||||
for (y = 0; y < 20; y++) {
|
||||
for (x = 0; x < 20; x++) {
|
||||
*((uint32_t *)(&fb + s * (y + 20) + (x + 50) * 4)) = 0x0000FF00;
|
||||
}
|
||||
}
|
||||
for (y = 0; y < 20; y++) {
|
||||
for (x = 0; x < 20; x++) {
|
||||
*((uint32_t *)(&fb + s * (y + 20) + (x + 80) * 4)) = 0x000000FF;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// hang for now
|
||||
PANIC("end of kernel");
|
||||
init_gdt();
|
||||
init_idt();
|
||||
|
||||
__asm__("int $0x80" ::);
|
||||
|
||||
struct tar_header hd;
|
||||
*/ int res = tar_get_file("hello.txt", &hd);
|
||||
*/ ASSERT(res == 1);
|
||||
*/ puts(hd.name);
|
||||
*/ putu32x(hd.size);
|
||||
*/ putln();
|
||||
*/ for (uint64_t i = 0; i < hd.size; i++) {
|
||||
*/ putc(((char *)hd.data)[i]);
|
||||
*/
|
||||
}
|
||||
putln();
|
||||
|
||||
// hang for now
|
||||
PANIC("end of kernel");
|
||||
}
|
||||
|
||||
/**************************
|
||||
* Display text on screen *
|
||||
**************************/
|
||||
typedef struct {
|
||||
uint32_t magic;
|
||||
uint32_t version;
|
||||
uint32_t headersize;
|
||||
uint32_t flags;
|
||||
uint32_t numglyph;
|
||||
uint32_t bytesperglyph;
|
||||
uint32_t height;
|
||||
uint32_t width;
|
||||
uint8_t glyphs;
|
||||
uint32_t magic;
|
||||
uint32_t version;
|
||||
uint32_t headersize;
|
||||
uint32_t flags;
|
||||
uint32_t numglyph;
|
||||
uint32_t bytesperglyph;
|
||||
uint32_t height;
|
||||
uint32_t width;
|
||||
uint8_t glyphs;
|
||||
} __attribute__((packed)) psf2_t;
|
||||
|
||||
extern volatile unsigned char _binary_font_psf_start;
|
||||
|
|
|
|||
490
src/std.c
490
src/std.c
|
|
@ -8,77 +8,77 @@
|
|||
|
||||
/* --- Memory Functions --- */
|
||||
void *memset(void *ptr, int value, size_t num) {
|
||||
unsigned char *byte_ptr = (unsigned char *)ptr;
|
||||
for (size_t i = 0; i < num; i++) {
|
||||
byte_ptr[i] = (unsigned char)value;
|
||||
}
|
||||
return ptr;
|
||||
unsigned char *byte_ptr = (unsigned char *)ptr;
|
||||
for (size_t i = 0; i < num; i++) {
|
||||
byte_ptr[i] = (unsigned char)value;
|
||||
}
|
||||
return ptr;
|
||||
}
|
||||
|
||||
void *memcpy(void *dest, const void *src, size_t n) {
|
||||
unsigned char *d = (unsigned char *)dest;
|
||||
const unsigned char *s = (const unsigned char *)src;
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
d[i] = s[i];
|
||||
}
|
||||
return dest;
|
||||
unsigned char *d = (unsigned char *)dest;
|
||||
const unsigned char *s = (const unsigned char *)src;
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
d[i] = s[i];
|
||||
}
|
||||
return dest;
|
||||
}
|
||||
|
||||
int memcmp(const void *ptr, const void *ptr2, size_t num) {
|
||||
unsigned char *d = (unsigned char *)ptr;
|
||||
unsigned char *b = (unsigned char *)ptr2;
|
||||
for (size_t i = 0; i < num; i++) {
|
||||
if (d[i] != b[i]) {
|
||||
return (d[i] - b[i]);
|
||||
}
|
||||
unsigned char *d = (unsigned char *)ptr;
|
||||
unsigned char *b = (unsigned char *)ptr2;
|
||||
for (size_t i = 0; i < num; i++) {
|
||||
if (d[i] != b[i]) {
|
||||
return (d[i] - b[i]);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void *memmove(void *dest, const void *src, size_t num) {
|
||||
unsigned char *d = (unsigned char *)dest;
|
||||
const unsigned char *s = (const unsigned char *)src;
|
||||
if (d < s || d >= (s + num)) {
|
||||
for (size_t i = 0; i < num; i++) {
|
||||
d[i] = s[i];
|
||||
}
|
||||
} else {
|
||||
for (size_t i = num; i > 0; i--) {
|
||||
d[i - 1] = s[i - 1];
|
||||
}
|
||||
unsigned char *d = (unsigned char *)dest;
|
||||
const unsigned char *s = (const unsigned char *)src;
|
||||
if (d < s || d >= (s + num)) {
|
||||
for (size_t i = 0; i < num; i++) {
|
||||
d[i] = s[i];
|
||||
}
|
||||
return dest;
|
||||
} else {
|
||||
for (size_t i = num; i > 0; i--) {
|
||||
d[i - 1] = s[i - 1];
|
||||
}
|
||||
}
|
||||
return dest;
|
||||
}
|
||||
|
||||
/* --- String functions --- */
|
||||
unsigned int strlen(const char *s) {
|
||||
unsigned int len = 0;
|
||||
while (*s != '\0') {
|
||||
s++;
|
||||
len++;
|
||||
}
|
||||
return len;
|
||||
unsigned int len = 0;
|
||||
while (*s != '\0') {
|
||||
s++;
|
||||
len++;
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
||||
bool streq(const char *a, const char *b) {
|
||||
while (*a != '\0' && *b != '\0') {
|
||||
if (*a != *b) {
|
||||
return false;
|
||||
}
|
||||
a++;
|
||||
b++;
|
||||
while (*a != '\0' && *b != '\0') {
|
||||
if (*a != *b) {
|
||||
return false;
|
||||
}
|
||||
// must have same length
|
||||
return *a == '\0' && *b == '\0';
|
||||
a++;
|
||||
b++;
|
||||
}
|
||||
// must have same length
|
||||
return *a == '\0' && *b == '\0';
|
||||
}
|
||||
|
||||
bool strcontains(const char *s, char c) {
|
||||
while (*s != '\0') {
|
||||
if (*s++ == c) {
|
||||
return true;
|
||||
}
|
||||
while (*s != '\0') {
|
||||
if (*s++ == c) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/* --- Line buffering --- */
|
||||
|
|
@ -87,77 +87,67 @@ static char linebuf[BUFFER_SIZE];
|
|||
static unsigned int current_buffer_position = 0;
|
||||
|
||||
static void linebuf_flush(void) {
|
||||
for (unsigned int i = 0; i < current_buffer_position; i++) {
|
||||
uart_write_char(linebuf[i]);
|
||||
}
|
||||
current_buffer_position = 0;
|
||||
for (unsigned int i = 0; i < current_buffer_position; i++) {
|
||||
uart_write_char(linebuf[i]);
|
||||
}
|
||||
current_buffer_position = 0;
|
||||
}
|
||||
|
||||
static void linebuf_putc(char c) {
|
||||
if (current_buffer_position == BUFFER_SIZE) {
|
||||
linebuf_flush();
|
||||
}
|
||||
linebuf[current_buffer_position++] = c;
|
||||
if (current_buffer_position == BUFFER_SIZE) {
|
||||
linebuf_flush();
|
||||
}
|
||||
linebuf[current_buffer_position++] = c;
|
||||
}
|
||||
|
||||
/* --- Low-level output functions --- */
|
||||
void putc(char c) {
|
||||
if (c == '\n') {
|
||||
linebuf_putc('\r');
|
||||
linebuf_putc('\n');
|
||||
linebuf_flush();
|
||||
} else {
|
||||
linebuf_putc(c);
|
||||
}
|
||||
if (c == '\n') {
|
||||
linebuf_putc('\r');
|
||||
linebuf_putc('\n');
|
||||
linebuf_flush();
|
||||
} else {
|
||||
linebuf_putc(c);
|
||||
}
|
||||
}
|
||||
|
||||
void putln(void) {
|
||||
putc('\n');
|
||||
}
|
||||
void putln(void) { putc('\n'); }
|
||||
|
||||
void puts(const char *s) {
|
||||
while (*s != '\0') {
|
||||
putc(*s++);
|
||||
}
|
||||
while (*s != '\0') {
|
||||
putc(*s++);
|
||||
}
|
||||
}
|
||||
|
||||
void putsln(const char *s) {
|
||||
puts(s);
|
||||
putln();
|
||||
puts(s);
|
||||
putln();
|
||||
}
|
||||
|
||||
void put_charbuf(const char *buf, unsigned int len) {
|
||||
for (unsigned int i = 0; i < len; i++) {
|
||||
putc(buf[i]);
|
||||
}
|
||||
for (unsigned int i = 0; i < len; i++) {
|
||||
putc(buf[i]);
|
||||
}
|
||||
}
|
||||
|
||||
#define TO_HEX(n) ((n) < 10 ? (n) + '0' : (n) - 10 + 'a')
|
||||
#define PUTUXX(nd) \
|
||||
do { \
|
||||
putc('0'); \
|
||||
putc('x'); \
|
||||
for (int i = 0; i < nd; i++) { \
|
||||
uint8_t hexval = (value >> ((((nd) - 1) - i) << 2)) & 0xf; \
|
||||
putc(TO_HEX(hexval)); \
|
||||
} \
|
||||
} while (0)
|
||||
#define PUTUXX(nd) \
|
||||
do { \
|
||||
putc('0'); \
|
||||
putc('x'); \
|
||||
for (int i = 0; i < nd; i++) { \
|
||||
uint8_t hexval = (value >> ((((nd) - 1) - i) << 2)) & 0xf; \
|
||||
putc(TO_HEX(hexval)); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
void putu8x(uint8_t value) {
|
||||
PUTUXX(2);
|
||||
}
|
||||
void putu8x(uint8_t value) { PUTUXX(2); }
|
||||
|
||||
void putu16x(uint16_t value) {
|
||||
PUTUXX(4);
|
||||
}
|
||||
void putu16x(uint16_t value) { PUTUXX(4); }
|
||||
|
||||
void putu32x(uint32_t value) {
|
||||
PUTUXX(8);
|
||||
}
|
||||
void putu32x(uint32_t value) { PUTUXX(8); }
|
||||
|
||||
void putu64x(uint64_t value) {
|
||||
PUTUXX(16);
|
||||
}
|
||||
void putu64x(uint64_t value) { PUTUXX(16); }
|
||||
|
||||
/* --- Number Conversion Functions --- */
|
||||
|
||||
|
|
@ -166,190 +156,192 @@ void putu64x(uint64_t value) {
|
|||
|
||||
/* Converts an int value to a string in a given base */
|
||||
void itoa(int value, unsigned int base, char *buffer) {
|
||||
itoa_ll(value, base, buffer);
|
||||
itoa_ll(value, base, buffer);
|
||||
}
|
||||
|
||||
/* Converts an unsigned int value to a string in a given base */
|
||||
void utoa(unsigned int value, unsigned int base, char *buffer) {
|
||||
utoa_ll(value, base, buffer);
|
||||
utoa_ll(value, base, buffer);
|
||||
}
|
||||
|
||||
/* Converts a long long value to a string in a given base */
|
||||
void itoa_ll(long long value, unsigned int base, char *buffer) {
|
||||
bool is_negative = false;
|
||||
unsigned long long uvalue;
|
||||
if (base == 10 && value < 0) {
|
||||
is_negative = true;
|
||||
uvalue = -value;
|
||||
} else {
|
||||
uvalue = value;
|
||||
}
|
||||
bool is_negative = false;
|
||||
unsigned long long uvalue;
|
||||
if (base == 10 && value < 0) {
|
||||
is_negative = true;
|
||||
uvalue = -value;
|
||||
} else {
|
||||
uvalue = value;
|
||||
}
|
||||
|
||||
if (is_negative) {
|
||||
buffer[0] = '-';
|
||||
utoa_ll(uvalue, base, buffer + 1);
|
||||
} else {
|
||||
utoa_ll(uvalue, base, buffer);
|
||||
}
|
||||
if (is_negative) {
|
||||
buffer[0] = '-';
|
||||
utoa_ll(uvalue, base, buffer + 1);
|
||||
} else {
|
||||
utoa_ll(uvalue, base, buffer);
|
||||
}
|
||||
}
|
||||
|
||||
/* Converts an unsigned long long value to a string in a given base */
|
||||
void utoa_ll(unsigned long long value, unsigned int base, char *buffer) {
|
||||
char temp[TOA_MAX_BUF_SIZE];
|
||||
int index = 0;
|
||||
if (value == 0) {
|
||||
temp[index++] = '0';
|
||||
} else {
|
||||
while (value > 0) {
|
||||
unsigned int digit = value % base;
|
||||
temp[index++] = "0123456789ABCDEF"[digit];
|
||||
value /= base;
|
||||
}
|
||||
char temp[TOA_MAX_BUF_SIZE];
|
||||
int index = 0;
|
||||
if (value == 0) {
|
||||
temp[index++] = '0';
|
||||
} else {
|
||||
while (value > 0) {
|
||||
unsigned int digit = value % base;
|
||||
temp[index++] = "0123456789ABCDEF"[digit];
|
||||
value /= base;
|
||||
}
|
||||
int out_index = 0;
|
||||
for (int i = index - 1; i >= 0; i--) {
|
||||
buffer[out_index++] = temp[i];
|
||||
}
|
||||
buffer[out_index] = '\0';
|
||||
}
|
||||
int out_index = 0;
|
||||
for (int i = index - 1; i >= 0; i--) {
|
||||
buffer[out_index++] = temp[i];
|
||||
}
|
||||
buffer[out_index] = '\0';
|
||||
}
|
||||
|
||||
/* --- Helper Functions --- */
|
||||
unsigned int toa_buf_size(unsigned int bits, unsigned int base) {
|
||||
unsigned int sz;
|
||||
if (base == 2) {
|
||||
sz = bits; // Binary: 1 symbol per bit
|
||||
} else if (base == 8) {
|
||||
sz = (bits + 2) / 3; // Octal: 3 bits per digit
|
||||
} else if (base == 16) {
|
||||
sz = (bits + 3) / 4; // Hex: 4 bits per digit
|
||||
} else if (base == 10) {
|
||||
sz = (bits * 30103) / 100000 + 1; // Approximate log10(2) ≈ 0.30103
|
||||
} else {
|
||||
UNREACHABLE();
|
||||
}
|
||||
return sz + 1; // null byte inclusive
|
||||
unsigned int sz;
|
||||
if (base == 2) {
|
||||
sz = bits; // Binary: 1 symbol per bit
|
||||
} else if (base == 8) {
|
||||
sz = (bits + 2) / 3; // Octal: 3 bits per digit
|
||||
} else if (base == 16) {
|
||||
sz = (bits + 3) / 4; // Hex: 4 bits per digit
|
||||
} else if (base == 10) {
|
||||
sz = (bits * 30103) / 100000 + 1; // Approximate log10(2) ≈ 0.30103
|
||||
} else {
|
||||
UNREACHABLE();
|
||||
}
|
||||
return sz + 1; // null byte inclusive
|
||||
}
|
||||
|
||||
/* --- Custom printf Implementation --- */
|
||||
#define IS_PRINTABLE(c) ((c) >= ' ' && (c) <= '~')
|
||||
|
||||
void printf(const char *format, ...) {
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
|
||||
while (*format) {
|
||||
if (*format == '%') {
|
||||
format++;
|
||||
bool do_number = false;
|
||||
int number_size_bits = 32;
|
||||
char number_buffer[TOA_MAX_BUF_SIZE + 1];
|
||||
char base;
|
||||
bool sign;
|
||||
// Check for length modifiers:
|
||||
switch (*format) {
|
||||
case 'h':
|
||||
do_number = true;
|
||||
number_size_bits = 16; // 16-bit (promoted to int in varargs)
|
||||
format++;
|
||||
break;
|
||||
case 'l':
|
||||
do_number = true;
|
||||
number_size_bits = 64; // 64-bit
|
||||
format++;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (do_number && !strcontains("duxob", *format)) {
|
||||
PANIC("printf: expected number format specifier after %h or %l");
|
||||
}
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
|
||||
switch (*format) {
|
||||
case 'd':
|
||||
do_number = true;
|
||||
base = 10;
|
||||
sign = true;
|
||||
break;
|
||||
case 'u':
|
||||
do_number = true;
|
||||
base = 10;
|
||||
sign = false;
|
||||
break;
|
||||
case 'x':
|
||||
do_number = true;
|
||||
base = 16;
|
||||
sign = false;
|
||||
break;
|
||||
case 'o':
|
||||
do_number = true;
|
||||
base = 8;
|
||||
sign = false;
|
||||
case 'b':
|
||||
do_number = true;
|
||||
base = 2;
|
||||
sign = false;
|
||||
break;
|
||||
case 'c': {
|
||||
char ch = (char)va_arg(args, int);
|
||||
putc(ch);
|
||||
break;
|
||||
}
|
||||
case 's': {
|
||||
char *str = va_arg(args, char *);
|
||||
puts(str);
|
||||
break;
|
||||
}
|
||||
case 'p': {
|
||||
void *ptr = va_arg(args, void *);
|
||||
putu64x((uint64_t)(intptr_t)ptr);
|
||||
break;
|
||||
}
|
||||
case '%': {
|
||||
putc('%');
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
PANIC("printf: unsupported format specifier");
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (do_number) {
|
||||
if (number_size_bits == 64) {
|
||||
long long value = va_arg(args, long long);
|
||||
if (sign) {
|
||||
itoa_ll(value, base, number_buffer);
|
||||
} else {
|
||||
utoa_ll((unsigned long long)value, base, number_buffer);
|
||||
}
|
||||
} else {
|
||||
int value = va_arg(args, int);
|
||||
if (sign) {
|
||||
itoa(value, base, number_buffer);
|
||||
} else {
|
||||
utoa((unsigned int)value, base, number_buffer);
|
||||
}
|
||||
}
|
||||
puts(number_buffer);
|
||||
}
|
||||
format++;
|
||||
} else if (IS_PRINTABLE(*format) || *format == '\n') {
|
||||
putc(*format);
|
||||
format++;
|
||||
while (*format) {
|
||||
if (*format == '%') {
|
||||
format++;
|
||||
bool do_number = false;
|
||||
int number_size_bits = 32;
|
||||
char number_buffer[TOA_MAX_BUF_SIZE + 1];
|
||||
char base;
|
||||
bool sign;
|
||||
// Check for length modifiers:
|
||||
switch (*format) {
|
||||
case 'h':
|
||||
do_number = true;
|
||||
number_size_bits = 16; // 16-bit (promoted to int in varargs)
|
||||
format++;
|
||||
break;
|
||||
case 'l':
|
||||
do_number = true;
|
||||
number_size_bits = 64; // 64-bit
|
||||
format++;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (do_number && !strcontains("duxob", *format)) {
|
||||
PANIC("printf: expected number format specifier after %h or %l");
|
||||
}
|
||||
|
||||
switch (*format) {
|
||||
case 'd':
|
||||
do_number = true;
|
||||
base = 10;
|
||||
sign = true;
|
||||
break;
|
||||
case 'u':
|
||||
do_number = true;
|
||||
base = 10;
|
||||
sign = false;
|
||||
break;
|
||||
case 'x':
|
||||
do_number = true;
|
||||
base = 16;
|
||||
sign = false;
|
||||
break;
|
||||
case 'o':
|
||||
do_number = true;
|
||||
base = 8;
|
||||
sign = false;
|
||||
case 'b':
|
||||
do_number = true;
|
||||
base = 2;
|
||||
sign = false;
|
||||
break;
|
||||
case 'c': {
|
||||
char ch = (char)va_arg(args, int);
|
||||
putc(ch);
|
||||
break;
|
||||
}
|
||||
case 's': {
|
||||
char *str = va_arg(args, char *);
|
||||
puts(str);
|
||||
break;
|
||||
}
|
||||
case 'p': {
|
||||
void *ptr = va_arg(args, void *);
|
||||
putu64x((uint64_t)(intptr_t)ptr);
|
||||
break;
|
||||
}
|
||||
case '%': {
|
||||
putc('%');
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
PANIC("printf: unsupported format specifier");
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (do_number) {
|
||||
if (number_size_bits == 64) {
|
||||
long long value = va_arg(args, long long);
|
||||
if (sign) {
|
||||
itoa_ll(value, base, number_buffer);
|
||||
} else {
|
||||
utoa_ll((unsigned long long)value, base, number_buffer);
|
||||
}
|
||||
} else {
|
||||
// we disallow everything else for now (including \r, \t)
|
||||
putc('[');
|
||||
putu8x(*format);
|
||||
putc(']');
|
||||
format++;
|
||||
int value = va_arg(args, int);
|
||||
if (sign) {
|
||||
itoa(value, base, number_buffer);
|
||||
} else {
|
||||
utoa((unsigned int)value, base, number_buffer);
|
||||
}
|
||||
}
|
||||
puts(number_buffer);
|
||||
}
|
||||
format++;
|
||||
} else if (IS_PRINTABLE(*format) || *format == '\n') {
|
||||
putc(*format);
|
||||
format++;
|
||||
} else {
|
||||
// we disallow everything else for now (including \r, \t)
|
||||
putc('[');
|
||||
putu8x(*format);
|
||||
putc(']');
|
||||
format++;
|
||||
}
|
||||
va_end(args);
|
||||
}
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
/* --- Debug helpers --- */
|
||||
__attribute__((noreturn)) void panic(const char *file, unsigned int line, const char *msg) {
|
||||
printf("PANIC@%s:%d: %s\n", file, line, msg);
|
||||
while (1) {
|
||||
// loop forever
|
||||
}
|
||||
__attribute__((noreturn)) void panic(const char *file, unsigned int line,
|
||||
const char *msg) {
|
||||
printf("PANIC@%s:%d: %s\n", file, line, msg);
|
||||
while (1) {
|
||||
// loop forever
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,125 +1,7 @@
|
|||
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <sys/io.h>
|
||||
|
||||
typedef volatile struct __attribute__((packed)) SATA_DEVICE {
|
||||
// 0x00 - 0x03: ID Identifiers (Vendor ID and Device ID)
|
||||
uint16_t vendor_id; // 0x00-0x01: Vendor ID
|
||||
uint16_t device_id; // 0x02-0x03: Device ID
|
||||
|
||||
// 0x04 - 0x05: Command Register
|
||||
uint16_t command; // 0x04-0x05
|
||||
|
||||
// 0x06 - 0x07: Status Register
|
||||
uint16_t status; // 0x06-0x07
|
||||
|
||||
// 0x08: Revision ID
|
||||
uint8_t revision_id; // 0x08
|
||||
|
||||
// 0x09 - 0x0B: Class Codes (3 bytes)
|
||||
uint8_t class_code[3]; // 0x09-0x0B
|
||||
|
||||
// 0x0C: Cache Line Size
|
||||
uint8_t cache_line_size; // 0x0C
|
||||
|
||||
// 0x0D: Master Latency Timer
|
||||
uint8_t master_latency_timer; // 0x0D
|
||||
|
||||
// 0x0E: Header Type
|
||||
uint8_t header_type; // 0x0E
|
||||
|
||||
// 0x0F: Built-in Self Test (BIST)
|
||||
uint8_t bist; // 0x0F
|
||||
|
||||
// 0x10 - 0x23: Base Address Registers (BAR0 - BAR4)
|
||||
uint32_t bars[5]; // 5 * 4 bytes = 20 bytes
|
||||
|
||||
// 0x24 - 0x27: AHCI Base Address Register (BAR5)
|
||||
uint32_t abar; // 0x24-0x27
|
||||
|
||||
// 0x28 - 0x2B: Reserved (typically unused)
|
||||
uint32_t reserved0; // 0x28-0x2B
|
||||
|
||||
// 0x2C - 0x2F: Subsystem Identifiers
|
||||
// Standard PCI header splits these into Subsystem Vendor ID and Subsystem ID.
|
||||
uint16_t subsystem_vendor_id; // 0x2C-0x2D: Subsystem Vendor ID
|
||||
uint16_t subsystem_id; // 0x2E-0x2F: Subsystem ID
|
||||
|
||||
// 0x30 - 0x33: Expansion ROM Base Address (Optional)
|
||||
uint32_t expansion_rom_base; // 0x30-0x33
|
||||
|
||||
// 0x34: Capabilities Pointer
|
||||
uint8_t cap_ptr; // 0x34
|
||||
|
||||
// 0x35 - 0x3B: Reserved
|
||||
uint8_t reserved1[7]; // 0x35-0x3B
|
||||
|
||||
// 0x3C - 0x3D: Interrupt Information
|
||||
// Typically split into Interrupt Line and Interrupt Pin.
|
||||
uint8_t interrupt_line; // 0x3C
|
||||
uint8_t interrupt_pin; // 0x3D
|
||||
|
||||
// 0x3E: Min Grant (Optional)
|
||||
uint8_t min_grant; // 0x3E
|
||||
|
||||
// 0x3F: Max Latency (Optional)
|
||||
uint8_t max_latency; // 0x3F
|
||||
} SATA_DEVICE;
|
||||
|
||||
typedef struct {
|
||||
volatile HBA_MEM *hbaMem; // Pointer to the complete HBA memory block.
|
||||
volatile HBA_PORT *ports; // Pointer to the port control registers block.
|
||||
} HBA_MMAP;
|
||||
|
||||
// Port for each device connected to the HBA device
|
||||
typedef volatile struct __attribute__((packed)) HBA_PORT {
|
||||
uint32_t clb; // 0x00: Command List Base Address
|
||||
uint32_t clbu; // 0x04: Command List Base Address Upper 32 bits (if needed)
|
||||
uint32_t fb; // 0x08: FIS Base Address
|
||||
uint32_t fbu; // 0x0C: FIS Base Address Upper 32 bits (if needed)
|
||||
uint32_t is; // 0x10: Interrupt Status
|
||||
uint32_t ie; // 0x14: Interrupt Enable
|
||||
uint32_t cmd; // 0x18: Command and Status
|
||||
uint32_t reserved0; // 0x1C: Reserved
|
||||
uint32_t tfd; // 0x20: Task File Data
|
||||
uint32_t sig; // 0x24: Signature (to identify the type of device connected)
|
||||
uint32_t ssts; // 0x28: SATA Status (SSTS)
|
||||
uint32_t sctl; // 0x2C: SATA Control (SCTL)
|
||||
uint32_t serr; // 0x30: SATA Error (SERR)
|
||||
uint32_t sact; // 0x34: SATA Active (SACT)
|
||||
uint32_t ci; // 0x38: Command Issue (CI)
|
||||
uint32_t sntf; // 0x3C: SATA Notification (SNTF)
|
||||
uint32_t fbs; // 0x40: FIS-Based Switching control (if supported)
|
||||
// Padding to ensure the entire port register block is 0x80 bytes in size:
|
||||
uint8_t reserved1[0x80 - 0x44]; // 0x44 to 0x7F reserved
|
||||
} HBA_PORT;
|
||||
|
||||
// Global registers vor the HBA controller
|
||||
typedef volatile struct __attribute__((packed)) HBA_MEM {
|
||||
uint32_t cap; // 0x00: Host Capabilities
|
||||
uint32_t ghc; // 0x04: Global Host Control
|
||||
uint32_t is; // 0x08: Interrupt Status
|
||||
uint32_t pi; // 0x0C: Ports Implemented (bitmask indicating active ports)
|
||||
uint32_t vs; // 0x10: Version
|
||||
uint32_t ccc_ctl; // 0x14: Command Completion Coalescing Control
|
||||
uint32_t ccc_ports; // 0x18: Command Completion Coalescing Ports
|
||||
uint32_t em_loc; // 0x1C: Enclosure Management Location
|
||||
uint32_t em_ctl; // 0x20: Enclosure Management Control
|
||||
uint32_t cap2; // 0x24: Host Capabilities Extended
|
||||
uint32_t bohc; // 0x28: BIOS/OS Handoff Control and Status
|
||||
|
||||
// Reserved regions
|
||||
uint8_t reserved0[0x60 - 0x2C]; // 0x2C - 0x5F: Reserved
|
||||
uint8_t reserved1[0xA0 - 0x60]; // 0x60 - 0x9F: Reserved for NVMHCI
|
||||
uint8_t vendor[0x100 - 0xA0]; // 0xA0 - 0xFF: Vendor Specific Registers
|
||||
|
||||
// Port Control Registers
|
||||
// Starting at 0x100, each port has a control register block (typically 0x80
|
||||
// bytes per port)
|
||||
HBA_PORT ports[32]; // Maximum of 32 ports; the 'pi' field in the global
|
||||
// registers indicates which are active
|
||||
} HBA_MEM;
|
||||
#include <x86_64/sata.h>
|
||||
|
||||
uint32_t pci_read(uint8_t bus, uint8_t device, uint8_t function,
|
||||
uint8_t offset) {
|
||||
|
|
@ -129,11 +11,10 @@ uint32_t pci_read(uint8_t bus, uint8_t device, uint8_t function,
|
|||
address); // Write the address to the PCI configuration address port
|
||||
return inl(0xCFC); // Read the configuration data from the data port
|
||||
}
|
||||
// HBA_GHC_RESET: Bit 0 – when set, the HBA begins a global reset.
|
||||
// HBA_GHC_AE: Bit 31 – when set, AHCI mode is enabled.
|
||||
#define HBA_GHC_RESET (1 << 0)
|
||||
#define HBA_GHC_AE (1 << 31)
|
||||
|
||||
void debug() {};
|
||||
void debug1() {};
|
||||
void debug2() {};
|
||||
void debug3() {};
|
||||
int check_PCI_devices(SATA_DEVICE *list_of_devices, int range) {
|
||||
int array_index = 0;
|
||||
for (int bus = 0; bus < 256; bus++) {
|
||||
|
|
@ -149,11 +30,13 @@ int check_PCI_devices(SATA_DEVICE *list_of_devices, int range) {
|
|||
continue;
|
||||
}
|
||||
uint16_t device_id = (id_val >> 16) & 0xFFFF;
|
||||
debug1();
|
||||
|
||||
// Offset 0x04: Command (lower 16 bits) and Status (upper 16 bits).
|
||||
uint32_t cmd_status = pci_read(bus, device, function, 0x04);
|
||||
uint16_t command = cmd_status & 0xFFFF;
|
||||
uint16_t status = (cmd_status >> 16) & 0xFFFF;
|
||||
debug2();
|
||||
|
||||
// Offset 0x08: Revision ID and Class Codes.
|
||||
// The 32-bit value at 0x08 has:
|
||||
|
|
@ -186,6 +69,7 @@ int check_PCI_devices(SATA_DEVICE *list_of_devices, int range) {
|
|||
uint8_t master_latency_timer = (misc >> 8) & 0xFF;
|
||||
uint8_t header_type = (misc >> 16) & 0xFF;
|
||||
uint8_t bist = (misc >> 24) & 0xFF;
|
||||
debug3();
|
||||
|
||||
// Offsets 0x10 - 0x23: BAR0 - BAR4.
|
||||
uint32_t bars[5];
|
||||
|
|
@ -263,6 +147,7 @@ int check_PCI_devices(SATA_DEVICE *list_of_devices, int range) {
|
|||
|
||||
list_of_devices[array_index++] = dev;
|
||||
}
|
||||
debug();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -306,31 +191,10 @@ void check_number_off_active_ports(volatile HBA_MEM *hba) {
|
|||
uint32_t ports_implemented = hba->pi;
|
||||
uint32_t number_of_ports = 0;
|
||||
|
||||
while (ports_implemented = !0) {
|
||||
while (ports_implemented != 0) {
|
||||
if (ports_implemented & 1) {
|
||||
number_of_ports++;
|
||||
}
|
||||
ports_implemented >> 1;
|
||||
// ports_implemented << 1;
|
||||
}
|
||||
}
|
||||
|
||||
int main() {
|
||||
if (ioperm(0xCF8, 8, 1)) {
|
||||
perror("ioperm");
|
||||
return 1;
|
||||
}
|
||||
|
||||
SATA_DEVICE list_of_devices[100];
|
||||
int device_count = check_PCI_devices(list_of_devices, 100);
|
||||
printf("\nFound %d SATA device(s).\n\n", device_count);
|
||||
|
||||
// Map Registers from the active ports into memorz
|
||||
// CommandList
|
||||
// CommandTable
|
||||
// FIS receive area
|
||||
// Configure Ports
|
||||
// Issue commands via CommndList and Table
|
||||
// Use DMA and via PRDT to send and recieve data
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue