Compare commits

...

3 Commits

Author SHA1 Message Date
59713279a0
kernel: Add a hexdump() method to log binary data for debugging
All checks were successful
Build and test / build (push) Successful in 1m33s
2024-03-29 12:12:56 +01:00
6443ec77f8
kernel/ATA: Add support for regular ATA drives (non-ATAPI)
Don't know why this took so long to figure out, I just had to pass the right value to select().
2024-03-29 12:11:39 +01:00
86372a3893
Update README.md 2024-03-28 22:37:16 +01:00
5 changed files with 133 additions and 32 deletions

View File

@ -38,17 +38,11 @@ Additionally, the build process needs some extra dependencies to run: `cmake`, `
`tools/run.sh` is the script you should use in most cases. It will build changed files, install, make an ISO image, and run Luna in QEMU.
If you have no toolchain set up, `run.sh` will build it automatically, which means that you don't necessarily have to run `setup.sh` since `run.sh` does it for you.
If you have no toolchain set up, `run.sh` will build it automatically, which means that you don't necessarily have to run `setup.sh` manually since `run.sh` does it for you.
## Prebuilt images
Prebuilt ISO images (numbered) for every version can be found at [pub.cloudapio.eu](https://pub.cloudapio.eu/luna/releases).
These images are built manually whenever a new release is created, and thus don't reflect the latest changes on the `main` branch.
Every hour, this server pulls the latest commits on `main` and builds an hourly ISO image. The ten most recent ones can be found in the [hourly](https://pub.cloudapio.eu/luna/hourly) directory, and [Luna-latest.iso](https://pub.cloudapio.eu/luna/Luna-latest.iso) should always be symlinked to the newest one.
These images do reflect the latest changes on the `main` branch, but are obviously less stable. Additionally, an hourly image will be skipped if building the latest commit of the project fails.
Prebuilt ISO images for every release version can be found at [pub.cloudapio.eu](https://pub.cloudapio.eu/luna/releases).
## Is there third-party software I can use on Luna?

View File

@ -6,6 +6,7 @@
#include <luna/Format.h>
#include <luna/SourceLocation.h>
#include <luna/Spinlock.h>
#include <luna/StringBuilder.h>
static bool g_debug_enabled = true;
static bool g_serial_enabled = true;
@ -174,3 +175,23 @@ static bool g_check_already_failed = false;
}
CPU::efficient_halt();
}
Result<void> hexdump(void* data, usize size)
{
StringBuilder sb;
u8* ptr = (u8*)data;
while (size)
{
TRY(sb.format("%#2x ", *ptr));
ptr++;
size--;
}
auto message = TRY(sb.string());
kdbgln("hexdump: %s", message.chars());
return {};
}

View File

@ -26,6 +26,8 @@ void set_text_console_initialized();
#define kwarnln(...) log(LogLevel::Warn, __VA_ARGS__)
#define kerrorln(...) log(LogLevel::Error, __VA_ARGS__)
Result<void> hexdump(void* data, usize size);
[[noreturn]] extern void __critical_error_handler(SourceLocation location, const char* expr, const char* failmsg,
const char* errmsg);

View File

@ -157,13 +157,27 @@ namespace ATA
void Channel::select(u8 drive)
{
if (drive == m_current_drive) return;
u8 value = (u8)(drive << 4) | 0xa0;
if (value == m_current_select_value) return;
write_register(Register::DriveSelect, value);
delay_400ns();
m_current_select_value = value;
m_current_drive = drive;
}
void Channel::select(u8 base, u8 drive)
{
u8 value = (u8)(drive << 4) | base;
if (value == m_current_select_value) return;
write_register(Register::DriveSelect, value);
delay_400ns();
m_current_select_value = value;
m_current_drive = drive;
}
@ -543,10 +557,61 @@ namespace ATA
return true;
}
Result<void> Drive::send_packet_atapi_pio(const atapi_packet* packet, void* out, u16 response_size)
void Drive::select_lba(u64 lba, usize count)
{
if (m_is_lba48)
{
m_channel->write_register(Register::SectorCount, (u8)((count >> 8) & 0xff));
m_channel->write_register(Register::LBALow, (u8)((lba >> 24) & 0xff));
m_channel->write_register(Register::LBAMiddle, (u8)((lba >> 32) & 0xff));
m_channel->write_register(Register::LBAHigh, (u8)((lba >> 40) & 0xff));
}
m_channel->write_register(Register::SectorCount, (u8)(count & 0xff));
m_channel->write_register(Register::LBALow, (u8)(lba & 0xff));
m_channel->write_register(Register::LBAMiddle, (u8)((lba >> 8) & 0xff));
m_channel->write_register(Register::LBAHigh, (u8)((lba >> 16) & 0xff));
}
Result<void> Drive::read_pio_bytes(void* out, usize size)
{
u8* ptr = (u8*)out;
usize i = 0;
while (i < size)
{
TRY(m_channel->wait_until_ready());
usize byte_count;
if (m_is_atapi)
{
byte_count =
m_channel->read_register(Register::LBAHigh) << 8 | m_channel->read_register(Register::LBAMiddle);
}
else
byte_count = min(512ul, size - i);
usize word_count = byte_count / 2;
while (word_count--)
{
u16 value = m_channel->read_data();
ptr[0] = (u8)(value & 0xff);
ptr[1] = (u8)(value >> 8);
ptr += 2;
}
i += byte_count;
m_channel->delay_400ns();
}
return {};
}
Result<void> Drive::send_packet_atapi_pio(const atapi_packet* packet, void* out, u16 response_size)
{
m_channel->select(m_drive_index);
// We use PIO here.
@ -559,30 +624,11 @@ namespace ATA
m_channel->delay_400ns();
usize i = 0;
TRY(m_channel->wait_until_ready());
for (int j = 0; j < 6; j++) m_channel->write_data(packet->command_words[j]);
while (i < response_size)
{
TRY(m_channel->wait_until_ready());
usize byte_count =
m_channel->read_register(Register::LBAHigh) << 8 | m_channel->read_register(Register::LBAMiddle);
usize word_count = byte_count / 2;
while (word_count--)
{
u16 value = m_channel->read_data();
ptr[0] = (u8)(value & 0xff);
ptr[1] = (u8)(value >> 8);
ptr += 2;
}
i += byte_count;
}
TRY(read_pio_bytes(out, response_size));
return {};
}
@ -704,6 +750,26 @@ namespace ATA
return send_packet_atapi_pio(&read_packet, out, (u16)size);
}
Result<void> Drive::ata_read_pio(u64 lba, void* out, usize size)
{
check(lba < m_block_count);
check(size <= ARCH_PAGE_SIZE);
usize count = ceil_div(size, m_block_size);
m_channel->select(m_is_lba48 ? 0x40 : (0xe0 | ((lba >> 24) & 0xf)), m_drive_index);
select_lba(lba, count);
m_channel->write_register(Register::Command, m_is_lba48 ? CMD_ReadSectorsExt : CMD_ReadSectors);
m_channel->delay_400ns();
TRY(read_pio_bytes(out, size));
return {};
}
Result<void> Drive::read_lba(u64 lba, void* out, usize nblocks)
{
const usize blocks_per_page = ARCH_PAGE_SIZE / m_block_size;
@ -719,7 +785,16 @@ namespace ATA
return atapi_read_pio(lba, out, nblocks * m_block_size);
}
else
todo();
{
while (nblocks > blocks_per_page)
{
TRY(ata_read_pio(lba, out, ARCH_PAGE_SIZE));
lba += blocks_per_page;
nblocks -= blocks_per_page;
out = offset_ptr(out, ARCH_PAGE_SIZE);
}
return ata_read_pio(lba, out, nblocks * m_block_size);
}
}
void Drive::irq_handler()

View File

@ -54,6 +54,8 @@ namespace ATA
enum CommandRegister : u8
{
CMD_ReadSectors = 0x20,
CMD_ReadSectorsExt = 0x24,
CMD_Identify = 0xec,
CMD_Packet = 0xa0,
CMD_Identify_Packet = 0xa1
@ -180,6 +182,11 @@ namespace ATA
Result<void> atapi_read_pio(u64 lba, void* out, usize size);
Result<void> ata_read_pio(u64 lba, void* out, usize size);
void select_lba(u64 lba, usize count);
Result<void> read_pio_bytes(void* out, usize size);
Channel* m_channel;
u8 m_drive_index;
@ -250,6 +257,7 @@ namespace ATA
}
void select(u8 drive);
void select(u8 base, u8 drive);
bool initialize();
@ -270,6 +278,7 @@ namespace ATA
bool m_irq_called { false };
u8 m_current_drive = (u8)-1;
u8 m_current_select_value = 0xff;
Option<Drive> m_drives[2];
};