Pridana verze v0.1

This commit is contained in:
2026-07-12 05:44:42 +02:00
commit 1266a65b82
40 changed files with 6126 additions and 0 deletions
+190
View File
@@ -0,0 +1,190 @@
/*
* AsterOS Kernel
* Autor: Pavel Kalaš
* Rok: 2026
*
*/
/*
* Tento ovladac realizuje textovou konzoli nad VGA pameti na adrese 0xB8000.
* Ridi pozici kurzoru, barvy znaku, zpracovani ridicich znaku
* a automaticky scroll, kdyz vystup presahne posledni radek obrazovky.
*/
#include "display.h"
#define VGA_WIDTH 80
#define VGA_HEIGHT 25
#define VGA_CONTENT_HEIGHT (VGA_HEIGHT - 1)
static volatile u16 *const vga = (u16 *)0xB8000;
static u8 color = 0x0F;
static usize row = 0;
static usize col = 0;
static inline void outb(u16 port, u8 value) {
__asm__ volatile ("outb %0, %1" : : "a"(value), "Nd"(port));
}
static void update_hw_cursor(void) {
u16 pos = (u16)(row * VGA_WIDTH + col);
outb(0x3D4, 0x0F);
outb(0x3D5, (u8)(pos & 0xFF));
outb(0x3D4, 0x0E);
outb(0x3D5, (u8)((pos >> 8) & 0xFF));
}
static inline u16 vga_entry(char c, u8 clr) {
return (u16)c | ((u16)clr << 8);
}
static void scroll_if_needed(void) {
usize r;
usize c;
if (row < VGA_CONTENT_HEIGHT) {
return;
}
for (r = 1; r < VGA_CONTENT_HEIGHT; ++r) {
for (c = 0; c < VGA_WIDTH; ++c) {
vga[(r - 1) * VGA_WIDTH + c] = vga[r * VGA_WIDTH + c];
}
}
for (c = 0; c < VGA_WIDTH; ++c) {
vga[(VGA_CONTENT_HEIGHT - 1) * VGA_WIDTH + c] = vga_entry(' ', color);
}
row = VGA_CONTENT_HEIGHT - 1;
}
void display_set_color(u8 fg, u8 bg) {
color = (u8)((bg << 4) | (fg & 0x0F));
}
void display_clear(void) {
usize i;
for (i = 0; i < VGA_WIDTH * VGA_HEIGHT; ++i) {
vga[i] = vga_entry(' ', color);
}
row = 0;
col = 0;
update_hw_cursor();
}
void display_init(void) {
display_set_color(0x0F, 0x00);
display_clear();
}
void display_putc(char c) {
if (c == '\n') {
col = 0;
++row;
scroll_if_needed();
update_hw_cursor();
return;
}
if (c == '\r') {
col = 0;
update_hw_cursor();
return;
}
if (c == '\b') {
if (col > 0) {
--col;
} else if (row > 0) {
--row;
col = VGA_WIDTH - 1;
}
vga[row * VGA_WIDTH + col] = vga_entry(' ', color);
update_hw_cursor();
return;
}
if (c == '\t') {
col = (col + 4) & ~3ULL;
if (col >= VGA_WIDTH) {
col = 0;
++row;
scroll_if_needed();
}
update_hw_cursor();
return;
}
vga[row * VGA_WIDTH + col] = vga_entry(c, color);
++col;
if (col >= VGA_WIDTH) {
col = 0;
++row;
scroll_if_needed();
}
update_hw_cursor();
}
void display_write(const char *text) {
while (*text) {
display_putc(*text++);
}
}
void display_get_cursor(usize *out_row, usize *out_col) {
if (out_row) {
*out_row = row;
}
if (out_col) {
*out_col = col;
}
}
void display_set_cursor(usize new_row, usize new_col) {
if (new_row >= VGA_HEIGHT) {
new_row = VGA_HEIGHT - 1;
}
if (new_col >= VGA_WIDTH) {
new_col = VGA_WIDTH - 1;
}
row = new_row;
col = new_col;
update_hw_cursor();
}
void display_fill_row(usize target_row, char ch, u8 fg, u8 bg) {
usize c;
u8 clr;
if (target_row >= VGA_HEIGHT) {
return;
}
clr = (u8)((bg << 4) | (fg & 0x0F));
for (c = 0; c < VGA_WIDTH; ++c) {
vga[target_row * VGA_WIDTH + c] = vga_entry(ch, clr);
}
}
void display_write_at(usize target_row, usize target_col, const char *text, u8 fg, u8 bg) {
usize c = target_col;
u8 clr;
if (!text || target_row >= VGA_HEIGHT || target_col >= VGA_WIDTH) {
return;
}
clr = (u8)((bg << 4) | (fg & 0x0F));
while (*text && c < VGA_WIDTH) {
vga[target_row * VGA_WIDTH + c] = vga_entry(*text++, clr);
++c;
}
}
+275
View File
@@ -0,0 +1,275 @@
/*
* AsterOS Kernel
* Autor: Pavel Kalaš
* Rok: 2026
*
*/
/*
* Tento soubor implementuje zakladni klavesnicovy vstup pres PS/2 porty.
* Preklada scancode na ASCII znaky a poskytuje funkci pro nacitani radku,
* kterou pouziva shell pro prijem prikazu od uzivatele.
*/
#include "display.h"
#include "drivers.h"
#define KBD_HISTORY_MAX 32
#define KBD_HISTORY_LINE_MAX 128
static char g_history[KBD_HISTORY_MAX][KBD_HISTORY_LINE_MAX];
static int g_history_count = 0;
static int g_history_head = 0;
static int g_ctrl_down = 0;
static inline unsigned char inb(unsigned short port) {
unsigned char ret;
__asm__ volatile ("inb %1, %0" : "=a"(ret) : "Nd"(port));
return ret;
}
static const char keymap[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, ' ',
};
void keyboard_init(void) {
}
int keyboard_try_read_key(void) {
unsigned char sc;
int out = -1;
if ((inb(0x64) & 1) == 0) {
return -1;
}
sc = inb(0x60);
if (sc == 0xE0) {
unsigned char ext;
if ((inb(0x64) & 1) == 0) {
return -1;
}
ext = inb(0x60);
if (ext == 0x1D) {
g_ctrl_down = 1;
return -1;
}
if (ext == 0x9D) {
g_ctrl_down = 0;
return -1;
}
if (ext & 0x80) {
return -1;
}
if (ext == 0x48) {
out = ASTER_KEY_UP;
return out;
}
if (ext == 0x50) {
out = ASTER_KEY_DOWN;
return out;
}
if (ext == 0x4B) {
out = ASTER_KEY_LEFT;
return out;
}
if (ext == 0x4D) {
out = ASTER_KEY_RIGHT;
return out;
}
return -1;
}
if (sc == 0x1D) {
g_ctrl_down = 1;
return -1;
}
if (sc == 0x9D) {
g_ctrl_down = 0;
return -1;
}
if (sc & 0x80) {
return -1;
}
if (sc == 0x3B) {
out = ASTER_KEY_F1;
return out;
}
if (sc == 0x3C) {
out = ASTER_KEY_F2;
return out;
}
if (sc == 0x1F && g_ctrl_down) {
out = 19; /* Ctrl+S */
return out;
}
if (sc < 128 && keymap[sc]) {
out = keymap[sc];
return out;
}
return -1;
}
int keyboard_read_key(void) {
for (;;) {
int k = keyboard_try_read_key();
if (k != -1) {
return k;
}
__asm__ volatile ("pause");
}
}
static void clear_current_line(int len) {
int j;
for (j = 0; j < len; ++j) {
display_putc('\b');
}
}
static void set_line_from_history(char *buffer, int *len, int max_len, const char *src) {
int j = 0;
int limit = max_len - 1;
clear_current_line(*len);
while (src[j] && j < limit) {
buffer[j] = src[j];
display_putc(src[j]);
++j;
}
buffer[j] = '\0';
*len = j;
}
static void history_push(const char *line) {
int i;
int slot;
if (!line || !line[0]) {
return;
}
if (g_history_count > 0) {
int last = (g_history_head + KBD_HISTORY_MAX - 1) % KBD_HISTORY_MAX;
if (g_history[last][0] != '\0') {
i = 0;
while (line[i] && g_history[last][i] && line[i] == g_history[last][i]) {
++i;
}
if (line[i] == '\0' && g_history[last][i] == '\0') {
return;
}
}
}
slot = g_history_head;
for (i = 0; i < KBD_HISTORY_LINE_MAX - 1 && line[i]; ++i) {
g_history[slot][i] = line[i];
}
g_history[slot][i] = '\0';
g_history_head = (g_history_head + 1) % KBD_HISTORY_MAX;
if (g_history_count < KBD_HISTORY_MAX) {
++g_history_count;
}
}
int keyboard_readline(char *buffer, int max_len) {
int i = 0;
int history_nav = -1;
if (max_len <= 1) {
return 0;
}
for (;;) {
int c = keyboard_read_key();
if (c == ASTER_KEY_F1 || c == ASTER_KEY_F2) {
continue;
}
if (c == ASTER_KEY_UP) {
if (g_history_count == 0) {
continue;
}
if (history_nav < g_history_count - 1) {
++history_nav;
}
{
int idx = (g_history_head + KBD_HISTORY_MAX - 1 - history_nav) % KBD_HISTORY_MAX;
set_line_from_history(buffer, &i, max_len, g_history[idx]);
}
continue;
}
if (c == ASTER_KEY_DOWN) {
if (g_history_count == 0) {
continue;
}
if (history_nav > 0) {
--history_nav;
{
int idx = (g_history_head + KBD_HISTORY_MAX - 1 - history_nav) % KBD_HISTORY_MAX;
set_line_from_history(buffer, &i, max_len, g_history[idx]);
}
} else if (history_nav == 0) {
history_nav = -1;
clear_current_line(i);
i = 0;
buffer[0] = '\0';
}
continue;
}
if (c == '\n') {
display_putc('\n');
buffer[i] = '\0';
history_push(buffer);
return i;
}
if (c == '\b') {
if (i > 0) {
--i;
display_putc('\b');
}
continue;
}
if (i < max_len - 1) {
buffer[i++] = (char)c;
display_putc((char)c);
buffer[i] = '\0';
history_nav = -1;
}
}
}
+669
View File
@@ -0,0 +1,669 @@
/*
* AsterOS Kernel
* Autor: Pavel Kalas
* Rok: 2026
*
*/
/*
* Tento modul implementuje AsterFS nad realnym ATA diskem v QEMU.
* Data se nahravaji pri startu a po kazde zmene se synchronizuji
* do sektoru na druhem IDE disku, aby pretrvala mezi restarty.
*/
#include "storage.h"
#include "string.h"
#define ATA_IO_BASE 0x1F0
#define ATA_CTRL_BASE 0x3F6
#define ATA_DRIVE_SLAVE 0xF0
#define ATA_REG_DATA 0
#define ATA_REG_SECCOUNT0 2
#define ATA_REG_LBA0 3
#define ATA_REG_LBA1 4
#define ATA_REG_LBA2 5
#define ATA_REG_HDDEVSEL 6
#define ATA_REG_COMMAND 7
#define ATA_REG_STATUS 7
#define ATA_CMD_READ_PIO 0x20
#define ATA_CMD_WRITE_PIO 0x30
#define ATA_CMD_CACHE_FLUSH 0xE7
#define ATA_SR_BSY 0x80
#define ATA_SR_DRQ 0x08
#define ATA_SR_ERR 0x01
#define ASTERFS_MAGIC "ASTERFS1"
#define ASTERFS_VERSION 1U
#define ASTERFS_NODE_BYTES (ASTERFS_NAME_LEN + 1 + 2 + 1 + ASTERFS_DATA_LEN)
#define ASTERFS_NODE_SECTORS (((ASTERFS_MAX_FILES * ASTERFS_NODE_BYTES) + 511) / 512)
#define ASTERFS_DISK_START_LBA 1U
typedef struct {
char magic[8];
u32 version;
u32 nodes_used;
u32 reserved;
u8 pad[512 - 8 - 4 - 4 - 4];
} asterfs_superblock_t;
typedef struct {
char name[ASTERFS_NAME_LEN];
u8 is_dir;
u16 size;
u8 reserved;
u8 data[ASTERFS_DATA_LEN];
} asterfs_disk_node_t;
static asterfs_node_t nodes[ASTERFS_MAX_FILES];
static int nodes_used = 0;
static int disk_ready = 0;
static u8 g_sector_buffer[512];
static u8 g_nodes_blob[ASTERFS_MAX_FILES * ASTERFS_NODE_BYTES];
static inline void outb(unsigned short port, unsigned char value) {
__asm__ volatile ("outb %0, %1" : : "a"(value), "Nd"(port));
}
static inline unsigned char inb(unsigned short port) {
unsigned char ret;
__asm__ volatile ("inb %1, %0" : "=a"(ret) : "Nd"(port));
return ret;
}
static inline void outw(unsigned short port, unsigned short value) {
__asm__ volatile ("outw %0, %1" : : "a"(value), "Nd"(port));
}
static inline unsigned short inw(unsigned short port) {
unsigned short ret;
__asm__ volatile ("inw %1, %0" : "=a"(ret) : "Nd"(port));
return ret;
}
static void ata_delay_400ns(void) {
(void)inb(ATA_CTRL_BASE);
(void)inb(ATA_CTRL_BASE);
(void)inb(ATA_CTRL_BASE);
(void)inb(ATA_CTRL_BASE);
}
static int ata_wait_not_busy(void) {
unsigned int timeout = 200000U;
while (timeout-- > 0) {
unsigned char s = inb(ATA_IO_BASE + ATA_REG_STATUS);
if (s == 0x00 || s == 0xFF) {
return -1;
}
if ((s & ATA_SR_BSY) == 0) {
return 0;
}
}
return -1;
}
static int ata_wait_drq(void) {
unsigned int timeout = 200000U;
while (timeout-- > 0) {
unsigned char s = inb(ATA_IO_BASE + ATA_REG_STATUS);
if (s == 0x00 || s == 0xFF) {
return -1;
}
if (s & ATA_SR_ERR) {
return -1;
}
if ((s & ATA_SR_BSY) == 0 && (s & ATA_SR_DRQ) != 0) {
return 0;
}
}
return -1;
}
static int ata_select_drive_lba(u32 lba) {
if (ata_wait_not_busy() != 0) {
return -1;
}
outb(ATA_IO_BASE + ATA_REG_HDDEVSEL, (unsigned char)(ATA_DRIVE_SLAVE | ((lba >> 24) & 0x0F)));
ata_delay_400ns();
return 0;
}
static int ata_probe_slave(void) {
unsigned char s;
outb(ATA_IO_BASE + ATA_REG_HDDEVSEL, ATA_DRIVE_SLAVE);
ata_delay_400ns();
s = inb(ATA_IO_BASE + ATA_REG_STATUS);
if (s == 0x00 || s == 0xFF) {
return -1;
}
return ata_wait_not_busy();
}
static int ata_read_sector(u32 lba, u8 *buf512) {
int i;
if (!buf512) {
return -1;
}
if (ata_select_drive_lba(lba) != 0) {
return -1;
}
outb(ATA_IO_BASE + ATA_REG_SECCOUNT0, 1);
outb(ATA_IO_BASE + ATA_REG_LBA0, (unsigned char)(lba & 0xFF));
outb(ATA_IO_BASE + ATA_REG_LBA1, (unsigned char)((lba >> 8) & 0xFF));
outb(ATA_IO_BASE + ATA_REG_LBA2, (unsigned char)((lba >> 16) & 0xFF));
outb(ATA_IO_BASE + ATA_REG_COMMAND, ATA_CMD_READ_PIO);
if (ata_wait_drq() != 0) {
return -1;
}
for (i = 0; i < 256; ++i) {
unsigned short w = inw(ATA_IO_BASE + ATA_REG_DATA);
buf512[i * 2] = (u8)(w & 0xFF);
buf512[i * 2 + 1] = (u8)((w >> 8) & 0xFF);
}
return 0;
}
static int ata_write_sector(u32 lba, const u8 *buf512) {
int i;
if (!buf512) {
return -1;
}
if (ata_select_drive_lba(lba) != 0) {
return -1;
}
outb(ATA_IO_BASE + ATA_REG_SECCOUNT0, 1);
outb(ATA_IO_BASE + ATA_REG_LBA0, (unsigned char)(lba & 0xFF));
outb(ATA_IO_BASE + ATA_REG_LBA1, (unsigned char)((lba >> 8) & 0xFF));
outb(ATA_IO_BASE + ATA_REG_LBA2, (unsigned char)((lba >> 16) & 0xFF));
outb(ATA_IO_BASE + ATA_REG_COMMAND, ATA_CMD_WRITE_PIO);
if (ata_wait_drq() != 0) {
return -1;
}
for (i = 0; i < 256; ++i) {
unsigned short w = (unsigned short)buf512[i * 2] | ((unsigned short)buf512[i * 2 + 1] << 8);
outw(ATA_IO_BASE + ATA_REG_DATA, w);
}
outb(ATA_IO_BASE + ATA_REG_COMMAND, ATA_CMD_CACHE_FLUSH);
if (ata_wait_not_busy() != 0) {
return -1;
}
return 0;
}
static void fs_reset_memory(void) {
int i;
for (i = 0; i < ASTERFS_MAX_FILES; ++i) {
nodes[i].name[0] = '\0';
nodes[i].is_dir = 0;
nodes[i].size = 0;
}
nodes_used = 0;
}
static void fs_encode_nodes(u8 *out) {
int i;
for (i = 0; i < ASTERFS_MAX_FILES; ++i) {
asterfs_disk_node_t d;
usize off = (usize)i * ASTERFS_NODE_BYTES;
aster_memset(&d, 0, sizeof(d));
aster_memcpy(d.name, nodes[i].name, ASTERFS_NAME_LEN);
d.is_dir = nodes[i].is_dir;
d.size = nodes[i].size;
aster_memcpy(d.data, nodes[i].data, ASTERFS_DATA_LEN);
aster_memcpy(out + off, &d, ASTERFS_NODE_BYTES);
}
}
static void fs_decode_nodes(const u8 *in) {
int i;
for (i = 0; i < ASTERFS_MAX_FILES; ++i) {
asterfs_disk_node_t d;
usize off = (usize)i * ASTERFS_NODE_BYTES;
aster_memcpy(&d, in + off, ASTERFS_NODE_BYTES);
aster_memset(nodes[i].name, 0, ASTERFS_NAME_LEN);
aster_memcpy(nodes[i].name, d.name, ASTERFS_NAME_LEN);
nodes[i].is_dir = d.is_dir;
nodes[i].size = d.size;
if (nodes[i].size > ASTERFS_DATA_LEN) {
nodes[i].size = ASTERFS_DATA_LEN;
}
aster_memcpy(nodes[i].data, d.data, ASTERFS_DATA_LEN);
}
}
static int fs_flush_disk(void) {
asterfs_superblock_t super;
unsigned int sector;
if (!disk_ready) {
return 0;
}
aster_memset(&super, 0, sizeof(super));
aster_memcpy(super.magic, ASTERFS_MAGIC, 8);
super.version = ASTERFS_VERSION;
super.nodes_used = (u32)nodes_used;
aster_memset(g_sector_buffer, 0, sizeof(g_sector_buffer));
aster_memcpy(g_sector_buffer, &super, sizeof(super));
if (ata_write_sector(ASTERFS_DISK_START_LBA, g_sector_buffer) != 0) {
return -1;
}
fs_encode_nodes(g_nodes_blob);
for (sector = 0; sector < ASTERFS_NODE_SECTORS; ++sector) {
usize off = (usize)sector * 512;
aster_memset(g_sector_buffer, 0, sizeof(g_sector_buffer));
if (off < sizeof(g_nodes_blob)) {
usize left = sizeof(g_nodes_blob) - off;
usize chunk = left < 512 ? left : 512;
aster_memcpy(g_sector_buffer, g_nodes_blob + off, chunk);
}
if (ata_write_sector(ASTERFS_DISK_START_LBA + 1U + sector, g_sector_buffer) != 0) {
return -1;
}
}
return 0;
}
static int fs_load_disk(void) {
asterfs_superblock_t super;
unsigned int sector;
if (!disk_ready) {
return -1;
}
if (ata_read_sector(ASTERFS_DISK_START_LBA, g_sector_buffer) != 0) {
return -1;
}
aster_memcpy(&super, g_sector_buffer, sizeof(super));
if (aster_strncmp(super.magic, ASTERFS_MAGIC, 8) != 0 || super.version != ASTERFS_VERSION) {
fs_reset_memory();
return fs_flush_disk();
}
for (sector = 0; sector < ASTERFS_NODE_SECTORS; ++sector) {
usize off = (usize)sector * 512;
if (ata_read_sector(ASTERFS_DISK_START_LBA + 1U + sector, g_sector_buffer) != 0) {
return -1;
}
if (off < sizeof(g_nodes_blob)) {
usize left = sizeof(g_nodes_blob) - off;
usize chunk = left < 512 ? left : 512;
aster_memcpy(g_nodes_blob + off, g_sector_buffer, chunk);
}
}
fs_decode_nodes(g_nodes_blob);
if (super.nodes_used > ASTERFS_MAX_FILES) {
nodes_used = ASTERFS_MAX_FILES;
} else {
nodes_used = (int)super.nodes_used;
}
return 0;
}
static int is_root(const char *path) {
return path && path[0] == '/' && path[1] == '\0';
}
static int path_parent_exists(const char *path) {
int i;
int last = -1;
char parent[ASTERFS_NAME_LEN];
if (!path || path[0] != '/') {
return 0;
}
for (i = 0; path[i] != '\0'; ++i) {
if (path[i] == '/') {
last = i;
}
}
if (last <= 0) {
return 1;
}
if ((usize)last >= ASTERFS_NAME_LEN) {
return 0;
}
aster_memcpy(parent, path, (usize)last);
parent[last] = '\0';
for (i = 0; i < nodes_used; ++i) {
if (nodes[i].is_dir && aster_strcmp(nodes[i].name, parent) == 0) {
return 1;
}
}
return 0;
}
static int path_is_child(const char *parent, const char *path, const char **leaf_start) {
usize parent_len;
const char *rest;
const char *p;
if (!parent || !path || path[0] != '/') {
return 0;
}
if (is_root(parent)) {
if (path[0] != '/' || path[1] == '\0') {
return 0;
}
rest = path + 1;
p = rest;
while (*p && *p != '/') {
++p;
}
if (*p != '\0') {
return 0;
}
*leaf_start = rest;
return 1;
}
parent_len = aster_strlen(parent);
if (aster_strncmp(path, parent, parent_len) != 0) {
return 0;
}
if (path[parent_len] != '/') {
return 0;
}
rest = path + parent_len + 1;
if (*rest == '\0') {
return 0;
}
p = rest;
while (*p && *p != '/') {
++p;
}
if (*p != '\0') {
return 0;
}
*leaf_start = rest;
return 1;
}
void storage_init(void) {
asterfs_init();
}
void asterfs_init(void) {
fs_reset_memory();
disk_ready = (ata_probe_slave() == 0);
if (!disk_ready) {
return;
}
if (fs_load_disk() != 0) {
fs_reset_memory();
(void)fs_flush_disk();
}
}
static int find_node(const char *name) {
int i;
for (i = 0; i < nodes_used; ++i) {
if (aster_strcmp(nodes[i].name, name) == 0) {
return i;
}
}
return -1;
}
int asterfs_create_file(const char *name) {
usize len;
if (!name || name[0] != '/' || nodes_used >= ASTERFS_MAX_FILES) {
return -1;
}
if (!path_parent_exists(name)) {
return -1;
}
if (find_node(name) >= 0) {
return 0;
}
len = aster_strlen(name);
if (len >= ASTERFS_NAME_LEN) {
return -1;
}
aster_memset(nodes[nodes_used].name, 0, ASTERFS_NAME_LEN);
aster_memcpy(nodes[nodes_used].name, name, len);
nodes[nodes_used].size = 0;
nodes[nodes_used].is_dir = 0;
++nodes_used;
(void)fs_flush_disk();
return 0;
}
int asterfs_create_dir(const char *name) {
usize len;
if (!name || name[0] != '/' || is_root(name) || nodes_used >= ASTERFS_MAX_FILES) {
return -1;
}
if (!path_parent_exists(name)) {
return -1;
}
if (find_node(name) >= 0) {
return 0;
}
len = aster_strlen(name);
if (len >= ASTERFS_NAME_LEN) {
return -1;
}
aster_memset(nodes[nodes_used].name, 0, ASTERFS_NAME_LEN);
aster_memcpy(nodes[nodes_used].name, name, len);
nodes[nodes_used].size = 0;
nodes[nodes_used].is_dir = 1;
++nodes_used;
(void)fs_flush_disk();
return 0;
}
int asterfs_remove_file(const char *name) {
int idx;
int i;
idx = find_node(name);
if (idx < 0 || nodes[idx].is_dir) {
return -1;
}
for (i = idx; i < nodes_used - 1; ++i) {
nodes[i] = nodes[i + 1];
}
--nodes_used;
(void)fs_flush_disk();
return 0;
}
int asterfs_remove_dir(const char *name) {
int idx;
int i;
const char *leaf;
if (is_root(name)) {
return -1;
}
idx = find_node(name);
if (idx < 0 || !nodes[idx].is_dir) {
return -1;
}
for (i = 0; i < nodes_used; ++i) {
if (i == idx) {
continue;
}
if (path_is_child(name, nodes[i].name, &leaf)) {
return -1;
}
}
for (i = idx; i < nodes_used - 1; ++i) {
nodes[i] = nodes[i + 1];
}
--nodes_used;
(void)fs_flush_disk();
return 0;
}
int asterfs_write_file(const char *name, const u8 *data, u16 len) {
int idx;
if (!name || !data || name[0] != '/') {
return -1;
}
idx = find_node(name);
if (idx < 0) {
if (asterfs_create_file(name) != 0) {
return -1;
}
idx = find_node(name);
}
if (idx < 0 || nodes[idx].is_dir) {
return -1;
}
if (len > ASTERFS_DATA_LEN) {
len = ASTERFS_DATA_LEN;
}
aster_memset(nodes[idx].data, 0, ASTERFS_DATA_LEN);
aster_memcpy(nodes[idx].data, data, len);
nodes[idx].size = len;
(void)fs_flush_disk();
return len;
}
int asterfs_read_file(const char *name, u8 *out, u16 max_len) {
int idx;
u16 len;
if (!name || !out || name[0] != '/') {
return -1;
}
idx = find_node(name);
if (idx < 0 || nodes[idx].is_dir) {
return -1;
}
len = nodes[idx].size;
if (len > max_len) {
len = max_len;
}
aster_memcpy(out, nodes[idx].data, len);
return len;
}
void asterfs_list(void (*cb)(const char *name, u8 is_dir, u16 size)) {
int i;
for (i = 0; i < nodes_used; ++i) {
cb(nodes[i].name, nodes[i].is_dir, nodes[i].size);
}
}
int asterfs_get_type(const char *name) {
int idx;
if (is_root(name)) {
return 1;
}
idx = find_node(name);
if (idx < 0) {
return -1;
}
return nodes[idx].is_dir ? 1 : 0;
}
void asterfs_list_dir(const char *path, void (*cb)(const char *name, u8 is_dir, u16 size)) {
int i;
const char *leaf = 0;
char temp[ASTERFS_NAME_LEN];
usize n;
for (i = 0; i < nodes_used; ++i) {
if (!path_is_child(path, nodes[i].name, &leaf)) {
continue;
}
n = aster_strlen(leaf);
if (n >= ASTERFS_NAME_LEN) {
n = ASTERFS_NAME_LEN - 1;
}
aster_memcpy(temp, leaf, n);
temp[n] = '\0';
cb(temp, nodes[i].is_dir, nodes[i].size);
}
}
+83
View File
@@ -0,0 +1,83 @@
/*
* AsterOS Kernel
* Autor: Pavel Kalaš
* Rok: 2026
*
*/
/*
* Tento soubor implementuje ovladac PIT casovace.
* Nastavuje frekvenci hardwaroveho casovace, drzi globalni citac tiku
* a poskytuje blokujici uspani jadra na zadany pocet milisekund.
*/
#include "timer.h"
static volatile unsigned long g_ticks = 0;
static inline unsigned long long read_tsc(void) {
unsigned int lo;
unsigned int hi;
__asm__ volatile ("rdtsc" : "=a"(lo), "=d"(hi));
return ((unsigned long long)hi << 32) | (unsigned long long)lo;
}
static int interrupts_enabled(void) {
unsigned long long rflags;
__asm__ volatile ("pushfq; popq %0" : "=r"(rflags));
return (rflags & (1ULL << 9)) != 0;
}
static void busy_delay_ms(unsigned long ms) {
unsigned long long start = read_tsc();
unsigned long long wait_cycles = (unsigned long long)ms * 1000000ULL;
unsigned long long end = start + wait_cycles;
while (read_tsc() < end) {
__asm__ volatile ("pause");
}
}
static inline void outb(unsigned short port, unsigned char value) {
__asm__ volatile ("outb %0, %1" : : "a"(value), "Nd"(port));
}
void timer_init(unsigned int hz) {
unsigned int divisor;
if (hz == 0) {
hz = 100;
}
divisor = 1193180U / hz;
outb(0x43, 0x36);
outb(0x40, (unsigned char)(divisor & 0xFF));
outb(0x40, (unsigned char)((divisor >> 8) & 0xFF));
}
unsigned long timer_ticks(void) {
return g_ticks;
}
void timer_tick_advance(void) {
++g_ticks;
}
void timer_sleep_ms(unsigned long ms) {
if (!interrupts_enabled()) {
busy_delay_ms(ms);
return;
}
unsigned long start = timer_ticks();
unsigned long wait_ticks = (ms + 9UL) / 10UL;
if (wait_ticks == 0) {
wait_ticks = 1;
}
while ((timer_ticks() - start) < wait_ticks) {
__asm__ volatile ("hlt");
}
}