Skip to content

Commit

Permalink
ATA PIO: ATA write hotfix (#159)
Browse files Browse the repository at this point in the history
  • Loading branch information
pimnik98 authored Oct 11, 2024
2 parents d6f5823 + ba89236 commit 709a9e5
Show file tree
Hide file tree
Showing 9 changed files with 103 additions and 72 deletions.
3 changes: 1 addition & 2 deletions common.mk
Original file line number Diff line number Diff line change
Expand Up @@ -256,8 +256,7 @@ QEMU_FLAGS = $(QEMU_BASE_FLAGS) \
-netdev user,id=net0,net=192.168.111.0,dhcpstart=192.168.111.128,hostfwd=tcp::9999-:9999 \
-device rtl8139,netdev=net0,id=mydev0 \
-M pcspk-audiodev=pa0 \
-device ich9-intel-hda,debug=0 \
-device hda-output,audiodev=pa0 \
-device ac97,audiodev=pa0 \
-trace "hda*" \
-device ich9-usb-uhci1 \
-drive file=disk.img,id=disk0,if=none \
Expand Down
2 changes: 1 addition & 1 deletion config.mk
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
DEBUG?=# -ggdb3 #-Werror
MEMORY_SIZE?=128M
MEMORY_SIZE?=256M
USE_SSE?=true
OPTIMIZATION_LEVEL?=0
6 changes: 2 additions & 4 deletions kernel/include/drv/audio/ac97.h
Original file line number Diff line number Diff line change
Expand Up @@ -42,14 +42,12 @@ void ac97_set_master_volume(uint8_t left, uint8_t right, bool mute);
// Volume in dB, not %
void ac97_set_pcm_volume(uint8_t right, uint8_t left, bool mute);
void ac97_set_pcm_sample_rate(uint16_t sample_rate);
void ac97_load_data(char* data, uint32_t length);
void ac97_reset_channel();
void ac97_clear_status_register();
void ac97_update_bdl();
void ac97_update_lvi(uint8_t index);
void ac97_set_play_sound(bool play);
void ac97_init();
size_t ac97_copy_user_memory_to_dma(const char* data, size_t length);
void ac97_single_page_write_wait(size_t page_num);
void ac97_destroy_user_buffer();
void ac97_FillBDLs();
void ac97_WriteAll(void* buffer, size_t size);
bool ac97_is_initialized();
4 changes: 3 additions & 1 deletion kernel/include/drv/disk/ata.h
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,8 @@ typedef struct {
void ide_select_drive(uint8_t bus, bool slave);
void ide_400ns_delay(uint16_t io);
void ide_poll(uint16_t io);
bool ide_poll_drq(uint16_t io);
bool ide_poll_bsy(uint16_t io);

void ata_read(uint8_t drive, uint8_t* buf, uint32_t location, uint32_t length) ;
void ata_write(uint8_t drive, const uint8_t* buf, size_t location, size_t length);
Expand All @@ -148,4 +150,4 @@ static inline void ata_set_params(uint8_t drive, uint16_t* io, uint8_t* real_dri
*io = ATA_SECONDARY_IO;

*real_drive = _drv;
}
}
4 changes: 1 addition & 3 deletions kernel/include/elf/elf.h
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,6 @@ typedef struct
Elf32_Half e_shentsize; ///< Размер записи заголовка раздела
Elf32_Half e_shnum; ///< Количество записей в заголовке раздела
Elf32_Half e_shstrndx; ///< ...

} Elf32_Ehdr;

/*-----------------------------------------------------------------------------
Expand Down Expand Up @@ -133,7 +132,6 @@ typedef struct
Elf32_Word p_memsz; ///< ...
Elf32_Word p_flags; ///< Флаги
Elf32_Word p_align; ///< Отступ

} Elf32_Phdr;

typedef struct elf_sections
Expand Down Expand Up @@ -166,4 +164,4 @@ static inline bool is_elf_file(FILE* fp) {
kfree(temp);

return result;
}
}
113 changes: 65 additions & 48 deletions kernel/src/drv/audio/ac97.c
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,10 @@ __attribute__((aligned(PAGE_SIZE))) AC97_BDL_t ac97_buffer[32];
char* ac97_audio_buffer = 0;
size_t ac97_audio_buffer_phys;

size_t ac97_lvi = 0;

#define AUDIO_BUFFER_SIZE (128 * KB)

// Volume in dB, not % (max 64)
void ac97_set_master_volume(uint8_t left, uint8_t right, bool mute) {
const uint16_t value = (right & 63) << 0
Expand Down Expand Up @@ -153,12 +157,11 @@ void ac97_init() {
// ac97_global_status_t* statusptr = &status;

const uint32_t status = inl(native_audio_bus_master + NABM_GLOBAL_STATUS);
qemu_log("Status: %x", status);

// qemu_log("Status: %d (%x)\n", status, status);
// qemu_log("Status Reserved: %d\n", status.reserved);
// qemu_log("Status Channels: %d\n", (status.channel==0?2:(status.channel==1?4:(status.channel==2?6:0))));
// qemu_log("Status Samples: %s\n", status.sample==1?"16 and 20 bits":"only 16 bits");
qemu_log("Status: %d (%x)\n", status, status);
// qemu_log("Status Reserved: %d\n", status.reserved);
// qemu_log("Status Channels: %d\n", (status.channel==0?2:(status.channel==1?4:(status.channel==2?6:0))));
// qemu_log("Status Samples: %s\n", status.sample==1?"16 and 20 bits":"only 16 bits");

// */

Expand All @@ -178,8 +181,14 @@ void ac97_init() {
ac97_set_master_volume(0, 0, false);
ac97_set_pcm_volume(0, 0, false);

ac97_audio_buffer = kmalloc_common(AUDIO_BUFFER_SIZE, PAGE_SIZE);
ac97_audio_buffer_phys = virt2phys(get_kernel_page_directory(),
(virtual_addr_t)ac97_audio_buffer);

qemu_log("Updated capabilities\n");

ac97_FillBDLs();

ac97_initialized = true;

qemu_log("AC'97 initialized successfully!");
Expand All @@ -189,58 +198,68 @@ bool ac97_is_initialized() {
return ac97_initialized;
}

size_t ac97_copy_user_memory_to_dma(const char* data, size_t length) {
currently_pages_count = length / PAGE_SIZE;
void ac97_FillBDLs() {
size_t sample_divisor = 2;
// We need to fill ALL BDL entries.
// If we don't do that, we can encounter lags and freezes, because DMA doesn't stop
// even when its read pointer reached the end marker. (It will scroll to the end)
// So we need to spread buffer on BDL array

ac97_audio_buffer = kmalloc_common(length, PAGE_SIZE);
ac97_audio_buffer_phys = virt2phys(get_kernel_page_directory(), (virtual_addr_t) ac97_audio_buffer);
size_t bdl_span = AUDIO_BUFFER_SIZE / 32; // It's the size of each transfer (32 is the count of BDLs)

memcpy(ac97_audio_buffer, data, length);
size_t filled = 0;
for (size_t j = 0; j < AUDIO_BUFFER_SIZE; j += bdl_span) {
ac97_buffer[filled].memory_pos = (void*)(ac97_audio_buffer_phys + j);
ac97_buffer[filled].sample_count = (bdl_span / sample_divisor) + 2;

qemu_log("Made user buffer with %d pages on a board", currently_pages_count);
// LOG("[%d] %x; %x", filled, ac97_data_buffer.second[filled].memory_pos, ac97_data_buffer.second[filled].sample_count);
filled++;
}

return currently_pages_count;
}
qemu_log("Fills: %d", filled);

void ac97_destroy_user_buffer() {
// if(!physpages_ac97)
// return;
//
// for (size_t i = 0; i < currently_pages_count; i++) {
// phys_free_single_page(physpages_ac97[i]);
// }

// memset(physpages_ac97, 0, sizeof(size_t) * currently_pages_count);
// kfree(physpages_ac97);
kfree(ac97_audio_buffer);
filled--;

currently_pages_count = 0;
// physpages_ac97 = 0;
ac97_buffer[filled].flags = (1 << 14) | (1 << 15);

ac97_update_bdl();
ac97_update_lvi(filled);

qemu_log("Destroyed buffer");
ac97_lvi = filled;
}

void ac97_single_page_write_wait(size_t page_num) {
size_t remaining_pages = currently_pages_count - page_num;
for (size_t j = 0; j < MIN(remaining_pages, 32); j++) {
// ac97_buffer[j].memory_pos = physpages_ac97[(remaining_pages) + j];
ac97_buffer[j].memory_pos = (void *) (ac97_audio_buffer_phys + ((page_num + j) * PAGE_SIZE));
ac97_buffer[j].sample_count = PAGE_SIZE / 2;
}
void ac97_WriteAll(void* buffer, size_t size) {
qemu_log("Start");

ac97_buffer[remaining_pages >= 31 ? 31 : remaining_pages].flags = 1 << 14;
size_t loaded = 0;

ac97_update_bdl();
ac97_update_lvi(remaining_pages >= 31 ? 31 : remaining_pages);

ac97_set_play_sound(true);
ac97_clear_status_register();
for(; loaded < size; loaded += AUDIO_BUFFER_SIZE) {
size_t block_size = MIN(size - loaded, AUDIO_BUFFER_SIZE);

memcpy(ac97_audio_buffer,
(char*)buffer + loaded,
block_size);

if (block_size < AUDIO_BUFFER_SIZE) {
memset((char *) ac97_audio_buffer + block_size,
0,
AUDIO_BUFFER_SIZE - block_size);
}

while(inb(native_audio_bus_master + 0x16) == 0) {}
ac97_update_lvi(ac97_lvi);

memset(&ac97_buffer, 0, sizeof(AC97_BDL_t)*31);
ac97_set_play_sound(true);
ac97_clear_status_register();

while ((inb(native_audio_bus_master + 0x16) & (1 << 1)) == 0) {
__asm__ volatile("nop");
}
}

qemu_log("Finish");
}


void ac97_test() {
FILE* file = fopen("R:\\Sayori\\a.wav", "rb");
fseek(file, 0, SEEK_END);
Expand All @@ -252,22 +271,20 @@ void ac97_test() {
char* data = kmalloc(filesize);
fread(file, filesize, 1, data);

size_t page_count = ac97_copy_user_memory_to_dma(data, filesize);
// size_t page_count = ac97_copy_user_memory_to_dma(data, filesize);

qemu_log("Allocated %d pages for user memory in DMA", page_count);
// qemu_log("Allocated %d pages for user memory in DMA", page_count);

ac97_set_master_volume(2, 2, false);
ac97_set_pcm_volume(2, 2, false);

for(ssize_t i = 0; i < page_count; i += 32) {
ac97_single_page_write_wait(i);
}
ac97_WriteAll(data, filesize);

qemu_log("Exiting");
ac97_reset_channel();

kfree(data);
fclose(file);

ac97_destroy_user_buffer();
// ac97_destroy_user_buffer();
}
25 changes: 23 additions & 2 deletions kernel/src/drv/disk/ata.c
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,28 @@
const char possible_dpm_letters_for_ata[4] = "CDEF";
ata_drive_t drives[4] = {0};

bool ide_poll_drq(uint16_t io) {
while(1) {
uint8_t status = inb(io + ATA_REG_STATUS);
if(status & ATA_SR_DRQ) {
return true;
} else if ((status & ATA_SR_ERR) || (status & ATA_SR_DF)) {
return false;
}
}
}

bool ide_poll_bsy(uint16_t io) {
while(1) {
uint8_t status = inb(io + ATA_REG_STATUS);
if(!(status & ATA_SR_BSY)) {
return true;
} else if ((status & ATA_SR_ERR) || (status & ATA_SR_DF)) {
return false;
}
}
}

void ide_select_drive(uint8_t bus, bool slave) {
if(bus == ATA_PRIMARY)
outb(ATA_PRIMARY_IO + ATA_REG_HDDEVSEL, (0xA0 | ((uint8_t)slave << 4)));
Expand Down Expand Up @@ -182,7 +204,6 @@ uint8_t ide_identify(uint8_t bus, uint8_t drive) {

if (disk_inx < 0){
qemu_err("[ATA] [DPM] [ERROR] An error occurred during disk registration, error code: %d",disk_inx);

} else {
qemu_ok("[ATA] [DPM] [Successful] [is_packet: %d] Your disk index: %d",drives[drive_num].is_packet, disk_inx);
dpm_fnc_write(disk_inx + 65, &dpm_ata_read, &dpm_ata_write);
Expand All @@ -198,7 +219,7 @@ uint8_t ide_identify(uint8_t bus, uint8_t drive) {
}

/* Now, poll until BSY is clear. */
while((status & ATA_SR_BSY) != 0){
while((status & ATA_SR_BSY) != 0){
qemu_log("Got status %x", status);
if(status & ATA_SR_ERR) {
qemu_log("%s %s has ERR set. Disabled.", PRIM_SEC(bus), MAST_SLV(drive));
Expand Down
7 changes: 5 additions & 2 deletions kernel/src/drv/disk/ata_pio.c
Original file line number Diff line number Diff line change
Expand Up @@ -134,15 +134,18 @@ uint8_t ata_pio_write_raw_sector(uint8_t drive, const uint8_t *buf, uint32_t lba
outb(io + ATA_REG_LBA2, (uint8_t)((lba) >> 16));
outb(io + ATA_REG_COMMAND, ATA_CMD_WRITE_PIO);

ide_poll(io);
ide_poll_drq(io);

for(int i = 0; i < 256; i++) {
outw(io + ATA_REG_DATA, *(uint16_t*)(buf + i * 2));
ide_400ns_delay(io);
}

ide_400ns_delay(io);

outb(io + ATA_REG_COMMAND, ATA_CMD_CACHE_FLUSH);

ide_poll_bsy(io);

return 1;
}

Expand Down
11 changes: 2 additions & 9 deletions kernel/src/toys/miniplay.c
Original file line number Diff line number Diff line change
Expand Up @@ -94,8 +94,7 @@ uint32_t miniplay(uint32_t argc, char* args[]) {

set_cursor_enabled(false);

miniplay_pages_total = ac97_copy_user_memory_to_dma(data, miniplay_filesize);

// Thread.
thread_t* display_thread = thread_create(get_current_proc(), miniplay_display, 0x1000, true, false);

ac97_set_pcm_sample_rate(miniplay_hdr.sampleRate);
Expand All @@ -105,19 +104,13 @@ uint32_t miniplay(uint32_t argc, char* args[]) {

miniplay_timestamp = timestamp();

for(miniplay_pages_played = 0;
miniplay_pages_played < miniplay_pages_total;
miniplay_pages_played += 32) {
ac97_single_page_write_wait(miniplay_pages_played);
}
ac97_WriteAll(data, miniplay_filesize);

ac97_reset_channel();

kfree(data);
fclose(file);

ac97_destroy_user_buffer();

thread_exit(display_thread);

clean_tty_screen();
Expand Down

0 comments on commit 709a9e5

Please sign in to comment.