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. `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 images
Prebuilt ISO images (numbered) for every version can be found at [pub.cloudapio.eu](https://pub.cloudapio.eu/luna/releases). Prebuilt ISO images for every release 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.
## Is there third-party software I can use on Luna? ## Is there third-party software I can use on Luna?

View File

@ -6,6 +6,7 @@
#include <luna/Format.h> #include <luna/Format.h>
#include <luna/SourceLocation.h> #include <luna/SourceLocation.h>
#include <luna/Spinlock.h> #include <luna/Spinlock.h>
#include <luna/StringBuilder.h>
static bool g_debug_enabled = true; static bool g_debug_enabled = true;
static bool g_serial_enabled = true; static bool g_serial_enabled = true;
@ -174,3 +175,23 @@ static bool g_check_already_failed = false;
} }
CPU::efficient_halt(); 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 kwarnln(...) log(LogLevel::Warn, __VA_ARGS__)
#define kerrorln(...) log(LogLevel::Error, __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, [[noreturn]] extern void __critical_error_handler(SourceLocation location, const char* expr, const char* failmsg,
const char* errmsg); const char* errmsg);

View File

@ -157,13 +157,27 @@ namespace ATA
void Channel::select(u8 drive) void Channel::select(u8 drive)
{ {
if (drive == m_current_drive) return;
u8 value = (u8)(drive << 4) | 0xa0; u8 value = (u8)(drive << 4) | 0xa0;
if (value == m_current_select_value) return;
write_register(Register::DriveSelect, value); write_register(Register::DriveSelect, value);
delay_400ns(); 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; m_current_drive = drive;
} }
@ -543,10 +557,61 @@ namespace ATA
return true; 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; 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); m_channel->select(m_drive_index);
// We use PIO here. // We use PIO here.
@ -559,30 +624,11 @@ namespace ATA
m_channel->delay_400ns(); m_channel->delay_400ns();
usize i = 0;
TRY(m_channel->wait_until_ready()); TRY(m_channel->wait_until_ready());
for (int j = 0; j < 6; j++) m_channel->write_data(packet->command_words[j]); for (int j = 0; j < 6; j++) m_channel->write_data(packet->command_words[j]);
while (i < response_size) TRY(read_pio_bytes(out, 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;
}
return {}; return {};
} }
@ -704,6 +750,26 @@ namespace ATA
return send_packet_atapi_pio(&read_packet, out, (u16)size); 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) Result<void> Drive::read_lba(u64 lba, void* out, usize nblocks)
{ {
const usize blocks_per_page = ARCH_PAGE_SIZE / m_block_size; 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); return atapi_read_pio(lba, out, nblocks * m_block_size);
} }
else 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() void Drive::irq_handler()

View File

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