Compare commits

...

17 Commits

Author SHA1 Message Date
Bananymous 865061b492 Kernel: Temporary fix to make tmpfs more stable
whole TmpFS will have to be rewritten at some point :)
2024-11-21 18:13:26 +02:00
Bananymous 39313e1737 BuildSystem: Add option to boot using IDE or USB drives 2024-11-21 18:09:35 +02:00
Bananymous 70880636f4 Kernel: Implement basic USB Mass Storage support
I finally decided to do this :D
2024-11-21 18:08:37 +02:00
Bananymous 96a5ba0ed3 BuildSystem: Make root partition UUID fixed
This allows specifying root as UUID which makes booting nicer experience
on real hardware
2024-11-21 17:59:38 +02:00
Bananymous 8054f6c618 Kernel: Wait 10 seconds to find root device
If root device is initialized asynchronously it may not be ready when
main initialization thread is finished. This patch adds searching for
root device every 500 ms for 10 seconds.
2024-11-21 17:56:58 +02:00
Bananymous 658ea68d04 Kernel: Check max packet size for all USB devices
Spec says that this has to be done. Most cases can be probably skipped
as I used to do, but this is less error prone and adds practically no
overhead
2024-11-21 13:46:42 +02:00
Bananymous 5750f87396 Kernel: Fix unaligned access in xHCI controller initialization 2024-11-21 13:46:09 +02:00
Bananymous 1253e2a458 Kernel: Add support for bulk endpoints and update endpoint API
USB device now sets its own data buffers for IN/OUT endpoints. This
allows more customization and parallelism as data buffer does not have
to be shared.
2024-11-21 13:44:21 +02:00
Bananymous 857b3e92f8 Kernel: Support initializing USB 3 devices 2024-11-21 13:40:16 +02:00
Bananymous 8bf14d542e Kernel: Move SCSI device rdev allocation out of ATA code 2024-11-21 13:36:59 +02:00
Bananymous 31d2a39540 BAN: Add default constructors for BAN::{Little,Big}Endian 2024-11-21 13:34:12 +02:00
Bananymous 97718b4046 Kernel: Don't launch init process twice
I had accidentrally left the old init process launch in when replacing
it with the new one.
2024-11-19 20:43:38 +02:00
Bananymous c07fd265f0 Kernel: Add support for ATA CHS addressing and cleanup code
I thought that I had an PC without LBA support so I implement support
for CHS. Turns out that my ATA device detection was broken and was no
device on that port and initialize data was just garbage.

Now that I added CHS, I guess I should just keep it in :)

Both ATA read and write are now combined into a single function to avoid
code duplication.
2024-11-19 20:39:32 +02:00
Bananymous 1de50a2a94 Kernel: Improve ATA device initialization
This does better detection of empty ports and fixes floating bus
read-value from 0x00 to 0xFF.
2024-11-19 00:25:42 +02:00
Bananymous 627ca432cc Kernel: Make PS/2 controller not hang if device keeps sending resend 2024-11-19 00:18:48 +02:00
Bananymous f8ef11b4d2 BAN: Make PlacementNew.h only include <new> if it exists
Otherwise it will define the functions itself. This allows compiling
toolchain as stdlibc++ depends on BAN.
2024-11-19 00:16:44 +02:00
Bananymous 71563034a7 Kernel: Remove accidentally left debug prints 2024-11-18 03:45:07 +02:00
37 changed files with 1058 additions and 296 deletions

View File

@ -70,15 +70,19 @@ namespace BAN
template<integral T>
struct LittleEndian
{
constexpr LittleEndian()
: raw(0)
{ }
constexpr LittleEndian(T value)
{
raw = host_to_little_endian(value);
}
: raw(host_to_little_endian(value))
{ }
constexpr operator T() const
{
return host_to_little_endian(raw);
}
private:
T raw;
};
@ -86,15 +90,19 @@ namespace BAN
template<integral T>
struct BigEndian
{
constexpr BigEndian()
: raw(0)
{ }
constexpr BigEndian(T value)
{
raw = host_to_big_endian(value);
}
: raw(host_to_big_endian(value))
{ }
constexpr operator T() const
{
return host_to_big_endian(raw);
}
private:
T raw;
};

View File

@ -1,3 +1,10 @@
#pragma once
#include <new>
#if __has_include(<new>)
#include <new>
#else
#include <stddef.h>
inline void* operator new(size_t, void* addr) { return addr; }
inline void* operator new[](size_t, void* addr) { return addr; }
#endif

View File

@ -83,5 +83,5 @@ command_line_enter_msg:
command_line:
# 100 character command line
command_line_buffer:
.ascii "root=/dev/sda2"
.skip 100 - 28
.ascii "root=UUID=9C87D2AF-566A-4517-971A-57BA86EEA88D"
.skip 100 - (. - command_line_buffer)

View File

@ -89,6 +89,7 @@ set(KERNEL_SOURCES
kernel/Storage/NVMe/Namespace.cpp
kernel/Storage/NVMe/Queue.cpp
kernel/Storage/Partition.cpp
kernel/Storage/SCSI.cpp
kernel/Storage/StorageDevice.cpp
kernel/Syscall.cpp
kernel/Terminal/FramebufferTerminal.cpp
@ -105,6 +106,8 @@ set(KERNEL_SOURCES
kernel/USB/HID/HIDDriver.cpp
kernel/USB/HID/Keyboard.cpp
kernel/USB/HID/Mouse.cpp
kernel/USB/MassStorage/MassStorageDriver.cpp
kernel/USB/MassStorage/SCSIDevice.cpp
kernel/USB/USBManager.cpp
kernel/USB/XHCI/Controller.cpp
kernel/USB/XHCI/Device.cpp

View File

@ -66,6 +66,7 @@
#define DEBUG_USB_HID 0
#define DEBUG_USB_KEYBOARD 0
#define DEBUG_USB_MOUSE 0
#define DEBUG_USB_MASS_STORAGE 0
namespace Debug

View File

@ -14,7 +14,6 @@ namespace Kernel
Ext2_NoInodes,
Storage_Boundaries,
Storage_GPTHeader,
ATA_NoLBA,
ATA_AMNF,
ATA_TKZNF,
ATA_ABRT,

View File

@ -1,8 +1,10 @@
#pragma once
#include <BAN/Array.h>
#include <BAN/StringView.h>
#include <kernel/Memory/Types.h>
#include <dirent.h>
#include <sys/types.h>
#include <time.h>

View File

@ -35,11 +35,12 @@ namespace Kernel
{}
BAN::ErrorOr<void> initialize();
void select_device(bool secondary);
BAN::ErrorOr<DeviceType> identify(bool secondary, BAN::Span<uint16_t> buffer);
BAN::ErrorOr<void> send_command(ATADevice&, uint64_t lba, uint64_t sector_count, bool write);
void block_until_irq();
//uint8_t device_index(const ATADevice&) const;
void select_device(bool is_secondary);
BAN::ErrorOr<DeviceType> identify(bool is_secondary, BAN::Span<uint16_t> buffer);
BAN::ErrorOr<void> block_until_irq();
uint8_t io_read(uint16_t);
void io_write(uint16_t, uint8_t);

View File

@ -19,18 +19,19 @@ namespace Kernel
};
public:
virtual ~ATABaseDevice() {};
virtual ~ATABaseDevice();
virtual uint32_t sector_size() const override { return m_sector_words * 2; }
virtual uint64_t total_size() const override { return m_lba_count * sector_size(); }
uint32_t words_per_sector() const { return m_sector_words; }
uint64_t sector_count() const { return m_lba_count; }
bool has_lba() const { return m_has_lba; }
BAN::StringView model() const { return m_model; }
BAN::StringView name() const { return m_name; }
BAN::StringView name() const override { return m_name; }
virtual dev_t rdev() const override { return m_rdev; }
dev_t rdev() const override { return m_rdev; }
protected:
ATABaseDevice();
@ -42,6 +43,7 @@ namespace Kernel
uint32_t m_command_set;
uint32_t m_sector_words;
uint64_t m_lba_count;
bool m_has_lba;
char m_model[41];
char m_name[4] {};

View File

@ -0,0 +1,11 @@
#pragma once
#include <sys/types.h>
namespace Kernel
{
dev_t scsi_get_rdev();
void scsi_free_rdev(dev_t);
}

View File

@ -19,7 +19,9 @@ namespace Kernel
USBClassDriver() = default;
virtual ~USBClassDriver() = default;
virtual void handle_input_data(BAN::ConstByteSpan, uint8_t endpoint_id) = 0;
virtual BAN::ErrorOr<void> initialize() { return {}; };
virtual void handle_input_data(size_t byte_count, uint8_t endpoint_id) = 0;
};
class USBDevice
@ -64,11 +66,12 @@ namespace Kernel
virtual BAN::ErrorOr<void> initialize_endpoint(const USBEndpointDescriptor&) = 0;
virtual BAN::ErrorOr<size_t> send_request(const USBDeviceRequest&, paddr_t buffer) = 0;
virtual void send_data_buffer(uint8_t endpoint_id, paddr_t buffer, size_t buffer_len) = 0;
static USB::SpeedClass determine_speed_class(uint64_t bits_per_second);
protected:
void handle_input_data(BAN::ConstByteSpan, uint8_t endpoint_id);
void handle_input_data(size_t byte_count, uint8_t endpoint_id);
virtual BAN::ErrorOr<void> initialize_control_endpoint() = 0;
private:

View File

@ -75,15 +75,13 @@ namespace Kernel
};
public:
static BAN::ErrorOr<BAN::UniqPtr<USBHIDDriver>> create(USBDevice&, const USBDevice::InterfaceDescriptor&);
void handle_input_data(BAN::ConstByteSpan, uint8_t endpoint_id) override;
void handle_input_data(size_t byte_count, uint8_t endpoint_id) override;
private:
USBHIDDriver(USBDevice&, const USBDevice::InterfaceDescriptor&);
~USBHIDDriver();
BAN::ErrorOr<void> initialize();
BAN::ErrorOr<void> initialize() override;
BAN::ErrorOr<BAN::Vector<DeviceReport>> initializes_device_reports(const BAN::Vector<USBHID::Collection>&);
@ -94,6 +92,9 @@ namespace Kernel
bool m_uses_report_id { false };
BAN::Vector<DeviceReport> m_device_inputs;
uint8_t m_data_endpoint_id = 0;
BAN::UniqPtr<DMARegion> m_data_buffer;
friend class BAN::UniqPtr<USBHIDDriver>;
};

View File

@ -0,0 +1,29 @@
#pragma once
#include <stdint.h>
namespace Kernel::USBMassStorage
{
struct CBW
{
uint32_t dCBWSignature;
uint32_t dCBWTag;
uint32_t dCBWDataTransferLength;
uint8_t bmCBWFlags;
uint8_t bCBWLUN;
uint8_t bCBWCBLength;
uint8_t CBWCB[16];
} __attribute__((packed));
static_assert(sizeof(CBW) == 31);
struct CSW
{
uint32_t dCSWSignature;
uint32_t dCSWTag;
uint32_t dCSWDataResidue;
uint8_t bmCSWStatus;
} __attribute__((packed));
static_assert(sizeof(CSW) == 13);
}

View File

@ -0,0 +1,49 @@
#pragma once
#include <BAN/Function.h>
#include <kernel/Lock/Mutex.h>
#include <kernel/Storage/StorageDevice.h>
#include <kernel/USB/Device.h>
namespace Kernel
{
class USBMassStorageDriver final : public USBClassDriver
{
BAN_NON_COPYABLE(USBMassStorageDriver);
BAN_NON_MOVABLE(USBMassStorageDriver);
public:
void handle_input_data(size_t byte_count, uint8_t endpoint_id) override;
BAN::ErrorOr<size_t> send_bytes(paddr_t, size_t count);
BAN::ErrorOr<size_t> recv_bytes(paddr_t, size_t count);
void lock() { m_mutex.lock(); }
void unlock() { m_mutex.unlock(); }
private:
USBMassStorageDriver(USBDevice&, const USBDevice::InterfaceDescriptor&);
~USBMassStorageDriver();
BAN::ErrorOr<void> initialize() override;
private:
USBDevice& m_device;
USBDevice::InterfaceDescriptor m_interface;
Mutex m_mutex;
uint8_t m_in_endpoint_id { 0 };
BAN::Function<void(size_t)> m_in_callback;
uint8_t m_out_endpoint_id { 0 };
BAN::Function<void(size_t)> m_out_callback;
BAN::Vector<BAN::RefPtr<StorageDevice>> m_storage_devices;
friend class BAN::UniqPtr<USBMassStorageDriver>;
};
}

View File

@ -0,0 +1,46 @@
#pragma once
#include <kernel/FS/DevFS/FileSystem.h>
#include <kernel/Storage/StorageDevice.h>
#include <kernel/USB/MassStorage/MassStorageDriver.h>
namespace Kernel
{
class USBSCSIDevice : public StorageDevice
{
public:
static BAN::ErrorOr<BAN::RefPtr<USBSCSIDevice>> create(USBMassStorageDriver& driver, uint8_t lun, uint32_t max_packet_size);
uint32_t sector_size() const override { return m_block_size; }
uint64_t total_size() const override { return m_block_size * m_block_count; }
dev_t rdev() const override { return m_rdev; }
BAN::StringView name() const override { return m_name; }
private:
USBSCSIDevice(USBMassStorageDriver& driver, uint8_t lun, BAN::UniqPtr<DMARegion>&&, uint64_t block_count, uint32_t block_size);
~USBSCSIDevice();
static BAN::ErrorOr<size_t> send_scsi_command_impl(USBMassStorageDriver&, DMARegion& dma_region, uint8_t lun, BAN::ConstByteSpan command, BAN::ByteSpan data, bool in);
BAN::ErrorOr<size_t> send_scsi_command(BAN::ConstByteSpan command, BAN::ByteSpan data, bool in);
BAN::ErrorOr<void> read_sectors_impl(uint64_t first_lba, uint64_t sector_count, BAN::ByteSpan buffer) override;
BAN::ErrorOr<void> write_sectors_impl(uint64_t lba, uint64_t sector_count, BAN::ConstByteSpan buffer) override;
private:
USBMassStorageDriver& m_driver;
BAN::UniqPtr<DMARegion> m_dma_region;
const uint8_t m_lun;
const uint64_t m_block_count;
const uint32_t m_block_size;
const dev_t m_rdev;
const char m_name[4];
friend class BAN::RefPtr<USBSCSIDevice>;
};
}

View File

@ -27,7 +27,6 @@ namespace Kernel
volatile uint32_t transfer_count { 0 };
volatile XHCI::TRB completion_trb;
BAN::UniqPtr<DMARegion> data_region;
void(XHCIDevice::*callback)(XHCI::TRB);
};
@ -36,6 +35,7 @@ namespace Kernel
BAN::ErrorOr<void> initialize_endpoint(const USBEndpointDescriptor&) override;
BAN::ErrorOr<size_t> send_request(const USBDeviceRequest&, paddr_t buffer) override;
void send_data_buffer(uint8_t endpoint_id, paddr_t buffer, size_t buffer_size) override;
void on_transfer_event(const volatile XHCI::TRB&);
@ -47,7 +47,7 @@ namespace Kernel
~XHCIDevice();
BAN::ErrorOr<void> update_actual_max_packet_size();
void on_interrupt_endpoint_event(XHCI::TRB);
void on_interrupt_or_bulk_endpoint_event(XHCI::TRB);
void advance_endpoint_enqueue(Endpoint&, bool chain);

View File

@ -17,7 +17,6 @@ namespace Kernel
"Ext2 filesystem out of inodes",
"Attempted to access outside of device boundaries",
"Device has invalid GPT header",
"Device does not support LBA addressing",
"Address mark not found",
"Track zero not found",
"Aborted command",

View File

@ -543,7 +543,7 @@ namespace Kernel
BAN::ErrorOr<void> TmpDirectoryInode::link_inode(TmpInode& inode, BAN::StringView name)
{
static constexpr size_t directory_entry_alignment = 16;
static constexpr size_t directory_entry_alignment = sizeof(TmpDirectoryEntry);
auto find_result = find_inode_impl(name);
if (!find_result.is_error())

View File

@ -6,6 +6,7 @@
#include <kernel/FS/VirtualFileSystem.h>
#include <kernel/Lock/LockGuard.h>
#include <kernel/Storage/Partition.h>
#include <kernel/Timer/Timer.h>
#include <fcntl.h>
@ -14,55 +15,105 @@ namespace Kernel
static BAN::RefPtr<VirtualFileSystem> s_instance;
static BAN::ErrorOr<BAN::RefPtr<BlockDevice>> find_partition_by_uuid(BAN::StringView uuid)
{
ASSERT(uuid.size() == 36);
BAN::RefPtr<BlockDevice> result;
DevFileSystem::get().for_each_inode(
[&result, uuid](BAN::RefPtr<Inode> inode) -> BAN::Iteration
{
if (!inode->is_device())
return BAN::Iteration::Continue;
if (!static_cast<Device*>(inode.ptr())->is_partition())
return BAN::Iteration::Continue;
auto* partition = static_cast<Partition*>(inode.ptr());
if (partition->uuid() != uuid)
return BAN::Iteration::Continue;
result = partition;
return BAN::Iteration::Break;
}
);
if (!result)
return BAN::Error::from_errno(ENOENT);
return result;
}
static BAN::ErrorOr<BAN::RefPtr<BlockDevice>> find_block_device_by_name(BAN::StringView name)
{
auto device_inode = TRY(DevFileSystem::get().root_inode()->find_inode(name));
if (!device_inode->mode().ifblk())
return BAN::Error::from_errno(ENOTBLK);
return BAN::RefPtr<BlockDevice>(static_cast<BlockDevice*>(device_inode.ptr()));
}
static BAN::RefPtr<BlockDevice> find_root_device(BAN::StringView root_path)
{
enum class RootType
{
PartitionUUID,
BlockDeviceName,
};
BAN::StringView entry;
RootType type;
if (root_path.size() >= 5 && root_path.substring(0, 5) == "UUID="_sv)
{
entry = root_path.substring(5);
if (entry.size() != 36)
panic("Invalid UUID '{}'", entry);
type = RootType::PartitionUUID;
}
else if (root_path.size() >= 5 && root_path.substring(0, 5) == "/dev/"_sv)
{
entry = root_path.substring(5);
if (entry.empty() || entry.contains('/'))
panic("Invalid root path '{}'", root_path);
type = RootType::BlockDeviceName;
}
else
{
panic("Unsupported root path format '{}'", root_path);
}
constexpr size_t timeout_ms = 10'000;
constexpr size_t sleep_ms = 500;
for (size_t i = 0; i < timeout_ms / sleep_ms; i++)
{
BAN::ErrorOr<BAN::RefPtr<BlockDevice>> ret = BAN::Error::from_errno(EINVAL);
switch (type)
{
case RootType::PartitionUUID:
ret = find_partition_by_uuid(entry);
break;
case RootType::BlockDeviceName:
ret = find_block_device_by_name(entry);
break;
}
if (!ret.is_error())
return ret.release_value();
if (ret.error().get_error_code() != ENOENT)
panic("could not open root device '{}': {}", root_path, ret.error());
SystemTimer::get().sleep_ms(sleep_ms);
}
panic("could not find root device '{}' after {} ms", root_path, timeout_ms);
}
void VirtualFileSystem::initialize(BAN::StringView root_path)
{
ASSERT(!s_instance);
s_instance = MUST(BAN::RefPtr<VirtualFileSystem>::create());
BAN::RefPtr<BlockDevice> root_device;
if (root_path.size() >= 5 && root_path.substring(0, 5) == "UUID="_sv)
{
auto uuid = root_path.substring(5);
if (uuid.size() != 36)
panic("Invalid UUID specified for root '{}'", uuid);
BAN::RefPtr<Partition> root_partition;
DevFileSystem::get().for_each_inode(
[&root_partition, uuid](BAN::RefPtr<Inode> inode) -> BAN::Iteration
{
if (!inode->is_device())
return BAN::Iteration::Continue;
if (!static_cast<Device*>(inode.ptr())->is_partition())
return BAN::Iteration::Continue;
auto* partition = static_cast<Partition*>(inode.ptr());
if (partition->uuid() != uuid)
return BAN::Iteration::Continue;
root_partition = partition;
return BAN::Iteration::Break;
}
);
if (!root_partition)
panic("Could not find partition with UUID '{}'", uuid);
root_device = root_partition;
}
else if (root_path.size() >= 5 && root_path.substring(0, 5) == "/dev/"_sv)
{
auto device_name = root_path.substring(5);
auto device_result = DevFileSystem::get().root_inode()->find_inode(device_name);
if (device_result.is_error())
panic("Could not open root device '{}': {}", root_path, device_result.error());
auto device_inode = device_result.release_value();
if (!device_inode->mode().ifblk())
panic("Root inode '{}' is not an block device", root_path);
root_device = static_cast<BlockDevice*>(device_inode.ptr());
}
else
{
panic("Unknown root path format '{}' specified", root_path);
}
auto root_device = find_root_device(root_path);
ASSERT(root_device);
auto filesystem_result = FileSystem::from_block_device(root_device);
if (filesystem_result.is_error())

View File

@ -70,18 +70,19 @@ namespace Kernel::Input
BAN::ErrorOr<void> PS2Controller::device_send_byte_and_wait_ack(uint8_t device_index, uint8_t byte)
{
LockGuard _(m_mutex);
for (;;)
for (size_t attempt = 0; attempt < 10; attempt++)
{
TRY(device_send_byte(device_index, byte));
uint8_t response = TRY(read_byte());
if (response == PS2::Response::RESEND)
continue;
if (response == PS2::Response::ACK)
break;
return {};
dwarnln_if(DEBUG_PS2, "PS/2 device on port {} did not respond with expected ACK, got {2H}", device_index, byte);
return BAN::Error::from_errno(EBADMSG);
}
return {};
dwarnln_if(DEBUG_PS2, "PS/2 device on port {} is in resend loop", device_index, byte);
return BAN::Error::from_errno(EBADMSG);
}
uint8_t PS2Controller::get_device_index(PS2Device* device) const
@ -244,7 +245,7 @@ namespace Kernel::Input
if (fadt && fadt->revision > 1 && !(fadt->iapc_boot_arch & (1 << 1)))
{
dwarnln_if(DEBUG_PS2, "No PS/2 available");
return {};
return BAN::Error::from_errno(ENODEV);
}
// Disable Devices

View File

@ -149,13 +149,9 @@ namespace Kernel
const uintptr_t addr = argv_region->vaddr() + offset;
TRY(argv_region->copy_data_to_region(i * sizeof(char*), reinterpret_cast<const uint8_t*>(&addr), sizeof(char*)));
dprintln("argv[{}] = {H}", i * sizeof(char*), addr);
const auto current = (i == 0) ? path : arguments[i - 1];
TRY(argv_region->copy_data_to_region(offset, reinterpret_cast<const uint8_t*>(current.data()), current.size()));
dprintln(" argv[{}] = '{}'", offset, current);
const uint8_t zero = 0;
TRY(argv_region->copy_data_to_region(offset + current.size(), &zero, 1));

View File

@ -19,7 +19,7 @@ namespace Kernel
if (bus_ptr == nullptr)
return BAN::Error::from_errno(ENOMEM);
auto bus = BAN::RefPtr<ATABus>::adopt(bus_ptr);
if (bus->io_read(ATA_PORT_STATUS) == 0x00)
if (bus->io_read(ATA_PORT_STATUS) == 0xFF)
{
dprintln("Floating ATA bus on IO port 0x{H}", base);
return BAN::Error::from_errno(ENODEV);
@ -69,94 +69,83 @@ namespace Kernel
SystemTimer::get().sleep_ns(400);
}
void ATABus::select_device(bool secondary)
void ATABus::select_device(bool is_secondary)
{
io_write(ATA_PORT_DRIVE_SELECT, 0xA0 | ((uint8_t)secondary << 4));
io_write(ATA_PORT_DRIVE_SELECT, 0xA0 | ((uint8_t)is_secondary << 4));
select_delay();
}
BAN::ErrorOr<ATABus::DeviceType> ATABus::identify(bool secondary, BAN::Span<uint16_t> buffer)
BAN::ErrorOr<ATABus::DeviceType> ATABus::identify(bool is_secondary, BAN::Span<uint16_t> buffer)
{
// Try to detect whether port contains device
uint8_t status = io_read(ATA_PORT_STATUS);
if (status & ATA_STATUS_BSY)
{
uint64_t timeout = SystemTimer::get().ms_since_boot() + s_ata_timeout_ms;
while ((status = io_read(ATA_PORT_STATUS)) & ATA_STATUS_BSY)
{
if (SystemTimer::get().ms_since_boot() >= timeout)
{
dprintln("BSY flag clear timeout, assuming no drive on port");
return BAN::Error::from_errno(ETIMEDOUT);
}
}
}
if (__builtin_popcount(status) >= 4)
{
dprintln("STATUS contains garbage, assuming no drive on port");
return BAN::Error::from_errno(EINVAL);
}
select_device(secondary);
select_device(is_secondary);
// Disable interrupts
io_write(ATA_PORT_CONTROL, ATA_CONTROL_nIEN);
io_write(ATA_PORT_SECTOR_COUNT, 0);
io_write(ATA_PORT_LBA0, 0);
io_write(ATA_PORT_LBA1, 0);
io_write(ATA_PORT_LBA2, 0);
io_write(ATA_PORT_COMMAND, ATA_COMMAND_IDENTIFY);
SystemTimer::get().sleep_ms(1);
// No device on port
if (io_read(ATA_PORT_STATUS) == 0)
return BAN::Error::from_errno(EINVAL);
return BAN::Error::from_errno(ENODEV);
DeviceType type = DeviceType::ATA;
TRY(wait(false));
if (wait(true).is_error())
const uint8_t lba1 = io_read(ATA_PORT_LBA1);
const uint8_t lba2 = io_read(ATA_PORT_LBA2);
auto device_type = DeviceType::ATA;
if (lba1 || lba2)
{
uint8_t lba1 = io_read(ATA_PORT_LBA1);
uint8_t lba2 = io_read(ATA_PORT_LBA2);
if (lba1 == 0x14 && lba2 == 0xEB)
type = DeviceType::ATAPI;
device_type = DeviceType::ATAPI;
else if (lba1 == 0x69 && lba2 == 0x96)
type = DeviceType::ATAPI;
device_type = DeviceType::ATAPI;
else
{
dprintln("Unsupported device type");
dprintln("Unsupported device type {2H} {2H}", lba1, lba2);
return BAN::Error::from_errno(EINVAL);
}
io_write(ATA_PORT_COMMAND, ATA_COMMAND_IDENTIFY_PACKET);
SystemTimer::get().sleep_ms(1);
if (auto res = wait(true); res.is_error())
{
dprintln("Fatal error: {}", res.error());
return BAN::Error::from_errno(EINVAL);
}
}
TRY(wait(true));
ASSERT(buffer.size() >= 256);
read_buffer(ATA_PORT_DATA, buffer.data(), 256);
return type;
return device_type;
}
void ATABus::handle_irq()
{
ASSERT(!m_has_got_irq);
if (io_read(ATA_PORT_STATUS) & ATA_STATUS_ERR)
dprintln("ATA Error: {}", error());
m_has_got_irq.store(true);
bool expected { false };
[[maybe_unused]] bool success = m_has_got_irq.compare_exchange(expected, true);
ASSERT(success);
}
void ATABus::block_until_irq()
BAN::ErrorOr<void> ATABus::block_until_irq()
{
const uint64_t timeout_ms = SystemTimer::get().ms_since_boot() + s_ata_timeout_ms;
bool expected { true };
while (!m_has_got_irq.compare_exchange(expected, false))
{
if (SystemTimer::get().ms_since_boot() >= timeout_ms)
return BAN::Error::from_errno(ETIMEDOUT);
Processor::pause();
expected = true;
}
return {};
}
uint8_t ATABus::io_read(uint16_t port)
@ -256,29 +245,12 @@ namespace Kernel
LockGuard _(m_mutex);
if (lba < (1 << 28))
{
// LBA28
io_write(ATA_PORT_DRIVE_SELECT, 0xE0 | ((uint8_t)device.is_secondary() << 4) | ((lba >> 24) & 0x0F));
select_delay();
io_write(ATA_PORT_CONTROL, 0);
TRY(send_command(device, lba, sector_count, false));
io_write(ATA_PORT_SECTOR_COUNT, sector_count);
io_write(ATA_PORT_LBA0, (uint8_t)(lba >> 0));
io_write(ATA_PORT_LBA1, (uint8_t)(lba >> 8));
io_write(ATA_PORT_LBA2, (uint8_t)(lba >> 16));
io_write(ATA_PORT_COMMAND, ATA_COMMAND_READ_SECTORS);
for (uint32_t sector = 0; sector < sector_count; sector++)
{
block_until_irq();
read_buffer(ATA_PORT_DATA, (uint16_t*)buffer.data() + sector * device.words_per_sector(), device.words_per_sector());
}
}
else
for (uint32_t sector = 0; sector < sector_count; sector++)
{
// LBA48
ASSERT(false);
TRY(block_until_irq());
read_buffer(ATA_PORT_DATA, (uint16_t*)buffer.data() + sector * device.words_per_sector(), device.words_per_sector());
}
return {};
@ -293,33 +265,60 @@ namespace Kernel
LockGuard _(m_mutex);
if (lba < (1 << 28))
{
// LBA28
io_write(ATA_PORT_DRIVE_SELECT, 0xE0 | ((uint8_t)device.is_secondary() << 4) | ((lba >> 24) & 0x0F));
select_delay();
io_write(ATA_PORT_CONTROL, 0);
TRY(send_command(device, lba, sector_count, true));
io_write(ATA_PORT_SECTOR_COUNT, sector_count);
io_write(ATA_PORT_LBA0, (uint8_t)(lba >> 0));
io_write(ATA_PORT_LBA1, (uint8_t)(lba >> 8));
io_write(ATA_PORT_LBA2, (uint8_t)(lba >> 16));
io_write(ATA_PORT_COMMAND, ATA_COMMAND_WRITE_SECTORS);
for (uint32_t sector = 0; sector < sector_count; sector++)
{
write_buffer(ATA_PORT_DATA, (uint16_t*)buffer.data() + sector * device.words_per_sector(), device.words_per_sector());
block_until_irq();
}
}
else
for (uint32_t sector = 0; sector < sector_count; sector++)
{
// LBA48
ASSERT(false);
write_buffer(ATA_PORT_DATA, (uint16_t*)buffer.data() + sector * device.words_per_sector(), device.words_per_sector());
TRY(block_until_irq());
}
io_write(ATA_PORT_COMMAND, ATA_COMMAND_CACHE_FLUSH);
block_until_irq();
TRY(block_until_irq());
return {};
}
BAN::ErrorOr<void> ATABus::send_command(ATADevice& device, uint64_t lba, uint64_t sector_count, bool write)
{
uint8_t io_select = 0;
uint8_t io_lba0 = 0;
uint8_t io_lba1 = 0;
uint8_t io_lba2 = 0;
if (lba >= (1 << 28))
{
dwarnln("LBA48 addressing not supported");
return BAN::Error::from_errno(ENOTSUP);
}
else if (device.has_lba())
{
io_select = 0xE0 | ((uint8_t)device.is_secondary() << 4) | ((lba >> 24) & 0x0F);
io_lba0 = (lba >> 0) & 0xFF;
io_lba1 = (lba >> 8) & 0xFF;
io_lba2 = (lba >> 16) & 0xFF;
}
else
{
const uint8_t sector = (lba % 63) + 1;
const uint8_t head = (lba + 1 - sector) % (16 * 63) / 63;
const uint16_t cylinder = (lba + 1 - sector) / (16 * 63);
io_select = 0xA0 | ((uint8_t)device.is_secondary() << 4) | head;
io_lba0 = sector;
io_lba1 = (cylinder >> 0) & 0xFF;
io_lba2 = (cylinder >> 8) & 0xFF;
}
io_write(ATA_PORT_DRIVE_SELECT, io_select);
select_delay();
io_write(ATA_PORT_CONTROL, 0);
io_write(ATA_PORT_SECTOR_COUNT, sector_count);
io_write(ATA_PORT_LBA0, io_lba0);
io_write(ATA_PORT_LBA1, io_lba1);
io_write(ATA_PORT_LBA2, io_lba2);
io_write(ATA_PORT_COMMAND, write ? ATA_COMMAND_WRITE_SECTORS : ATA_COMMAND_READ_SECTORS);
return {};
}

View File

@ -4,44 +4,43 @@
#include <kernel/Storage/ATA/ATABus.h>
#include <kernel/Storage/ATA/ATADefinitions.h>
#include <kernel/Storage/ATA/ATADevice.h>
#include <kernel/Storage/SCSI.h>
#include <sys/sysmacros.h>
namespace Kernel
{
static dev_t get_ata_dev_minor()
{
static dev_t minor = 0;
return minor++;
}
detail::ATABaseDevice::ATABaseDevice()
: m_rdev(makedev(DeviceNumber::SCSI, get_ata_dev_minor()))
: m_rdev(scsi_get_rdev())
{
strcpy(m_name, "sda");
m_name[2] += minor(m_rdev);
}
detail::ATABaseDevice::~ATABaseDevice()
{
scsi_free_rdev(m_rdev);
}
BAN::ErrorOr<void> detail::ATABaseDevice::initialize(BAN::Span<const uint16_t> identify_data)
{
ASSERT(identify_data.size() >= 256);
m_signature = identify_data[ATA_IDENTIFY_SIGNATURE];
m_signature = identify_data[ATA_IDENTIFY_SIGNATURE];
m_capabilities = identify_data[ATA_IDENTIFY_CAPABILITIES];
m_command_set = 0;
m_command_set |= (uint32_t)(identify_data[ATA_IDENTIFY_COMMAND_SET + 0] << 0);
m_command_set |= (uint32_t)(identify_data[ATA_IDENTIFY_COMMAND_SET + 1] << 16);
m_command_set = static_cast<uint32_t>(identify_data[ATA_IDENTIFY_COMMAND_SET + 0]) << 0;
m_command_set |= static_cast<uint32_t>(identify_data[ATA_IDENTIFY_COMMAND_SET + 1]) << 16;
if (!(m_capabilities & ATA_CAPABILITIES_LBA))
return BAN::Error::from_error_code(ErrorCode::ATA_NoLBA);
m_has_lba = !!(m_capabilities & ATA_CAPABILITIES_LBA);
if ((identify_data[ATA_IDENTIFY_SECTOR_INFO] & (1 << 15)) == 0 &&
(identify_data[ATA_IDENTIFY_SECTOR_INFO] & (1 << 14)) != 0 &&
(identify_data[ATA_IDENTIFY_SECTOR_INFO] & (1 << 12)) != 0)
{
m_sector_words = *(uint32_t*)(identify_data.data() + ATA_IDENTIFY_SECTOR_WORDS);
m_sector_words = static_cast<uint32_t>(identify_data[ATA_IDENTIFY_SECTOR_WORDS + 0]) << 0;
m_sector_words |= static_cast<uint32_t>(identify_data[ATA_IDENTIFY_SECTOR_WORDS + 1]) << 16;
}
else
{
@ -50,9 +49,17 @@ namespace Kernel
m_lba_count = 0;
if (m_command_set & ATA_COMMANDSET_LBA48_SUPPORTED)
m_lba_count = *(uint64_t*)(identify_data.data() + ATA_IDENTIFY_LBA_COUNT_EXT);
{
m_lba_count = static_cast<uint64_t>(identify_data[ATA_IDENTIFY_LBA_COUNT_EXT + 0]) << 0;
m_lba_count |= static_cast<uint64_t>(identify_data[ATA_IDENTIFY_LBA_COUNT_EXT + 1]) << 16;
m_lba_count |= static_cast<uint64_t>(identify_data[ATA_IDENTIFY_LBA_COUNT_EXT + 2]) << 32;
m_lba_count |= static_cast<uint64_t>(identify_data[ATA_IDENTIFY_LBA_COUNT_EXT + 3]) << 48;
}
if (m_lba_count < (1 << 28))
m_lba_count = *(uint32_t*)(identify_data.data() + ATA_IDENTIFY_LBA_COUNT);
{
m_lba_count = static_cast<uint32_t>(identify_data[ATA_IDENTIFY_LBA_COUNT + 0]) << 0;
m_lba_count |= static_cast<uint32_t>(identify_data[ATA_IDENTIFY_LBA_COUNT + 1]) << 16;
}
for (int i = 0; i < 20; i++)
{

View File

@ -0,0 +1,44 @@
#include <kernel/Device/DeviceNumbers.h>
#include <kernel/Lock/SpinLock.h>
#include <kernel/Storage/SCSI.h>
#include <sys/sysmacros.h>
namespace Kernel
{
static uint64_t s_scsi_bitmap { 0 };
static SpinLock s_scsi_spinlock;
static constexpr size_t s_scsi_bitmap_bits = sizeof(s_scsi_bitmap) * 8;
dev_t scsi_get_rdev()
{
SpinLockGuard _(s_scsi_spinlock);
uint64_t mask = 1;
for (uint8_t minor = 0; minor < s_scsi_bitmap_bits; minor++, mask <<= 1)
{
if (s_scsi_bitmap & mask)
continue;
s_scsi_bitmap |= mask;
return makedev(DeviceNumber::SCSI, minor);
}
ASSERT_NOT_REACHED();
}
void scsi_free_rdev(dev_t rdev)
{
ASSERT(major(rdev) == static_cast<dev_t>(DeviceNumber::SCSI));
SpinLockGuard _(s_scsi_spinlock);
const uint64_t mask = static_cast<uint64_t>(1) << minor(rdev);
ASSERT(s_scsi_bitmap & mask);
s_scsi_bitmap &= ~mask;
}
}

View File

@ -1,6 +1,7 @@
#include <kernel/Memory/DMARegion.h>
#include <kernel/USB/Device.h>
#include <kernel/USB/HID/HIDDriver.h>
#include <kernel/USB/MassStorage/MassStorageDriver.h>
#define USB_DUMP_DESCRIPTORS 0
@ -154,7 +155,7 @@ namespace Kernel
dprintln_if(DEBUG_USB, "Found CommunicationAndCDCControl interface");
break;
case USB::InterfaceBaseClass::HID:
if (auto result = USBHIDDriver::create(*this, interface); !result.is_error())
if (auto result = BAN::UniqPtr<USBHIDDriver>::create(*this, interface); !result.is_error())
TRY(m_class_drivers.push_back(result.release_value()));
break;
case USB::InterfaceBaseClass::Physical:
@ -167,7 +168,8 @@ namespace Kernel
dprintln_if(DEBUG_USB, "Found Printer interface");
break;
case USB::InterfaceBaseClass::MassStorage:
dprintln_if(DEBUG_USB, "Found MassStorage interface");
if (auto result = BAN::UniqPtr<USBMassStorageDriver>::create(*this, interface); !result.is_error())
TRY(m_class_drivers.push_back(result.release_value()));
break;
case USB::InterfaceBaseClass::CDCData:
dprintln_if(DEBUG_USB, "Found CDCData interface");
@ -220,6 +222,15 @@ namespace Kernel
}
}
for (size_t i = 0; i < m_class_drivers.size(); i++)
{
if (auto ret = m_class_drivers[i]->initialize(); ret.is_error())
{
dwarnln("Could not initialize USB interface {}", ret.error());
m_class_drivers.remove(i--);
}
}
if (!m_class_drivers.empty())
{
dprintln("Successfully initialized USB device with {}/{} interfaces",
@ -317,10 +328,10 @@ namespace Kernel
return BAN::move(configuration);
}
void USBDevice::handle_input_data(BAN::ConstByteSpan data, uint8_t endpoint_id)
void USBDevice::handle_input_data(size_t byte_count, uint8_t endpoint_id)
{
for (auto& driver : m_class_drivers)
driver->handle_input_data(data, endpoint_id);
driver->handle_input_data(byte_count, endpoint_id);
}
USB::SpeedClass USBDevice::determine_speed_class(uint64_t bits_per_second)

View File

@ -1,4 +1,5 @@
#include <BAN/ByteSpan.h>
#include <BAN/ScopeGuard.h>
#include <kernel/FS/DevFS/FileSystem.h>
#include <kernel/USB/HID/HIDDriver.h>
@ -68,13 +69,6 @@ namespace Kernel
static BAN::ErrorOr<BAN::Vector<Collection>> parse_report_descriptor(BAN::ConstByteSpan report_data, bool& out_use_report_id);
BAN::ErrorOr<BAN::UniqPtr<USBHIDDriver>> USBHIDDriver::create(USBDevice& device, const USBDevice::InterfaceDescriptor& interface)
{
auto result = TRY(BAN::UniqPtr<USBHIDDriver>::create(device, interface));
TRY(result->initialize());
return result;
}
USBHIDDriver::USBHIDDriver(USBDevice& device, const USBDevice::InterfaceDescriptor& interface)
: m_device(device)
, m_interface(interface)
@ -192,7 +186,29 @@ namespace Kernel
m_device_inputs = TRY(initializes_device_reports(collections));
for (const auto& endpoint : m_interface.endpoints)
TRY(m_device.initialize_endpoint(endpoint.descriptor));
{
const auto& desc = endpoint.descriptor;
if (!(desc.bEndpointAddress & 0x80))
continue;
if ((desc.bmAttributes & 0x03) != 0x03)
continue;
TRY(m_device.initialize_endpoint(desc));
m_data_buffer = TRY(DMARegion::create(desc.wMaxPacketSize & 0x07FF));
m_data_endpoint_id = (desc.bEndpointAddress & 0x0F) * 2 + !!(desc.bEndpointAddress & 0x80);
break;
}
if (m_data_endpoint_id == 0)
{
dwarnln("HID device does not an interrupt IN endpoints");
return BAN::Error::from_errno(EINVAL);
}
m_device.send_data_buffer(m_data_endpoint_id, m_data_buffer->paddr(), m_data_buffer->size());
return {};
}
@ -256,23 +272,15 @@ namespace Kernel
return BAN::move(result);
}
void USBHIDDriver::handle_input_data(BAN::ConstByteSpan data, uint8_t endpoint_id)
void USBHIDDriver::handle_input_data(size_t byte_count, uint8_t endpoint_id)
{
{
bool found = false;
for (const auto& endpoint : m_interface.endpoints)
{
const auto& desc = endpoint.descriptor;
if (endpoint_id == (desc.bEndpointAddress & 0x0F) * 2 + !!(desc.bEndpointAddress & 0x80))
{
found = true;
break;
}
}
// If this packet is not for us, skip it
if (!found)
return;
}
if (m_data_endpoint_id != endpoint_id)
return;
auto data = BAN::ConstByteSpan(reinterpret_cast<uint8_t*>(m_data_buffer->vaddr()), byte_count);
BAN::ScopeGuard _([&] {
m_device.send_data_buffer(m_data_endpoint_id, m_data_buffer->paddr(), m_data_buffer->size());
});
if constexpr(DEBUG_USB_HID)
{

View File

@ -0,0 +1,199 @@
#include <BAN/Endianness.h>
#include <BAN/ScopeGuard.h>
#include <BAN/StringView.h>
#include <kernel/FS/VirtualFileSystem.h>
#include <kernel/Lock/LockGuard.h>
#include <kernel/Timer/Timer.h>
#include <kernel/USB/MassStorage/MassStorageDriver.h>
#include <kernel/USB/MassStorage/SCSIDevice.h>
namespace Kernel
{
USBMassStorageDriver::USBMassStorageDriver(USBDevice& device, const USBDevice::InterfaceDescriptor& interface)
: m_device(device)
, m_interface(interface)
{ }
USBMassStorageDriver::~USBMassStorageDriver()
{ }
BAN::ErrorOr<void> USBMassStorageDriver::initialize()
{
if (m_interface.descriptor.bInterfaceProtocol != 0x50)
{
dwarnln("Only USB Mass Storage BBB is supported");
return BAN::Error::from_errno(ENOTSUP);
}
auto dma_region = TRY(DMARegion::create(PAGE_SIZE));
// Bulk-Only Mass Storage Reset
{
USBDeviceRequest reset_request {
.bmRequestType = USB::RequestType::HostToDevice | USB::RequestType::Class | USB::RequestType::Interface,
.bRequest = 0xFF,
.wValue = 0x0000,
.wIndex = m_interface.descriptor.bInterfaceNumber,
.wLength = 0x0000,
};
TRY(m_device.send_request(reset_request, 0));
}
// Get Max LUN
{
USBDeviceRequest lun_request {
.bmRequestType = USB::RequestType::DeviceToHost | USB::RequestType::Class | USB::RequestType::Interface,
.bRequest = 0xFE,
.wValue = 0x0000,
.wIndex = m_interface.descriptor.bInterfaceNumber,
.wLength = 0x0001,
};
uint32_t max_lun = 0;
const auto lun_result = m_device.send_request(lun_request, dma_region->paddr());
if (!lun_result.is_error() && lun_result.value() == 1)
max_lun = *reinterpret_cast<uint8_t*>(dma_region->vaddr());
TRY(m_storage_devices.resize(max_lun + 1));
}
uint32_t max_packet_size = -1;
// Initialize bulk-in and bulk-out endpoints
{
constexpr size_t invalid_index = -1;
size_t bulk_in_index = invalid_index;
size_t bulk_out_index = invalid_index;
for (size_t i = 0; i < m_interface.endpoints.size(); i++)
{
const auto& endpoint = m_interface.endpoints[i].descriptor;
if (endpoint.bmAttributes != 0x02)
continue;
((endpoint.bEndpointAddress & 0x80) ? bulk_in_index : bulk_out_index) = i;
}
if (bulk_in_index == invalid_index || bulk_out_index == invalid_index)
{
dwarnln("USB Mass Storage device does not contain bulk-in and bulk-out endpoints");
return BAN::Error::from_errno(EFAULT);
}
TRY(m_device.initialize_endpoint(m_interface.endpoints[bulk_in_index].descriptor));
TRY(m_device.initialize_endpoint(m_interface.endpoints[bulk_out_index].descriptor));
{
const auto& desc = m_interface.endpoints[bulk_in_index].descriptor;
m_in_endpoint_id = (desc.bEndpointAddress & 0x0F) * 2 + !!(desc.bEndpointAddress & 0x80);
max_packet_size = BAN::Math::min<uint32_t>(max_packet_size, desc.wMaxPacketSize);
}
{
const auto& desc = m_interface.endpoints[bulk_out_index].descriptor;
m_out_endpoint_id = (desc.bEndpointAddress & 0x0F) * 2 + !!(desc.bEndpointAddress & 0x80);
max_packet_size = BAN::Math::min<uint32_t>(max_packet_size, desc.wMaxPacketSize);
}
}
BAN::Function<BAN::ErrorOr<BAN::RefPtr<StorageDevice>>(USBMassStorageDriver&, uint8_t, uint32_t)> create_device_func;
switch (m_interface.descriptor.bInterfaceSubClass)
{
case 0x06:
create_device_func =
[](USBMassStorageDriver& driver, uint8_t lun, uint32_t max_packet_size) -> BAN::ErrorOr<BAN::RefPtr<StorageDevice>>
{
auto ret = TRY(USBSCSIDevice::create(driver, lun, max_packet_size));
return BAN::RefPtr<StorageDevice>(ret);
};
break;
default:
dwarnln("Unsupported command block {2H}", m_interface.descriptor.bInterfaceSubClass);
return BAN::Error::from_errno(ENOTSUP);
}
ASSERT(m_storage_devices.size() <= 0xFF);
for (uint8_t lun = 0; lun < m_storage_devices.size(); lun++)
m_storage_devices[lun] = TRY(create_device_func(*this, lun, max_packet_size));
return {};
}
BAN::ErrorOr<size_t> USBMassStorageDriver::send_bytes(paddr_t paddr, size_t count)
{
ASSERT(m_mutex.is_locked());
constexpr size_t invalid = -1;
static volatile size_t bytes_sent;
bytes_sent = invalid;
ASSERT(!m_out_callback);
m_out_callback = [](size_t bytes) { bytes_sent = bytes; };
BAN::ScopeGuard _([this] { m_out_callback.clear(); });
m_device.send_data_buffer(m_out_endpoint_id, paddr, count);
const uint64_t timeout_ms = SystemTimer::get().ms_since_boot() + 100;
while (bytes_sent == invalid)
if (SystemTimer::get().ms_since_boot() > timeout_ms)
return BAN::Error::from_errno(EIO);
return static_cast<size_t>(bytes_sent);
}
BAN::ErrorOr<size_t> USBMassStorageDriver::recv_bytes(paddr_t paddr, size_t count)
{
ASSERT(m_mutex.is_locked());
constexpr size_t invalid = -1;
static volatile size_t bytes_recv;
bytes_recv = invalid;
ASSERT(!m_in_callback);
m_in_callback = [](size_t bytes) { bytes_recv = bytes; };
BAN::ScopeGuard _([this] { m_in_callback.clear(); });
m_device.send_data_buffer(m_in_endpoint_id, paddr, count);
const uint64_t timeout_ms = SystemTimer::get().ms_since_boot() + 100;
while (bytes_recv == invalid)
if (SystemTimer::get().ms_since_boot() > timeout_ms)
return BAN::Error::from_errno(EIO);
m_in_callback.clear();
return static_cast<size_t>(bytes_recv);
}
void USBMassStorageDriver::handle_input_data(size_t byte_count, uint8_t endpoint_id)
{
if (endpoint_id != m_in_endpoint_id && endpoint_id != m_out_endpoint_id)
return;
dprintln_if(DEBUG_USB_MASS_STORAGE, "got {} bytes to {} endpoint", byte_count, endpoint_id == m_in_endpoint_id ? "IN" : "OUT");
if (endpoint_id == m_in_endpoint_id)
{
if (m_in_callback)
m_in_callback(byte_count);
else
dwarnln("ignoring {} bytes to IN endpoint", byte_count);
return;
}
if (endpoint_id == m_out_endpoint_id)
{
if (m_out_callback)
m_out_callback(byte_count);
else
dwarnln("ignoring {} bytes to OUT endpoint", byte_count);
return;
}
}
}

View File

@ -0,0 +1,265 @@
#include <BAN/Endianness.h>
#include <kernel/Storage/SCSI.h>
#include <kernel/USB/MassStorage/Definitions.h>
#include <kernel/USB/MassStorage/SCSIDevice.h>
#include <sys/sysmacros.h>
namespace Kernel
{
namespace SCSI
{
struct InquiryRes
{
uint8_t peripheral_device_type : 5;
uint8_t peripheral_qualifier : 3;
uint8_t reserved0 : 7;
uint8_t rmb : 1;
uint8_t version;
uint8_t response_data_format : 4;
uint8_t hisup : 1;
uint8_t normaca : 1;
uint8_t obsolete0 : 1;
uint8_t obsolete1 : 1;
uint8_t additional_length;
uint8_t protect : 1;
uint8_t reserved1 : 2;
uint8_t _3pc : 1;
uint8_t tgps : 2;
uint8_t acc : 1;
uint8_t sccs : 1;
uint8_t obsolete2 : 1;
uint8_t obsolete3 : 1;
uint8_t obsolete4 : 1;
uint8_t obsolete5 : 1;
uint8_t multip : 1;
uint8_t vs0 : 1;
uint8_t encserv : 1;
uint8_t obsolete6 : 1;
uint8_t vs1 : 1;
uint8_t cmdque : 1;
uint8_t obsolete7 : 1;
uint8_t obsolete8 : 1;
uint8_t obsolete9 : 1;
uint8_t obsolete10 : 1;
uint8_t obsolete11 : 1;
uint8_t obsolete12 : 1;
uint8_t t10_vendor_identification[8];
uint8_t product_identification[16];
uint8_t product_revision_level[4];
};
static_assert(sizeof(InquiryRes) == 36);
struct ReadCapacity10
{
BAN::BigEndian<uint32_t> logical_block_address {};
BAN::BigEndian<uint32_t> block_length;
};
static_assert(sizeof(ReadCapacity10) == 8);
}
BAN::ErrorOr<BAN::RefPtr<USBSCSIDevice>> USBSCSIDevice::create(USBMassStorageDriver& driver, uint8_t lun, uint32_t max_packet_size)
{
auto dma_region = TRY(DMARegion::create(max_packet_size));
dprintln("USB SCSI device");
{
const uint8_t scsi_inquiry_req[6] {
0x12,
0x00,
0x00,
0x00, sizeof(SCSI::InquiryRes),
0x00
};
SCSI::InquiryRes inquiry_res;
TRY(send_scsi_command_impl(driver, *dma_region, lun, BAN::ConstByteSpan::from(scsi_inquiry_req), BAN::ByteSpan::from(inquiry_res), true));
dprintln(" vendor: {}", BAN::StringView(reinterpret_cast<const char*>(inquiry_res.t10_vendor_identification), 8));
dprintln(" product: {}", BAN::StringView(reinterpret_cast<const char*>(inquiry_res.product_identification), 16));
dprintln(" revision: {}", BAN::StringView(reinterpret_cast<const char*>(inquiry_res.product_revision_level), 4));
}
uint32_t block_count;
uint32_t block_size;
{
const uint8_t scsi_read_capacity_req[10] {
0x25,
0x00,
0x00, 0x00, 0x00, 0x00,
0x00, 0x00,
0x00,
0x00
};
SCSI::ReadCapacity10 read_capacity_res;
TRY(send_scsi_command_impl(driver, *dma_region, lun, BAN::ConstByteSpan::from(scsi_read_capacity_req), BAN::ByteSpan::from(read_capacity_res), true));
block_count = read_capacity_res.logical_block_address + 1;
block_size = read_capacity_res.block_length;
if (block_count == 0)
{
dwarnln("Too big USB storage");
return BAN::Error::from_errno(ENOTSUP);
}
dprintln(" last LBA: {}", block_count);
dprintln(" block size: {}", block_size);
dprintln(" total size: {} MiB", block_count * block_size / 1024 / 1024);
}
auto result = TRY(BAN::RefPtr<USBSCSIDevice>::create(driver, lun, BAN::move(dma_region), block_count, block_size));
result->add_disk_cache();
DevFileSystem::get().add_device(result);
if (auto res = result->initialize_partitions(result->name()); res.is_error())
dprintln("{}", res.error());
return result;
}
USBSCSIDevice::USBSCSIDevice(USBMassStorageDriver& driver, uint8_t lun, BAN::UniqPtr<DMARegion>&& dma_region, uint64_t block_count, uint32_t block_size)
: m_driver(driver)
, m_dma_region(BAN::move(dma_region))
, m_lun(lun)
, m_block_count(block_count)
, m_block_size(block_size)
, m_rdev(scsi_get_rdev())
, m_name { 's', 'd', (char)('a' + minor(m_rdev)), '\0' }
{ }
USBSCSIDevice::~USBSCSIDevice()
{
scsi_free_rdev(m_rdev);
}
BAN::ErrorOr<size_t> USBSCSIDevice::send_scsi_command(BAN::ConstByteSpan scsi_command, BAN::ByteSpan data, bool in)
{
return TRY(send_scsi_command_impl(m_driver, *m_dma_region, m_lun, scsi_command, data, in));
}
BAN::ErrorOr<size_t> USBSCSIDevice::send_scsi_command_impl(USBMassStorageDriver& driver, DMARegion& dma_region, uint8_t lun, BAN::ConstByteSpan scsi_command, BAN::ByteSpan data, bool in)
{
ASSERT(scsi_command.size() <= 16);
LockGuard _(driver);
auto& cbw = *reinterpret_cast<USBMassStorage::CBW*>(dma_region.vaddr());
cbw = {
.dCBWSignature = 0x43425355,
.dCBWTag = 0x00000000,
.dCBWDataTransferLength = static_cast<uint32_t>(data.size()),
.bmCBWFlags = static_cast<uint8_t>(in ? 0x80 : 0x00),
.bCBWLUN = lun,
.bCBWCBLength = static_cast<uint8_t>(scsi_command.size()),
.CBWCB = {},
};
memcpy(cbw.CBWCB, scsi_command.data(), scsi_command.size());
if (TRY(driver.send_bytes(dma_region.paddr(), sizeof(USBMassStorage::CBW))) != sizeof(USBMassStorage::CBW))
{
dwarnln("failed to send full CBW");
return BAN::Error::from_errno(EFAULT);
}
const size_t ntransfer =
TRY([&]() -> BAN::ErrorOr<size_t>
{
if (data.empty())
return 0;
if (in)
return TRY(driver.recv_bytes(dma_region.paddr(), data.size()));
memcpy(reinterpret_cast<void*>(dma_region.vaddr()), data.data(), data.size());
return TRY(driver.send_bytes(dma_region.paddr(), data.size()));
}());
if (ntransfer > data.size())
{
dwarnln("device responded with more bytes than requested");
return BAN::Error::from_errno(EFAULT);
}
if (in && !data.empty())
memcpy(data.data(), reinterpret_cast<void*>(dma_region.vaddr()), ntransfer);
if (TRY(driver.recv_bytes(dma_region.paddr(), sizeof(USBMassStorage::CSW))) != sizeof(USBMassStorage::CSW))
{
dwarnln("could not receive full CSW");
return BAN::Error::from_errno(EFAULT);
}
if (auto status = reinterpret_cast<USBMassStorage::CSW*>(dma_region.vaddr())->bmCSWStatus)
{
dwarnln("CSW status {2H}", status);
return BAN::Error::from_errno(EFAULT);
}
return ntransfer;
}
BAN::ErrorOr<void> USBSCSIDevice::read_sectors_impl(uint64_t first_lba, uint64_t sector_count, BAN::ByteSpan buffer)
{
const size_t max_blocks_per_read = m_dma_region->size() / m_block_size;
ASSERT(max_blocks_per_read <= 0xFFFF);
for (uint64_t i = 0; i < sector_count;)
{
const uint32_t lba = first_lba + i;
const uint32_t count = BAN::Math::min<uint32_t>(max_blocks_per_read, sector_count - i);
const uint8_t scsi_read_req[10] {
0x28,
0x00,
(uint8_t)(lba >> 24), (uint8_t)(lba >> 16), (uint8_t)(lba >> 8), (uint8_t)(lba >> 0),
0x00,
(uint8_t)(count >> 8), (uint8_t)(count >> 0),
0x00
};
TRY(send_scsi_command(BAN::ConstByteSpan::from(scsi_read_req), buffer.slice(i * m_block_size, count * m_block_size), true));
i += count;
}
return {};
}
BAN::ErrorOr<void> USBSCSIDevice::write_sectors_impl(uint64_t first_lba, uint64_t sector_count, BAN::ConstByteSpan _buffer)
{
const size_t max_blocks_per_write = m_dma_region->size() / m_block_size;
ASSERT(max_blocks_per_write <= 0xFFFF);
auto buffer = BAN::ByteSpan(const_cast<uint8_t*>(_buffer.data()), _buffer.size());
for (uint64_t i = 0; i < sector_count;)
{
const uint32_t lba = first_lba + i;
const uint32_t count = BAN::Math::min<uint32_t>(max_blocks_per_write, sector_count - i);
const uint8_t scsi_write_req[10] {
0x2A,
0x00,
(uint8_t)(lba >> 24), (uint8_t)(lba >> 16), (uint8_t)(lba >> 8), (uint8_t)(lba >> 0),
0x00,
(uint8_t)(count >> 8), (uint8_t)(count >> 0),
0x00
};
TRY(send_scsi_command(BAN::ConstByteSpan::from(scsi_write_req), buffer.slice(i * m_block_size, count * m_block_size), false));
i += count;
}
return {};
}
}

View File

@ -159,7 +159,13 @@ namespace Kernel
{
auto& protocol = reinterpret_cast<volatile XHCI::SupportedPrococolCap&>(ext_cap);
if (protocol.name_string != *reinterpret_cast<const uint32_t*>("USB "))
const uint32_t target_name_string {
('U' << 0) |
('S' << 8) |
('B' << 16) |
(' ' << 24)
};
if (protocol.name_string != target_name_string)
{
dwarnln("Invalid port protocol name string");
return BAN::Error::from_errno(EFAULT);
@ -268,6 +274,7 @@ namespace Kernel
// read and clear needed change flags
const bool reset_change = op_port.portsc & XHCI::PORTSC::PRC;
const bool connection_change = op_port.portsc & XHCI::PORTSC::CSC;
const bool port_enabled = op_port.portsc & XHCI::PORTSC::PED;
op_port.portsc = XHCI::PORTSC::CSC | XHCI::PORTSC::PRC | XHCI::PORTSC::PP;
if (!(op_port.portsc & XHCI::PORTSC::CCS))
@ -284,18 +291,18 @@ namespace Kernel
switch (my_port.revision_major)
{
case 2:
if (!reset_change)
{
if (connection_change)
op_port.portsc = XHCI::PORTSC::PR | XHCI::PORTSC::PP;
continue;
}
break;
case 3:
if (!connection_change)
continue;
dprintln_if(DEBUG_XHCI, "USB 3 devices not supported");
// USB2 ports advance to Enabled state after a reset
if (port_enabled && reset_change)
break;
// reset port
if (connection_change)
op_port.portsc = XHCI::PORTSC::PR | XHCI::PORTSC::PP;
continue;
case 3:
if (!connection_change || !port_enabled)
continue;
// USB3 ports advance to Enabled state automatically
break;
default:
continue;
}

View File

@ -106,9 +106,7 @@ namespace Kernel
TRY(m_controller.send_command(address_device));
}
// NOTE: Full speed devices can have other max packet sizes than 8
if (m_speed_class == USB::SpeedClass::FullSpeed)
TRY(update_actual_max_packet_size());
TRY(update_actual_max_packet_size());
return {};
}
@ -117,7 +115,7 @@ namespace Kernel
{
// FIXME: This is more or less generic USB code
dprintln_if(DEBUG_XHCI, "Retrieving actual max packet size of full speed device");
dprintln_if(DEBUG_XHCI, "Retrieving actual max packet size");
BAN::Vector<uint8_t> buffer;
TRY(buffer.resize(8, 0));
@ -130,7 +128,13 @@ namespace Kernel
request.wLength = 8;
TRY(send_request(request, kmalloc_paddr_of((vaddr_t)buffer.data()).value()));
m_endpoints[0].max_packet_size = buffer.back();
const bool is_usb3 = m_controller.port(m_port_id).revision_major == 3;
const uint32_t new_max_packet_size = is_usb3 ? 1u << buffer.back() : buffer.back();
if (m_endpoints[0].max_packet_size == new_max_packet_size)
return {};
m_endpoints[0].max_packet_size = new_max_packet_size;
const uint32_t context_size = m_controller.context_size_set() ? 64 : 32;
@ -200,20 +204,20 @@ namespace Kernel
BAN::ErrorOr<void> XHCIDevice::initialize_endpoint(const USBEndpointDescriptor& endpoint_descriptor)
{
ASSERT(m_controller.port(m_port_id).revision_major == 2);
const bool is_control { (endpoint_descriptor.bmAttributes & 0x03) == 0x00 };
const bool is_isoch { (endpoint_descriptor.bmAttributes & 0x03) == 0x01 };
const bool is_bulk { (endpoint_descriptor.bmAttributes & 0x03) == 0x02 };
const bool is_interrupt { (endpoint_descriptor.bmAttributes & 0x03) == 0x03 };
const uint32_t endpoint_id = (endpoint_descriptor.bEndpointAddress & 0x0F) * 2 + !!(endpoint_descriptor.bEndpointAddress & 0x80);
const uint32_t max_packet_size = endpoint_descriptor.wMaxPacketSize & 0x07FF;
const uint32_t max_burst_size = (endpoint_descriptor.wMaxPacketSize >> 11) & 0x0003;
const uint32_t max_esit_payload = max_packet_size * (max_burst_size + 1);
const uint32_t interval = determine_interval(endpoint_descriptor, m_speed_class);
const uint32_t average_trb_length = ((endpoint_descriptor.bmAttributes & 3) == 0b00) ? 8 : max_esit_payload;
const uint32_t error_count = ((endpoint_descriptor.bmAttributes & 3) == 0b01) ? 0 : 3;
(void)is_control;
(void)is_isoch;
(void)is_bulk;
(void)is_interrupt;
XHCI::EndpointType endpoint_type;
switch ((endpoint_descriptor.bEndpointAddress & 0x80) | (endpoint_descriptor.bmAttributes & 0x03))
{
case 0x00:
case 0x00: ASSERT_NOT_REACHED();
case 0x80: endpoint_type = XHCI::EndpointType::Control; break;
case 0x01: endpoint_type = XHCI::EndpointType::IsochOut; break;
case 0x81: endpoint_type = XHCI::EndpointType::IsochIn; break;
@ -224,6 +228,16 @@ namespace Kernel
default: ASSERT_NOT_REACHED();
}
// FIXME: Streams
const uint32_t endpoint_id = (endpoint_descriptor.bEndpointAddress & 0x0F) * 2 + !!(endpoint_descriptor.bEndpointAddress & 0x80);
const uint32_t max_packet_size = (is_control || is_bulk) ? endpoint_descriptor.wMaxPacketSize : endpoint_descriptor.wMaxPacketSize & 0x07FF;
const uint32_t max_burst_size = (is_control || is_bulk) ? 0 : (endpoint_descriptor.wMaxPacketSize & 0x1800) >> 11;
const uint32_t max_esit_payload = max_packet_size * (max_burst_size + 1);
const uint32_t interval = determine_interval(endpoint_descriptor, m_speed_class);
const uint32_t average_trb_length = (is_control) ? 8 : max_esit_payload;
const uint32_t error_count = (is_isoch) ? 0 : 3;
auto& endpoint = m_endpoints[endpoint_id - 1];
ASSERT(!endpoint.transfer_ring);
@ -237,8 +251,7 @@ namespace Kernel
endpoint.dequeue_index = 0;
endpoint.enqueue_index = 0;
endpoint.cycle_bit = 1;
endpoint.callback = &XHCIDevice::on_interrupt_endpoint_event;
endpoint.data_region = TRY(DMARegion::create(endpoint.max_packet_size));
endpoint.callback = (is_interrupt || is_bulk) ? &XHCIDevice::on_interrupt_or_bulk_endpoint_event : nullptr;
memset(reinterpret_cast<void*>(endpoint.transfer_ring->vaddr()), 0, endpoint.transfer_ring->size());
@ -276,62 +289,27 @@ namespace Kernel
configure_endpoint.configure_endpoint_command.slot_id = m_slot_id;
TRY(m_controller.send_command(configure_endpoint));
if (endpoint_type == XHCI::EndpointType::InterruptIn)
{
auto& trb = *reinterpret_cast<volatile XHCI::TRB*>(endpoint.transfer_ring->vaddr());
memset(const_cast<XHCI::TRB*>(&trb), 0, sizeof(XHCI::TRB));
trb.normal.trb_type = XHCI::TRBType::Normal;
trb.normal.data_buffer_pointer = endpoint.data_region->paddr();
trb.normal.trb_transfer_length = endpoint.data_region->size();
trb.normal.td_size = 0;
trb.normal.interrupt_target = 0;
trb.normal.cycle_bit = 1;
trb.normal.interrupt_on_completion = 1;
trb.normal.interrupt_on_short_packet = 1;
advance_endpoint_enqueue(endpoint, false);
m_controller.doorbell_reg(m_slot_id) = endpoint_id;
}
else
{
dwarnln("Configured unsupported endpoint {2H}",
(endpoint_descriptor.bEndpointAddress & 0x80) | (endpoint_descriptor.bmAttributes & 0x03)
);
}
return {};
}
void XHCIDevice::on_interrupt_endpoint_event(XHCI::TRB trb)
void XHCIDevice::on_interrupt_or_bulk_endpoint_event(XHCI::TRB trb)
{
ASSERT(trb.trb_type == XHCI::TRBType::TransferEvent);
if (trb.transfer_event.completion_code != 1 && trb.transfer_event.completion_code != 13)
{
dwarnln("Interrupt endpoint got transfer event with completion code {}", +trb.transfer_event.completion_code);
dwarnln("Interrupt or bulk endpoint got transfer event with completion code {}", +trb.transfer_event.completion_code);
return;
}
const uint32_t endpoint_id = trb.transfer_event.endpoint_id;
auto& endpoint = m_endpoints[endpoint_id - 1];
ASSERT(endpoint.transfer_ring && endpoint.data_region);
const uint32_t transfer_length = endpoint.max_packet_size - trb.transfer_event.trb_transfer_length;
auto received_data = BAN::ConstByteSpan(reinterpret_cast<uint8_t*>(endpoint.data_region->vaddr()), transfer_length);
handle_input_data(received_data, endpoint_id);
const auto* transfer_trb_arr = reinterpret_cast<volatile XHCI::TRB*>(endpoint.transfer_ring->vaddr());
const uint32_t transfer_trb_index = (trb.transfer_event.trb_pointer - endpoint.transfer_ring->paddr()) / sizeof(XHCI::TRB);
const uint32_t original_len = transfer_trb_arr[transfer_trb_index].normal.trb_transfer_length;
auto& new_trb = *reinterpret_cast<volatile XHCI::TRB*>(endpoint.transfer_ring->vaddr() + endpoint.enqueue_index * sizeof(XHCI::TRB));
memset(const_cast<XHCI::TRB*>(&new_trb), 0, sizeof(XHCI::TRB));
new_trb.normal.trb_type = XHCI::TRBType::Normal;
new_trb.normal.data_buffer_pointer = endpoint.data_region->paddr();
new_trb.normal.trb_transfer_length = endpoint.max_packet_size;
new_trb.normal.td_size = 0;
new_trb.normal.interrupt_target = 0;
new_trb.normal.cycle_bit = endpoint.cycle_bit;
new_trb.normal.interrupt_on_completion = 1;
new_trb.normal.interrupt_on_short_packet = 1;
advance_endpoint_enqueue(endpoint, false);
m_controller.doorbell_reg(m_slot_id) = endpoint_id;
const uint32_t transfer_length = original_len - trb.transfer_event.trb_transfer_length;
handle_input_data(transfer_length, endpoint_id);
}
void XHCIDevice::on_transfer_event(const volatile XHCI::TRB& trb)
@ -495,6 +473,28 @@ namespace Kernel
return endpoint.transfer_count;
}
void XHCIDevice::send_data_buffer(uint8_t endpoint_id, paddr_t buffer, size_t buffer_len)
{
ASSERT(endpoint_id != 0);
auto& endpoint = m_endpoints[endpoint_id - 1];
ASSERT(buffer_len <= endpoint.max_packet_size);
auto& trb = *reinterpret_cast<volatile XHCI::TRB*>(endpoint.transfer_ring->vaddr() + endpoint.enqueue_index * sizeof(XHCI::TRB));
memset(const_cast<XHCI::TRB*>(&trb), 0, sizeof(XHCI::TRB));
trb.normal.trb_type = XHCI::TRBType::Normal;
trb.normal.data_buffer_pointer = buffer;
trb.normal.trb_transfer_length = buffer_len;
trb.normal.td_size = 0;
trb.normal.interrupt_target = 0;
trb.normal.cycle_bit = endpoint.cycle_bit;
trb.normal.interrupt_on_completion = 1;
trb.normal.interrupt_on_short_packet = 1;
advance_endpoint_enqueue(endpoint, false);
m_controller.doorbell_reg(m_slot_id) = endpoint_id;
}
void XHCIDevice::advance_endpoint_enqueue(Endpoint& endpoint, bool chain)
{
endpoint.enqueue_index++;

View File

@ -254,8 +254,6 @@ static void init2(void*)
TTY::initialize_devices();
MUST(Process::create_userspace({ 0, 0, 0, 0 }, "/usr/bin/init"_sv, {}));
auto console_path = MUST(BAN::String::formatted("/dev/{}", cmdline.console));
auto console_path_sv = console_path.sv();
MUST(Process::create_userspace({ 0, 0, 0, 0 }, "/usr/bin/init"_sv, BAN::Span<BAN::StringView>(&console_path_sv, 1)));

View File

@ -33,3 +33,5 @@ if [[ -z $BANAN_BOOTLOADER ]]; then
fi
export BANAN_CMAKE=$BANAN_TOOLCHAIN_PREFIX/bin/cmake
export BANAN_ROOT_PART_UUID='9C87D2AF-566A-4517-971A-57BA86EEA88D'

View File

@ -46,6 +46,15 @@ else
mkpart root ext2 2M 100%
fi
fdisk "$BANAN_DISK_IMAGE_PATH" >/dev/null << EOF
x
u
2
$BANAN_ROOT_PART_UUID
r
w
EOF
# create loop device
LOOP_DEV=$(sudo losetup --show -fP "$BANAN_DISK_IMAGE_PATH" || exit 1 )
PARTITION1=${LOOP_DEV}p1

View File

@ -44,7 +44,7 @@ install_grub_legacy() {
--boot-directory="$MOUNT_DIR/boot" \
$LOOP_DEV
sudo mkdir -p "$MOUNT_DIR/boot/grub"
sudo cp "$BANAN_TOOLCHAIN_DIR/grub-legacy-boot.cfg" "$MOUNT_DIR/boot/grub/grub.cfg"
sed "s/<ROOT>/UUID=$BANAN_ROOT_PART_UUID/" "$BANAN_TOOLCHAIN_DIR/grub-legacy-boot.cfg" | sudo tee "$MOUNT_DIR/boot/grub/grub.cfg" >/dev/null
sudo umount "$MOUNT_DIR"
}
@ -57,7 +57,7 @@ install_grub_uefi() {
sudo mount $PARTITION2 "$MOUNT_DIR"
sudo mkdir -p "$MOUNT_DIR/boot/grub"
sudo cp "$BANAN_TOOLCHAIN_DIR/grub-uefi.cfg" "$MOUNT_DIR/boot/grub/grub.cfg"
sed "s/<ROOT>/UUID=$BANAN_ROOT_PART_UUID/" "$BANAN_TOOLCHAIN_DIR/grub-uefi.cfg" | sudo tee "$MOUNT_DIR/boot/grub/grub.cfg" >/dev/null
sudo umount "$MOUNT_DIR"
}

View File

@ -15,6 +15,10 @@ fi
if [[ $BANAN_DISK_TYPE == "NVME" ]]; then
DISK_ARGS="-device nvme,serial=deadbeef,drive=disk"
elif [[ $BANAN_DISK_TYPE == "IDE" ]]; then
DISK_ARGS="-device piix3-ide,id=ide -device ide-hd,drive=disk,bus=ide.0"
elif [[ $BANAN_DISK_TYPE == "USB" ]]; then
DISK_ARGS="-device usb-storage,drive=disk"
else
DISK_ARGS="-device ahci,id=ahci -device ide-hd,drive=disk,bus=ahci.0"
fi

View File

@ -1,23 +1,23 @@
menuentry "banan-os" {
multiboot2 /boot/banan-os.kernel root=/dev/sda2
multiboot2 /boot/banan-os.kernel root=<ROOT>
}
menuentry "banan-os (no serial)" {
multiboot2 /boot/banan-os.kernel root=/dev/sda2 noserial
multiboot2 /boot/banan-os.kernel root=<ROOT> noserial
}
menuentry "banan-os (only serial)" {
multiboot2 /boot/banan-os.kernel root=/dev/sda2 console=ttyS0
multiboot2 /boot/banan-os.kernel root=<ROOT> console=ttyS0
}
menuentry "banan-os (no apic)" {
multiboot2 /boot/banan-os.kernel root=/dev/sda2 noapic
multiboot2 /boot/banan-os.kernel root=<ROOT> noapic
}
menuentry "banan-os (no apic, no serial)" {
multiboot2 /boot/banan-os.kernel root=/dev/sda2 noapic noserial
multiboot2 /boot/banan-os.kernel root=<ROOT> noapic noserial
}
menuentry "banan-os (no apic, only serial)" {
multiboot2 /boot/banan-os.kernel root=/dev/sda2 noapic console=ttyS0
multiboot2 /boot/banan-os.kernel root=<ROOT> noapic console=ttyS0
}

View File

@ -4,25 +4,25 @@ set root=(hd0,gpt2)
insmod all_video
menuentry "banan-os" {
multiboot2 /boot/banan-os.kernel root=/dev/sda2
multiboot2 /boot/banan-os.kernel root=<ROOT>
}
menuentry "banan-os (no serial)" {
multiboot2 /boot/banan-os.kernel root=/dev/sda2 noserial
multiboot2 /boot/banan-os.kernel root=<ROOT> noserial
}
menuentry "banan-os (only serial)" {
multiboot2 /boot/banan-os.kernel root=/dev/sda2 console=ttyS0
multiboot2 /boot/banan-os.kernel root=<ROOT> console=ttyS0
}
menuentry "banan-os (no apic)" {
multiboot2 /boot/banan-os.kernel root=/dev/sda2 noapic
multiboot2 /boot/banan-os.kernel root=<ROOT> noapic
}
menuentry "banan-os (no apic, no serial)" {
multiboot2 /boot/banan-os.kernel root=/dev/sda2 noapic noserial
multiboot2 /boot/banan-os.kernel root=<ROOT> noapic noserial
}
menuentry "banan-os (no apic, only serial)" {
multiboot2 /boot/banan-os.kernel root=/dev/sda2 noapic console=ttyS0
multiboot2 /boot/banan-os.kernel root=<ROOT> noapic console=ttyS0
}