Skip to content

Commit 5e4b575

Browse files
committed
feat: fully realize ATA PIO driver, add disk img creation in makefile
1 parent 3a74eb1 commit 5e4b575

File tree

7 files changed

+339
-189
lines changed

7 files changed

+339
-189
lines changed

CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,9 @@
1+
commit 3a74eb131a365ecca0b4c54689f545a459e6fa39
2+
Author: Alexeev Bronislav <[email protected]>
3+
Date: Fri Aug 29 22:02:52 2025 +0700
4+
5+
fix codestyle
6+
17
commit a7fc4dba0e193a9a8e9db88c089c4f612aaf133f
28
Author: Alexeev Bronislav <[email protected]>
39
Date: Fri Aug 29 00:13:29 2025 +0700

Makefile

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ SRC_DIR = src
99
BIN_DIR = bin
1010
DISKIMG_DIR = diskimgs
1111
DISKIMG_NAME = kintsugi_floppy_i386.img
12+
HDDIMG_NAME = kintsugi_hdd_i386.img
1213

1314
CFLAGS = -g -m32 -nostdlib -nostdinc -fno-builtin -fno-stack-protector -nostartfiles -nodefaultlibs -Wall -Wextra -ffreestanding -I$(SRC_DIR)/kernel/include
1415
ASMFLAGS_BIN = -f bin
@@ -57,28 +58,43 @@ $(BIN_DIR)/%.o: $(SRC_DIR)/%.c
5758
@$(CC) $(CFLAGS) -c $< -o $@
5859

5960
$(DISKIMG_DIR)/$(DISKIMG_NAME): $(BIN_DIR)/kintsugios.bin
60-
@printf "$(BLUE)[DD] Make IMG %-50s -> %s$(RESET)\n" "$(BIN_DIR)/kintsugios.bin" "$@"
61+
@printf "$(BLUE)[DD] Make Floppy IMG %-50s -> %s$(RESET)\n" "$(BIN_DIR)/kintsugios.bin" "$@"
6162
@mkdir -p $(DISKIMG_DIR)
6263
@dd if=/dev/zero of=$@.tmp bs=1024 count=1440
6364
@dd if=$< of=$@.tmp conv=notrunc
6465
@mv $@.tmp $@
6566

67+
$(DISKIMG_DIR)/$(HDDIMG_NAME):
68+
@printf "$(BLUE)[DD] Make HDD IMG %-50s -> %s$(RESET)\n" "empty disk" "$@"
69+
@mkdir -p $(DISKIMG_DIR)
70+
@dd if=/dev/zero of=$@ bs=512 count=10000 # ~5MB disk
71+
6672
diskimg: $(DISKIMG_DIR)/$(DISKIMG_NAME)
6773

74+
hddimg: $(DISKIMG_DIR)/$(HDDIMG_NAME)
75+
6876
run_bin: $(BIN_DIR)/kintsugios.bin
6977
@printf "$(GREEN)[QEMU] Run bin %-50s$(RESET)\n" "$(BIN_DIR)/kintsugios.bin"
7078
@qemu-system-i386 -fda $(BIN_DIR)/kintsugios.bin
7179

72-
run: $(DISKIMG_DIR)/$(DISKIMG_NAME)
80+
run_fda: $(DISKIMG_DIR)/$(DISKIMG_NAME)
7381
@printf "$(GREEN)[QEMU] Run img %-50s$(RESET)\n" "$<"
7482
@qemu-system-i386 -fda $< -boot a -m 16
7583

76-
debug: $(DISKIMG_DIR)/$(DISKIMG_NAME)
84+
run: $(DISKIMG_DIR)/$(DISKIMG_NAME) $(DISKIMG_DIR)/$(HDDIMG_NAME)
85+
@printf "$(GREEN)[QEMU] Run with HDD %-50s$(RESET)\n" "$<"
86+
@qemu-system-i386 -fda $< -hda $(DISKIMG_DIR)/$(HDDIMG_NAME) -boot a -m 16
87+
88+
debug_fda: $(DISKIMG_DIR)/$(DISKIMG_NAME)
7789
@printf "$(GREEN)[QEMU] Debug img %-50s$(RESET)\n" "$<"
7890
@qemu-system-i386 -fda $< -boot a -s -S -m 16
7991

92+
debug: $(DISKIMG_DIR)/$(DISKIMG_NAME) $(DISKIMG_DIR)/$(HDDIMG_NAME)
93+
@printf "$(GREEN)[QEMU] Debug with HDD %-50s$(RESET)\n" "$<"
94+
@qemu-system-i386 -fda $< -hda $(DISKIMG_DIR)/$(HDDIMG_NAME) -boot a -s -S -m 16
95+
8096
clean:
8197
@printf "$(RED)[RM] Clean $(BIN_DIR) and $(DISKIMG_DIR)$(RESET)\n"
8298
@rm -rf $(BIN_DIR)/* $(DISKIMG_DIR)/*
8399

84-
.PHONY: all diskimg run run_bin debug clean clean_all
100+
.PHONY: all diskimg hddimg run run_bin run_hdd debug debug_hdd clean

src/kernel/drivers/ata_pio.c

Lines changed: 181 additions & 88 deletions
Original file line numberDiff line numberDiff line change
@@ -1,121 +1,214 @@
1-
#include "ata_pio.h"
1+
/*------------------------------------------------------------------------------
2+
* Kintsugi OS Drivers source code
3+
* File: kernel/drivers/ata_pio.c
4+
* Title: Драйвер ATA PIO
5+
* Description: Реализация драйвера для работы с жесткими дисками через PIO mode.
6+
* ---------------------------------------------------------------------------*/
27

8+
#include "ata_pio.h"
39
#include "lowlevel_io.h"
10+
#include "../kklibc/kklibc.h"
411
#include "screen.h"
512

6-
// Источник: https://wiki.osdev.org/ATA_PIO_Mode
13+
// внутреннее API ядра
14+
static void ata_pio_select_drive(u8 drive);
15+
static void ata_pio_set_lba(u32 lba, u8 drive);
716

8-
static void ata_wait_ready() {
9-
while (port_byte_in(ATA_REG_STATUS) & ATA_SR_BSY)
10-
;
11-
}
17+
// глобал переменные для хранения информации о дисках
18+
ata_disk_info_t ata_disks[2]; // 0 - master, 1 - slave
1219

13-
static void ata_cache_flush() {
14-
ata_wait_ready();
15-
port_byte_out(ATA_REG_COMMAND, ATA_CMD_CACHE_FLUSH);
16-
ata_wait_ready();
17-
}
20+
// внешнее api ядра
1821

19-
void ata_read_sectors(u32 lba, u32 sector_count, const u8* buffer) {
20-
ata_wait_ready();
22+
void ata_pio_init() {
23+
kprint("Initializing ATA PIO driver...\n");
2124

22-
// Выбор диска (Master)
23-
port_byte_out(ATA_REG_DRIVE_SELECT, 0xE0 | ((lba >> 24) & 0x0F));
25+
for (int i = 0; i < 2; i++) {
26+
u8 drive = (i == 0) ? ATA_MASTER : ATA_SLAVE;
2427

25-
// Задержка для стабилизации контроллера
26-
port_byte_out(ATA_REG_ERROR, 0x00);
28+
// чекаем наличие устройства
29+
ata_pio_select_drive(drive);
30+
u8 status = port_byte_in(ATA_PRIMARY_STATUS);
2731

28-
port_byte_out(ATA_REG_SECCOUNT, sector_count); // Количество секторов для чтения
29-
port_byte_out(ATA_REG_LBA0, (u8)(lba & 0xFF));
30-
port_byte_out(ATA_REG_LBA1, (u8)((lba >> 8) & 0xFF));
31-
port_byte_out(ATA_REG_LBA2, (u8)((lba >> 16) & 0xFF));
32-
port_byte_out(ATA_REG_COMMAND, ATA_CMD_READ_SECTORS);
32+
if (status == 0xFF) {
33+
printf("Drive %d: no device connected\n", i);
34+
continue;
35+
}
3336

34-
ata_wait_ready();
37+
int result = ata_pio_identify(drive, &ata_disks[i]);
3538

36-
for (u8 sector = 0; sector < sector_count; sector++) {
37-
while (!(port_byte_in(ATA_REG_STATUS) & ATA_SR_DRQ))
38-
;
39-
// ПРИМЕЧАНИЕ: При чтении слов в little-endian порядок байт сохраняется корректно
40-
rep_insw(
41-
ATA_REG_DATA, (void*)(&buffer[sector * SECTOR_BYTES]), SECTOR_WORDS); // 256 слов (512 байт)
42-
}
43-
}
44-
45-
void ata_write_sectors(u32 lba, u32 sector_count, const u8* buffer) {
46-
ata_wait_ready();
47-
48-
// Выбор диска (Master)
49-
port_byte_out(ATA_REG_DRIVE_SELECT, 0xE0 | ((lba >> 24) & 0x0F));
50-
51-
// Задержка для стабилизации контроллера
52-
port_byte_out(ATA_REG_ERROR, 0x00);
53-
54-
port_byte_out(ATA_REG_SECCOUNT, (u8)sector_count); // Количество секторов для записи
55-
port_byte_out(ATA_REG_LBA0, (u8)(lba & 0xFF));
56-
port_byte_out(ATA_REG_LBA1, (u8)((lba >> 8) & 0xFF));
57-
port_byte_out(ATA_REG_LBA2, (u8)((lba >> 16) & 0xFF));
58-
port_byte_out(ATA_REG_COMMAND, ATA_CMD_WRITE_SECTORS);
59-
60-
for (u8 sector = 0; sector < sector_count; sector++) {
61-
while (!(port_byte_in(ATA_REG_STATUS) & ATA_SR_DRQ))
62-
;
63-
for (u32 sw = 0; sw < SECTOR_WORDS; sw++) {
64-
// Преобразование в big-endian для контроллера
65-
outsw(ATA_REG_DATA,
66-
((u16)buffer[sector * SECTOR_BYTES + sw * 2 + 1]) << 8
67-
| (u16)(buffer[sector * SECTOR_BYTES + sw * 2]));
39+
if (result == 0) {
40+
printf("Drive %d: %s %d MB\n", i, ata_disks[i].model,
41+
(ata_disks[i].size * 512) / (1024 * 1024));
42+
} else {
43+
printf("Drive %d: identification failed (error %d)\n", i, result);
6844
}
6945
}
46+
}
7047

71-
ata_cache_flush();
48+
static void ata_pio_select_drive(u8 drive) {
49+
// выюор диска (master/slave) и режима LBA
50+
port_byte_out(ATA_PRIMARY_DRIVE_SEL, drive | 0x40); // LBA mode
51+
// задержка для стабильности
52+
for (int i = 0; i < 4; i++) port_byte_in(ATA_PRIMARY_STATUS);
7253
}
7354

74-
void ata_select_drive(int is_master) {
75-
port_byte_out(ATA_REG_DRIVE_SELECT, is_master ? 0xA0 : 0xB0);
55+
static void ata_pio_set_lba(u32 lba, u8 drive) {
56+
// установочка LBA адреса
57+
port_byte_out(ATA_PRIMARY_LBA_LOW, (u8)(lba & 0xFF));
58+
port_byte_out(ATA_PRIMARY_LBA_MID, (u8)((lba >> 8) & 0xFF));
59+
port_byte_out(ATA_PRIMARY_LBA_HIGH, (u8)((lba >> 16) & 0xFF));
60+
port_byte_out(ATA_PRIMARY_DRIVE_SEL, drive | 0x40 | ((lba >> 24) & 0x0F));
7661
}
7762

78-
void ata_identify() {
79-
ata_select_drive(1); // Выбор master-диска
63+
int ata_pio_wait() {
64+
// ожидаем снятия флага BSY и установки флага DRDY
65+
int timeout = 100000; // таймаут для предотвращения зависания
8066

81-
port_byte_out(ATA_REG_SECCOUNT, 0);
82-
port_byte_out(ATA_REG_LBA0, 0);
83-
port_byte_out(ATA_REG_LBA1, 0);
84-
port_byte_out(ATA_REG_LBA2, 0);
85-
port_byte_out(ATA_REG_COMMAND, ATA_CMD_IDENTIFY);
86-
}
67+
while (timeout-- > 0) {
68+
u8 status = port_byte_in(ATA_PRIMARY_STATUS);
8769

88-
int ata_wait() {
89-
while (1) {
90-
u8 status = port_byte_in(ATA_REG_STATUS);
91-
if (!(status & 0x80)) {
92-
return 1; // Проверка бита BSY (занято)
70+
// коли BSY снят и DRDY установлен - диск готов
71+
if (!(status & ATA_SR_BSY) && (status & ATA_SR_DRDY)) {
72+
return 0;
73+
}
74+
75+
// произошла ошибка
76+
if (status & ATA_SR_ERR) {
77+
return -1;
9378
}
9479
}
80+
81+
return -2; // таймаут
9582
}
9683

97-
void ata_read_buffer(u16* buffer) {
98-
// Чтение всего сектора: 256 слов, 512 байт
84+
int ata_pio_identify(u8 drive, ata_disk_info_t* info) {
85+
ata_pio_select_drive(drive);
86+
87+
u8 status = port_byte_in(ATA_PRIMARY_STATUS);
88+
if (status == 0xFF) {
89+
// нет устройства на этом канале
90+
return -3;
91+
}
92+
93+
// ожидаем готовности диска
94+
if (ata_pio_wait() != 0) {
95+
return -1;
96+
}
97+
98+
// отправляем IDENTIFY
99+
port_byte_out(ATA_PRIMARY_CMD, ATA_CMD_IDENTIFY);
100+
101+
// ждем ответа
102+
if (ata_pio_wait() != 0) {
103+
return -2;
104+
}
105+
106+
// процесс чтения данных (256 слов = 512 байт)
107+
u16 buffer[256];
99108
for (int i = 0; i < 256; i++) {
100-
buffer[i] = port_word_in(ATA_REG_DATA);
109+
buffer[i] = port_word_in(ATA_PRIMARY_DATA);
110+
}
111+
112+
// анализируем полученные данные
113+
info->signature = buffer[0];
114+
info->capabilities = buffer[49];
115+
info->command_sets = *((u32*)&buffer[83]);
116+
117+
// получаем модель диска
118+
for (int i = 0; i < 20; i++) {
119+
info->model[i * 2] = (char)(buffer[27 + i] >> 8);
120+
info->model[i * 2 + 1] = (char)(buffer[27 + i] & 0xFF);
121+
}
122+
info->model[40] = '\0';
123+
124+
// размер диска в секторах
125+
if (info->command_sets & 0x40000000) {
126+
// 48-bit LBA
127+
info->size = *((u32*)&buffer[100]);
128+
} else {
129+
// 28-bit LBA
130+
info->size = *((u32*)&buffer[60]);
101131
}
102-
}
103132

104-
u32 ata_get_disk_size() {
105-
// 1024^2 = 1048576 (1 МиБ)
106-
u16 ata_buffer[256];
107-
ata_identify();
108-
ata_wait();
109-
ata_read_buffer(ata_buffer);
110-
u32 total_sectors = ((u32)ata_buffer[61] << 16) | ata_buffer[60];
111-
return (u32)total_sectors * 512; // Конвертация в байты
133+
// тип диска
134+
if (buffer[0] == 0x8489 || buffer[0] == 0x8449) {
135+
info->type = ATA_DISK_PATAPI;
136+
} else {
137+
info->type = ATA_DISK_PATA;
138+
}
139+
140+
return 0;
112141
}
113142

114-
void ata_read_blocks(u32 block_num, const u8* buffer, u32 count) {
115-
ata_read_sectors(block_num * SECTORS_PER_BLOCK, SECTORS_PER_BLOCK * count, buffer);
143+
int ata_pio_read_sectors(u8 drive, u32 lba, u8 num, u16* buffer) {
144+
if (num == 0) return 0;
145+
146+
// выбор диск
147+
ata_pio_select_drive(drive);
148+
149+
// колво количество секторов
150+
port_byte_out(ATA_PRIMARY_SECTOR_CNT, num);
151+
152+
// сетаем LBA адрес
153+
ata_pio_set_lba(lba, drive);
154+
155+
// сендим команду чтения
156+
port_byte_out(ATA_PRIMARY_CMD, ATA_CMD_READ_PIO);
157+
158+
// Читаем сектора
159+
for (int sector = 0; sector < num; sector++) {
160+
// Ждем готовности данных
161+
if (ata_pio_wait() != 0) {
162+
return -1;
163+
}
164+
165+
// Читаем сектор (256 слов = 512 байт)
166+
for (int i = 0; i < 256; i++) {
167+
buffer[sector * 256 + i] = port_word_in(ATA_PRIMARY_DATA);
168+
}
169+
170+
// ждем между секторами
171+
for (int i = 0; i < 4; i++) port_byte_in(ATA_PRIMARY_STATUS);
172+
}
173+
174+
return 0;
116175
}
117176

118-
// неэффективные методы: запись происходит поверх буфера без учета длины
119-
void ata_write_blocks(u32 block_num, const u8* buffer, u32 count) {
120-
ata_write_sectors(block_num * SECTORS_PER_BLOCK, SECTORS_PER_BLOCK * count, buffer);
177+
int ata_pio_write_sectors(u8 drive, u32 lba, u8 num, u16* buffer) {
178+
if (num == 0) return 0;
179+
180+
// диск
181+
ata_pio_select_drive(drive);
182+
183+
// количество секторов
184+
port_byte_out(ATA_PRIMARY_SECTOR_CNT, num);
185+
186+
// LBA адрес
187+
ata_pio_set_lba(lba, drive);
188+
189+
// команда записи
190+
port_byte_out(ATA_PRIMARY_CMD, ATA_CMD_WRITE_PIO);
191+
192+
// врайтим сектора
193+
for (int sector = 0; sector < num; sector++) {
194+
// ждем готовности к приему данных
195+
if (ata_pio_wait() != 0) {
196+
return -1;
197+
}
198+
199+
// сектор (256 слов = 512 байт)
200+
for (int i = 0; i < 256; i++) {
201+
port_word_out(ATA_PRIMARY_DATA, buffer[sector * 256 + i]);
202+
}
203+
204+
// оиждаем завершения записи
205+
if (ata_pio_wait() != 0) {
206+
return -2;
207+
}
208+
209+
port_byte_out(ATA_PRIMARY_CMD, ATA_CMD_CACHE_FLUSH);
210+
ata_pio_wait(); //
211+
}
212+
213+
return 0;
121214
}

0 commit comments

Comments
 (0)