forked from Bananymous/banan-os
				
			
			update main #1
			
				
			
		
		
		
	| 
						 | 
				
			
			@ -53,6 +53,8 @@ set(KERNEL_SOURCES
 | 
			
		|||
	kernel/Semaphore.cpp
 | 
			
		||||
	kernel/SpinLock.cpp
 | 
			
		||||
	kernel/SSP.cpp
 | 
			
		||||
	kernel/Storage/ATA/AHCI/Controller.cpp
 | 
			
		||||
	kernel/Storage/ATA/AHCI/Device.cpp
 | 
			
		||||
	kernel/Storage/ATA/ATABus.cpp
 | 
			
		||||
	kernel/Storage/ATA/ATAController.cpp
 | 
			
		||||
	kernel/Storage/ATA/ATADevice.cpp
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -0,0 +1,43 @@
 | 
			
		|||
#pragma once
 | 
			
		||||
 | 
			
		||||
#include <BAN/Array.h>
 | 
			
		||||
#include <BAN/RefPtr.h>
 | 
			
		||||
#include <kernel/InterruptController.h>
 | 
			
		||||
#include <kernel/Memory/DMARegion.h>
 | 
			
		||||
#include <kernel/PCI.h>
 | 
			
		||||
#include <kernel/Storage/ATA/AHCI/Definitions.h>
 | 
			
		||||
 | 
			
		||||
namespace Kernel
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
	class AHCIController final : public StorageController, public Interruptable
 | 
			
		||||
	{
 | 
			
		||||
		BAN_NON_COPYABLE(AHCIController);
 | 
			
		||||
		BAN_NON_MOVABLE(AHCIController);
 | 
			
		||||
 | 
			
		||||
	public:
 | 
			
		||||
		~AHCIController();
 | 
			
		||||
 | 
			
		||||
		virtual void handle_irq() override;
 | 
			
		||||
 | 
			
		||||
		uint32_t command_slot_count() const { return m_command_slot_count; }
 | 
			
		||||
 | 
			
		||||
	private:
 | 
			
		||||
		AHCIController(PCI::Device& pci_device)
 | 
			
		||||
			: m_pci_device(pci_device)
 | 
			
		||||
		{ }
 | 
			
		||||
		BAN::ErrorOr<void> initialize();
 | 
			
		||||
		BAN::Optional<AHCIPortType> check_port_type(volatile HBAPortMemorySpace&);
 | 
			
		||||
 | 
			
		||||
	private:
 | 
			
		||||
		PCI::Device& m_pci_device;
 | 
			
		||||
		BAN::UniqPtr<PCI::BarRegion> m_abar;
 | 
			
		||||
 | 
			
		||||
		BAN::Array<AHCIDevice*, 32> m_devices;
 | 
			
		||||
 | 
			
		||||
		uint32_t m_command_slot_count { 0 };
 | 
			
		||||
 | 
			
		||||
		friend class ATAController;
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,294 @@
 | 
			
		|||
#pragma once
 | 
			
		||||
 | 
			
		||||
#include <stdint.h>
 | 
			
		||||
 | 
			
		||||
#define FIS_TYPE_REGISTER_H2D		0x27
 | 
			
		||||
#define FIS_TYPE_REGISTER_D2H		0x34
 | 
			
		||||
#define FIS_TYPE_DMA_ACT			0x39
 | 
			
		||||
#define FIS_TYPE_DMA_SETUP			0x41
 | 
			
		||||
#define FIS_TYPE_DATA				0x46
 | 
			
		||||
#define FIS_TYPE_BIST				0x58
 | 
			
		||||
#define FIS_TYPE_PIO_SETUP			0x5F
 | 
			
		||||
#define FIS_TYPE_SET_DEVIVE_BITS	0xA1
 | 
			
		||||
 | 
			
		||||
#define SATA_CAP_SUPPORTS64	(1 << 31)
 | 
			
		||||
 | 
			
		||||
#define SATA_GHC_AHCI_ENABLE		(1 << 31)
 | 
			
		||||
#define SATA_GHC_INTERRUPT_ENABLE	(1 << 1)
 | 
			
		||||
 | 
			
		||||
#define	SATA_SIG_ATA	0x00000101
 | 
			
		||||
#define	SATA_SIG_ATAPI	0xEB140101
 | 
			
		||||
#define	SATA_SIG_SEMB	0xC33C0101
 | 
			
		||||
#define	SATA_SIG_PM		0x96690101
 | 
			
		||||
 | 
			
		||||
#define HBA_PORT_IPM_ACTIVE		1
 | 
			
		||||
#define HBA_PORT_DET_PRESENT	3
 | 
			
		||||
 | 
			
		||||
#define HBA_PxCMD_ST	0x0001
 | 
			
		||||
#define HBA_PxCMD_FRE	0x0010
 | 
			
		||||
#define HBA_PxCMD_FR	0x4000
 | 
			
		||||
#define HBA_PxCMD_CR	0x8000
 | 
			
		||||
 | 
			
		||||
namespace Kernel
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
	static constexpr uint32_t s_hba_prdt_count { 8 };
 | 
			
		||||
 | 
			
		||||
	struct FISRegisterH2D
 | 
			
		||||
	{
 | 
			
		||||
		uint8_t  fis_type;			// FIS_TYPE_REGISTER_H2D
 | 
			
		||||
	
 | 
			
		||||
		uint8_t  pm_port : 4;		// Port multiplier
 | 
			
		||||
		uint8_t  __reserved0 : 3;
 | 
			
		||||
		uint8_t  c : 1;				// 1: Command, 0: Control
 | 
			
		||||
	
 | 
			
		||||
		uint8_t  command;
 | 
			
		||||
		uint8_t  feature_lo;		// Feature register, 7:0
 | 
			
		||||
	
 | 
			
		||||
		uint8_t  lba0;				// LBA low register, 7:0
 | 
			
		||||
		uint8_t  lba1;				// LBA mid register, 15:8
 | 
			
		||||
		uint8_t  lba2;				// LBA high register, 23:16
 | 
			
		||||
		uint8_t  device;
 | 
			
		||||
	
 | 
			
		||||
		uint8_t  lba3;				// LBA register, 31:24
 | 
			
		||||
		uint8_t  lba4;				// LBA register, 39:32
 | 
			
		||||
		uint8_t  lba5;				// LBA register, 47:40
 | 
			
		||||
		uint8_t  feature_hi;		// Feature register, 15:8
 | 
			
		||||
	
 | 
			
		||||
		uint8_t  count_lo;			// Count register, 7:0
 | 
			
		||||
		uint8_t  count_hi;			// Count register, 15:8
 | 
			
		||||
		uint8_t  icc;				// Isochronous command completion
 | 
			
		||||
		uint8_t  control;
 | 
			
		||||
	
 | 
			
		||||
		uint8_t  __reserved1[4];
 | 
			
		||||
	} __attribute__((packed));
 | 
			
		||||
 | 
			
		||||
	struct FISRegisterD2H
 | 
			
		||||
	{
 | 
			
		||||
		uint8_t  fis_type;			// FIS_TYPE_REGISTER_D2H
 | 
			
		||||
	
 | 
			
		||||
		uint8_t  pm_port : 4;		// Port multiplier
 | 
			
		||||
		uint8_t  __reserved0 : 2;
 | 
			
		||||
		uint8_t  i : 1;				// Interrupt bit
 | 
			
		||||
		uint8_t  __reserved1 : 1;
 | 
			
		||||
	
 | 
			
		||||
		uint8_t  status;
 | 
			
		||||
		uint8_t  error;
 | 
			
		||||
	
 | 
			
		||||
		uint8_t  lba0;				// LBA low register, 7:0
 | 
			
		||||
		uint8_t  lba1;				// LBA mid register, 15:8
 | 
			
		||||
		uint8_t  lba2;				// LBA high register, 23:16
 | 
			
		||||
		uint8_t  device;
 | 
			
		||||
	
 | 
			
		||||
		uint8_t  lba3;				// LBA register, 31:24
 | 
			
		||||
		uint8_t  lba4;				// LBA register, 39:32
 | 
			
		||||
		uint8_t  lba5;				// LBA register, 47:40
 | 
			
		||||
		uint8_t  __reserved2;
 | 
			
		||||
	
 | 
			
		||||
		uint8_t  count_lo;			// Count register, 7:0
 | 
			
		||||
		uint8_t  count_hi;			// Count register, 15:8
 | 
			
		||||
		uint8_t  __reserved3[2];
 | 
			
		||||
	
 | 
			
		||||
		uint8_t  __reserved4[4];
 | 
			
		||||
	} __attribute__((packed));
 | 
			
		||||
 | 
			
		||||
	struct FISDataBI
 | 
			
		||||
	{
 | 
			
		||||
		uint8_t  fis_type;			// FIS_TYPE_DATA
 | 
			
		||||
	
 | 
			
		||||
		uint8_t  pm_port : 4;		// Port multiplier
 | 
			
		||||
		uint8_t  __reserved0 : 4;
 | 
			
		||||
	
 | 
			
		||||
		uint8_t  __reserved1[2];
 | 
			
		||||
 | 
			
		||||
		uint32_t data[0];			// Payload (1 - 2048 dwords)
 | 
			
		||||
	} __attribute__((packed));
 | 
			
		||||
 | 
			
		||||
	struct SetDeviceBitsD2H
 | 
			
		||||
	{
 | 
			
		||||
		uint8_t fis_type;		// FIS_TYPE_SET_DEVICE_BITS
 | 
			
		||||
 | 
			
		||||
		uint8_t pm_port : 4;	// Port multiplier
 | 
			
		||||
		uint8_t __reserved0 : 2;
 | 
			
		||||
		uint8_t i : 1;			// Interrupt bit
 | 
			
		||||
		uint8_t n : 1;			// Notification bit
 | 
			
		||||
 | 
			
		||||
		uint8_t status;
 | 
			
		||||
		uint8_t error;
 | 
			
		||||
 | 
			
		||||
		uint32_t __reserved1;
 | 
			
		||||
	} __attribute__((packed));
 | 
			
		||||
 | 
			
		||||
	struct PIOSetupD2H
 | 
			
		||||
	{
 | 
			
		||||
		uint8_t  fis_type;			// FIS_TYPE_PIO_SETUP
 | 
			
		||||
	
 | 
			
		||||
		uint8_t  pm_port : 4;		// Port multiplier
 | 
			
		||||
		uint8_t  __reserved0 : 1;
 | 
			
		||||
		uint8_t  d : 1;				// Data transfer direction, 1 - device to host
 | 
			
		||||
		uint8_t  i : 1;				// Interrupt bit
 | 
			
		||||
		uint8_t  __reserved1 : 1;
 | 
			
		||||
	
 | 
			
		||||
		uint8_t  status;
 | 
			
		||||
		uint8_t  error;
 | 
			
		||||
	
 | 
			
		||||
		uint8_t  lba0;				// LBA low register, 7:0
 | 
			
		||||
		uint8_t  lba1;				// LBA mid register, 15:8
 | 
			
		||||
		uint8_t  lba2;				// LBA high register, 23:16
 | 
			
		||||
		uint8_t  device;
 | 
			
		||||
	
 | 
			
		||||
		uint8_t  lba3;				// LBA register, 31:24
 | 
			
		||||
		uint8_t  lba4;				// LBA register, 39:32
 | 
			
		||||
		uint8_t  lba5;				// LBA register, 47:40
 | 
			
		||||
		uint8_t  __reserved2;
 | 
			
		||||
	
 | 
			
		||||
		uint8_t  count_lo;			// Count register, 7:0
 | 
			
		||||
		uint8_t  count_hi;			// Count register, 15:8
 | 
			
		||||
		uint8_t  __reserved3;
 | 
			
		||||
		uint8_t  e_status;			// New value of status register
 | 
			
		||||
	
 | 
			
		||||
		uint16_t tc;				// Transfer count
 | 
			
		||||
		uint8_t  __reserved4[2];
 | 
			
		||||
	} __attribute__((packed));
 | 
			
		||||
 | 
			
		||||
	struct DMASetupBI
 | 
			
		||||
	{
 | 
			
		||||
		uint8_t  fis_type;				// FIS_TYPE_DMA_SETUP
 | 
			
		||||
	
 | 
			
		||||
		uint8_t  pm_port : 4;			// Port multiplier
 | 
			
		||||
		uint8_t  __reserved0 : 1;
 | 
			
		||||
		uint8_t  d : 1;					// Data transfer direction, 1 - device to host
 | 
			
		||||
		uint8_t  i : 1;					// Interrupt bit
 | 
			
		||||
		uint8_t  a : 1;					// Auto-activate. Specifies if DMA Activate FIS is needed
 | 
			
		||||
	
 | 
			
		||||
		uint8_t  __reserved1[2];
 | 
			
		||||
 | 
			
		||||
		uint64_t dma_buffer_id;			// DMA Buffer Identifier. Used to Identify DMA buffer in host memory.
 | 
			
		||||
										// SATA Spec says host specific and not in Spec. Trying AHCI spec might work.
 | 
			
		||||
 | 
			
		||||
		uint32_t __reserved2;
 | 
			
		||||
 | 
			
		||||
		uint32_t dma_buffer_offset;		// Byte offset into buffer. First 2 bits must be 0
 | 
			
		||||
 | 
			
		||||
		uint32_t dma_transfer_count;	// Number of bytes to transfer. Bit 0 must be 0
 | 
			
		||||
 | 
			
		||||
		uint32_t __reserved3;
 | 
			
		||||
	} __attribute__((packed));
 | 
			
		||||
 | 
			
		||||
	struct HBAPortMemorySpace
 | 
			
		||||
	{
 | 
			
		||||
		uint32_t clb;		// command list base address, 1K-byte aligned
 | 
			
		||||
		uint32_t clbu;		// command list base address upper 32 bits
 | 
			
		||||
		uint32_t fb;		// FIS base address, 256-byte aligned
 | 
			
		||||
		uint32_t fbu;		// FIS base address upper 32 bits
 | 
			
		||||
		uint32_t is;		// interrupt status
 | 
			
		||||
		uint32_t ie;		// interrupt enable
 | 
			
		||||
		uint32_t cmd;		// command and status
 | 
			
		||||
		uint32_t __reserved0;
 | 
			
		||||
		uint32_t tfd;		// task file data
 | 
			
		||||
		uint32_t sig;		// signature
 | 
			
		||||
		uint32_t ssts;		// SATA status (SCR0:SStatus)
 | 
			
		||||
		uint32_t sctl;		// SATA control (SCR2:SControl)
 | 
			
		||||
		uint32_t serr;		// SATA error (SCR1:SError)
 | 
			
		||||
		uint32_t sact;		// SATA active (SCR3:SActive)
 | 
			
		||||
		uint32_t ci;		// command issue
 | 
			
		||||
		uint32_t sntf;		// SATA notification (SCR4:SNotification)
 | 
			
		||||
		uint32_t fbs;		// FIS-based switch control
 | 
			
		||||
		uint32_t __reserved1[11];
 | 
			
		||||
		uint32_t vendor[4];
 | 
			
		||||
	} __attribute__((packed));
 | 
			
		||||
 | 
			
		||||
	struct HBAGeneralMemorySpace
 | 
			
		||||
	{
 | 
			
		||||
		uint32_t cap;		// Host capability
 | 
			
		||||
		uint32_t ghc;		// Global host control
 | 
			
		||||
		uint32_t is;		// Interrupt status
 | 
			
		||||
		uint32_t pi;		// Port implemented
 | 
			
		||||
		uint32_t vs;		// Version
 | 
			
		||||
		uint32_t ccc_ctl;	// Command completion coalescing control
 | 
			
		||||
		uint32_t ccc_pts;	// Command completion coalescing ports
 | 
			
		||||
		uint32_t em_loc;	// 0x1C, Enclosure management location
 | 
			
		||||
		uint32_t em_ctl;	// 0x20, Enclosure management control
 | 
			
		||||
		uint32_t cap2;		// 0x24, Host capabilities extended
 | 
			
		||||
		uint32_t bohc;		// 0x28, BIOS/OS handoff control and status
 | 
			
		||||
	
 | 
			
		||||
		uint8_t  __reserved0[0xA0-0x2C];
 | 
			
		||||
	
 | 
			
		||||
		uint8_t  vendor[0x100-0xA0];
 | 
			
		||||
	
 | 
			
		||||
		HBAPortMemorySpace ports[0]; // 1 - 32 ports
 | 
			
		||||
	} __attribute__((packed));
 | 
			
		||||
 | 
			
		||||
	struct ReceivedFIS
 | 
			
		||||
	{
 | 
			
		||||
		DMASetupBI			dsfis;
 | 
			
		||||
		uint8_t				pad0[4];
 | 
			
		||||
	
 | 
			
		||||
		PIOSetupD2H			psfis;
 | 
			
		||||
		uint8_t				pad1[12];
 | 
			
		||||
	
 | 
			
		||||
		FISRegisterD2H		rfis;
 | 
			
		||||
		uint8_t				pad2[4];
 | 
			
		||||
	
 | 
			
		||||
		SetDeviceBitsD2H	sdbfis;
 | 
			
		||||
	
 | 
			
		||||
		uint8_t				ufis[64];
 | 
			
		||||
	
 | 
			
		||||
		uint8_t				__reserved[0x100-0xA0];
 | 
			
		||||
	} __attribute__((packed));
 | 
			
		||||
 | 
			
		||||
	struct HBACommandHeader
 | 
			
		||||
	{
 | 
			
		||||
		uint8_t  cfl : 5;	// Command FIS length in DWORDS, 2 ~ 16
 | 
			
		||||
		uint8_t  a : 1;		// ATAPI
 | 
			
		||||
		uint8_t  w : 1;		// Write, 1: H2D, 0: D2H
 | 
			
		||||
		uint8_t  p : 1;		// Prefetchable
 | 
			
		||||
	
 | 
			
		||||
		uint8_t  r : 1;		// Reset
 | 
			
		||||
		uint8_t  b : 1;		// BIST
 | 
			
		||||
		uint8_t  c : 1;		// Clear busy upon R_OK
 | 
			
		||||
		uint8_t  __reserved0 : 1;
 | 
			
		||||
		uint8_t  pmp : 4;	// Port multiplier port
 | 
			
		||||
	
 | 
			
		||||
		uint16_t prdtl;		// Physical region descriptor table length in entries
 | 
			
		||||
	
 | 
			
		||||
		volatile uint32_t prdbc;	// Physical region descriptor byte count transferred
 | 
			
		||||
	
 | 
			
		||||
		uint32_t ctba;		// Command table descriptor base address
 | 
			
		||||
		uint32_t ctbau;		// Command table descriptor base address upper 32 bits
 | 
			
		||||
	
 | 
			
		||||
		uint32_t __reserved1[4];
 | 
			
		||||
	} __attribute__((packed));
 | 
			
		||||
 | 
			
		||||
	struct HBAPRDTEntry
 | 
			
		||||
	{
 | 
			
		||||
		uint32_t dba;			// Data base address
 | 
			
		||||
		uint32_t dbau;			// Data base address upper 32 bits
 | 
			
		||||
		uint32_t __reserved0;
 | 
			
		||||
 | 
			
		||||
		uint32_t dbc : 22;		// Byte count, 4M max
 | 
			
		||||
		uint32_t __reserved1 : 9;
 | 
			
		||||
		uint32_t i : 1;			// Interrupt on completion
 | 
			
		||||
	} __attribute__((packed));
 | 
			
		||||
 | 
			
		||||
	struct HBACommandTable
 | 
			
		||||
	{
 | 
			
		||||
		uint8_t cfis[64];
 | 
			
		||||
		uint8_t acmd[16];
 | 
			
		||||
		uint8_t __reserved[48];
 | 
			
		||||
		HBAPRDTEntry prdt_entry[s_hba_prdt_count];
 | 
			
		||||
	} __attribute__((packed));
 | 
			
		||||
 | 
			
		||||
	enum class AHCIPortType
 | 
			
		||||
	{
 | 
			
		||||
		NONE,
 | 
			
		||||
		SATA,
 | 
			
		||||
		SATAPI,
 | 
			
		||||
		SEMB,
 | 
			
		||||
		PM
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	class AHCIController;
 | 
			
		||||
	class AHCIDevice;
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,49 @@
 | 
			
		|||
#pragma once
 | 
			
		||||
 | 
			
		||||
#include <kernel/Semaphore.h>
 | 
			
		||||
#include <kernel/Storage/ATA/AHCI/Definitions.h>
 | 
			
		||||
#include <kernel/Storage/ATA/ATADevice.h>
 | 
			
		||||
 | 
			
		||||
namespace Kernel
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
	class AHCIDevice final : public detail::ATABaseDevice
 | 
			
		||||
	{
 | 
			
		||||
	public:
 | 
			
		||||
		static BAN::ErrorOr<BAN::RefPtr<AHCIDevice>> create(BAN::RefPtr<AHCIController>, volatile HBAPortMemorySpace*);
 | 
			
		||||
		~AHCIDevice() = default;
 | 
			
		||||
 | 
			
		||||
	private:
 | 
			
		||||
		AHCIDevice(BAN::RefPtr<AHCIController> controller, volatile HBAPortMemorySpace* port)
 | 
			
		||||
			: m_controller(controller)
 | 
			
		||||
			, m_port(port)
 | 
			
		||||
		{ }
 | 
			
		||||
		BAN::ErrorOr<void> initialize();
 | 
			
		||||
		BAN::ErrorOr<void> allocate_buffers();
 | 
			
		||||
		BAN::ErrorOr<void> rebase();
 | 
			
		||||
		BAN::ErrorOr<void> read_identify_data();
 | 
			
		||||
 | 
			
		||||
		virtual BAN::ErrorOr<void> read_sectors_impl(uint64_t lba, uint64_t sector_count, uint8_t* buffer) override;
 | 
			
		||||
		virtual BAN::ErrorOr<void> write_sectors_impl(uint64_t lba, uint64_t sector_count, const uint8_t* buffer) override;
 | 
			
		||||
		BAN::ErrorOr<void> send_command_and_block(uint64_t lba, uint64_t sector_count, Command command);
 | 
			
		||||
 | 
			
		||||
		BAN::Optional<uint32_t> find_free_command_slot();
 | 
			
		||||
 | 
			
		||||
		void handle_irq();
 | 
			
		||||
		void block_until_irq();
 | 
			
		||||
 | 
			
		||||
	private:
 | 
			
		||||
		BAN::RefPtr<AHCIController> m_controller;
 | 
			
		||||
		volatile HBAPortMemorySpace* const m_port;
 | 
			
		||||
		
 | 
			
		||||
		BAN::UniqPtr<DMARegion> m_dma_region;
 | 
			
		||||
		// Intermediate read/write buffer
 | 
			
		||||
		// TODO: can we read straight to user buffer?
 | 
			
		||||
		BAN::UniqPtr<DMARegion> m_data_dma_region;
 | 
			
		||||
 | 
			
		||||
		volatile bool m_has_got_irq { false };
 | 
			
		||||
 | 
			
		||||
		friend class AHCIController;
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -33,7 +33,11 @@
 | 
			
		|||
#define ATA_STATUS_BSY				0x80
 | 
			
		||||
 | 
			
		||||
#define ATA_COMMAND_READ_SECTORS	0x20
 | 
			
		||||
#define ATA_COMMAND_READ_DMA		0xC8
 | 
			
		||||
#define ATA_COMMAND_READ_DMA_EXT	0x25
 | 
			
		||||
#define ATA_COMMAND_WRITE_SECTORS	0x30
 | 
			
		||||
#define ATA_COMMAND_WRITE_DMA		0xCA
 | 
			
		||||
#define ATA_COMMAND_WRITE_DMA_EXT	0x35
 | 
			
		||||
#define ATA_COMMAND_IDENTIFY_PACKET	0xA1
 | 
			
		||||
#define ATA_COMMAND_CACHE_FLUSH		0xE7
 | 
			
		||||
#define ATA_COMMAND_IDENTIFY		0xEC
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -0,0 +1,120 @@
 | 
			
		|||
#include <kernel/Memory/Heap.h>
 | 
			
		||||
#include <kernel/Memory/PageTable.h>
 | 
			
		||||
#include <kernel/Storage/ATA/AHCI/Controller.h>
 | 
			
		||||
#include <kernel/Storage/ATA/AHCI/Definitions.h>
 | 
			
		||||
#include <kernel/Storage/ATA/AHCI/Device.h>
 | 
			
		||||
 | 
			
		||||
namespace Kernel
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
	BAN::ErrorOr<void> AHCIController::initialize()
 | 
			
		||||
	{
 | 
			
		||||
		m_abar = TRY(m_pci_device.allocate_bar_region(5));
 | 
			
		||||
		if (m_abar->type() != PCI::BarType::MEM)
 | 
			
		||||
		{
 | 
			
		||||
			dprintln("ABAR not MMIO");
 | 
			
		||||
			return BAN::Error::from_errno(EINVAL);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		auto& abar_mem = *(volatile HBAGeneralMemorySpace*)m_abar->vaddr();
 | 
			
		||||
		if (!(abar_mem.ghc & SATA_GHC_AHCI_ENABLE))
 | 
			
		||||
		{
 | 
			
		||||
			dprintln("Controller not in AHCI mode");
 | 
			
		||||
			return BAN::Error::from_errno(EINVAL);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// Enable interrupts and bus mastering
 | 
			
		||||
		m_pci_device.enable_bus_mastering();
 | 
			
		||||
		m_pci_device.enable_pin_interrupts();
 | 
			
		||||
		set_irq(TRY(m_pci_device.get_irq()));
 | 
			
		||||
		enable_interrupt();
 | 
			
		||||
		abar_mem.ghc = abar_mem.ghc | SATA_GHC_INTERRUPT_ENABLE;
 | 
			
		||||
 | 
			
		||||
		m_command_slot_count = ((abar_mem.cap >> 8) & 0x1F) + 1;
 | 
			
		||||
 | 
			
		||||
		uint32_t pi = abar_mem.pi;
 | 
			
		||||
		for (uint32_t i = 0; i < 32 && pi; i++, pi >>= 1)
 | 
			
		||||
		{
 | 
			
		||||
			// Verify we don't access abar outside of its bounds
 | 
			
		||||
			if (sizeof(HBAGeneralMemorySpace) + i * sizeof(HBAPortMemorySpace) > m_abar->size())
 | 
			
		||||
				break;
 | 
			
		||||
 | 
			
		||||
			if (!(pi & 1))
 | 
			
		||||
				continue;
 | 
			
		||||
			
 | 
			
		||||
			auto type = check_port_type(abar_mem.ports[i]);
 | 
			
		||||
			if (!type.has_value())
 | 
			
		||||
				continue;
 | 
			
		||||
 | 
			
		||||
			if (type.value() != AHCIPortType::SATA)
 | 
			
		||||
			{
 | 
			
		||||
				dprintln("Non-SATA devices not supported");
 | 
			
		||||
				continue;
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			auto device = AHCIDevice::create(this, &abar_mem.ports[i]);
 | 
			
		||||
			if (device.is_error())
 | 
			
		||||
			{
 | 
			
		||||
				dprintln("{}", device.error());
 | 
			
		||||
				continue;
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			m_devices[i] = device.value().ptr();
 | 
			
		||||
			if (auto ret = m_devices[i]->initialize(); ret.is_error())
 | 
			
		||||
			{
 | 
			
		||||
				dprintln("{}", ret.error());
 | 
			
		||||
				m_devices[i] = nullptr;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		return {};
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	AHCIController::~AHCIController()
 | 
			
		||||
	{
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void AHCIController::handle_irq()
 | 
			
		||||
	{
 | 
			
		||||
		auto& abar_mem = *(volatile HBAGeneralMemorySpace*)m_abar->vaddr();
 | 
			
		||||
 | 
			
		||||
		uint32_t is = abar_mem.is;
 | 
			
		||||
		for (uint8_t i = 0; i < 32; i++)
 | 
			
		||||
		{
 | 
			
		||||
			if (is & (1 << i))
 | 
			
		||||
			{
 | 
			
		||||
				ASSERT(m_devices[i]);
 | 
			
		||||
				m_devices[i]->handle_irq();
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		abar_mem.is = is;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	BAN::Optional<AHCIPortType> AHCIController::check_port_type(volatile HBAPortMemorySpace& port)
 | 
			
		||||
	{
 | 
			
		||||
		uint32_t ssts = port.ssts;
 | 
			
		||||
		uint8_t ipm = (ssts >> 8) & 0x0F;
 | 
			
		||||
		uint8_t det = (ssts >> 0) & 0x0F;
 | 
			
		||||
 | 
			
		||||
		if (det != HBA_PORT_DET_PRESENT)
 | 
			
		||||
			return {};
 | 
			
		||||
		if (ipm != HBA_PORT_IPM_ACTIVE)
 | 
			
		||||
			return {};
 | 
			
		||||
 | 
			
		||||
		switch (port.sig)
 | 
			
		||||
		{
 | 
			
		||||
			case SATA_SIG_ATA:
 | 
			
		||||
				return AHCIPortType::SATA;
 | 
			
		||||
			case SATA_SIG_ATAPI:
 | 
			
		||||
				return AHCIPortType::SATAPI;
 | 
			
		||||
			case SATA_SIG_PM:
 | 
			
		||||
				return AHCIPortType::PM;
 | 
			
		||||
			case SATA_SIG_SEMB:
 | 
			
		||||
				return AHCIPortType::SEMB;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		return {};
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,276 @@
 | 
			
		|||
#include <kernel/Storage/ATA/AHCI/Controller.h>
 | 
			
		||||
#include <kernel/Storage/ATA/AHCI/Device.h>
 | 
			
		||||
#include <kernel/Storage/ATA/ATADefinitions.h>
 | 
			
		||||
#include <kernel/Thread.h>
 | 
			
		||||
#include <kernel/Timer/Timer.h>
 | 
			
		||||
 | 
			
		||||
namespace Kernel
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
	static void start_cmd(volatile HBAPortMemorySpace* port)
 | 
			
		||||
	{
 | 
			
		||||
		while (port->cmd & HBA_PxCMD_CR)
 | 
			
		||||
			continue;
 | 
			
		||||
		port->cmd = port->cmd | HBA_PxCMD_FRE;
 | 
			
		||||
		port->cmd = port->cmd | HBA_PxCMD_ST; 
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	static void stop_cmd(volatile HBAPortMemorySpace* port)
 | 
			
		||||
	{
 | 
			
		||||
		port->cmd = port->cmd & ~HBA_PxCMD_ST;
 | 
			
		||||
		port->cmd = port->cmd & ~HBA_PxCMD_FRE;
 | 
			
		||||
		while (port->cmd & (HBA_PxCMD_FR | HBA_PxCMD_CR))
 | 
			
		||||
			continue;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	BAN::ErrorOr<BAN::RefPtr<AHCIDevice>> AHCIDevice::create(BAN::RefPtr<AHCIController> controller, volatile HBAPortMemorySpace* port)
 | 
			
		||||
	{
 | 
			
		||||
		auto* device_ptr = new AHCIDevice(controller, port);
 | 
			
		||||
		if (device_ptr == nullptr)
 | 
			
		||||
			return BAN::Error::from_errno(ENOMEM);
 | 
			
		||||
		return BAN::RefPtr<AHCIDevice>::adopt(device_ptr);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	BAN::ErrorOr<void> AHCIDevice::initialize()
 | 
			
		||||
	{
 | 
			
		||||
		TRY(allocate_buffers());
 | 
			
		||||
		TRY(rebase());
 | 
			
		||||
 | 
			
		||||
		// enable interrupts
 | 
			
		||||
		m_port->ie = 0xFFFFFFFF;
 | 
			
		||||
 | 
			
		||||
		TRY(read_identify_data());
 | 
			
		||||
		TRY(detail::ATABaseDevice::initialize({ (const uint16_t*)m_data_dma_region->vaddr(), m_data_dma_region->size() }));
 | 
			
		||||
 | 
			
		||||
		return {};
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	BAN::ErrorOr<void> AHCIDevice::allocate_buffers()
 | 
			
		||||
	{
 | 
			
		||||
		uint32_t command_slot_count = m_controller->command_slot_count();
 | 
			
		||||
		size_t needed_bytes = (sizeof(HBACommandHeader) + sizeof(HBACommandTable)) * command_slot_count + sizeof(ReceivedFIS);
 | 
			
		||||
 | 
			
		||||
		m_dma_region = TRY(DMARegion::create(needed_bytes));
 | 
			
		||||
		memset((void*)m_dma_region->vaddr(), 0x00, m_dma_region->size());
 | 
			
		||||
 | 
			
		||||
		m_data_dma_region = TRY(DMARegion::create(PAGE_SIZE));
 | 
			
		||||
		memset((void*)m_data_dma_region->vaddr(), 0x00, m_data_dma_region->size());
 | 
			
		||||
		
 | 
			
		||||
		return {};
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	BAN::ErrorOr<void> AHCIDevice::rebase()
 | 
			
		||||
	{
 | 
			
		||||
		ASSERT(m_dma_region);
 | 
			
		||||
 | 
			
		||||
		uint32_t command_slot_count = m_controller->command_slot_count();
 | 
			
		||||
 | 
			
		||||
		stop_cmd(m_port);
 | 
			
		||||
 | 
			
		||||
		paddr_t fis_paddr = m_dma_region->paddr();
 | 
			
		||||
		m_port->fb = fis_paddr & 0xFFFFFFFF;
 | 
			
		||||
		m_port->fbu = fis_paddr >> 32;
 | 
			
		||||
 | 
			
		||||
		paddr_t command_list_paddr = fis_paddr + sizeof(ReceivedFIS);
 | 
			
		||||
		m_port->clb = command_list_paddr & 0xFFFFFFFF;
 | 
			
		||||
		m_port->clbu = command_list_paddr >> 32;
 | 
			
		||||
 | 
			
		||||
		auto* command_headers = (HBACommandHeader*)m_dma_region->paddr_to_vaddr(command_list_paddr);
 | 
			
		||||
		paddr_t command_table_paddr = command_list_paddr + command_slot_count * sizeof(HBACommandHeader);
 | 
			
		||||
		for (uint32_t i = 0; i < command_slot_count; i++)
 | 
			
		||||
		{
 | 
			
		||||
			uint64_t command_table_entry_paddr = command_table_paddr + i * sizeof(HBACommandTable);
 | 
			
		||||
			command_headers[i].prdtl = s_hba_prdt_count;
 | 
			
		||||
			command_headers[i].ctba = command_table_entry_paddr & 0xFFFFFFFF;
 | 
			
		||||
			command_headers[i].ctbau = command_table_entry_paddr >> 32;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		start_cmd(m_port);
 | 
			
		||||
 | 
			
		||||
		return {};
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	BAN::ErrorOr<void> AHCIDevice::read_identify_data()
 | 
			
		||||
	{
 | 
			
		||||
		ASSERT(m_data_dma_region);
 | 
			
		||||
 | 
			
		||||
		m_port->is = ~(uint32_t)0;
 | 
			
		||||
 | 
			
		||||
		auto slot = find_free_command_slot();
 | 
			
		||||
		ASSERT(slot.has_value());
 | 
			
		||||
 | 
			
		||||
		auto& command_header = ((HBACommandHeader*)m_dma_region->paddr_to_vaddr(m_port->clb))[slot.value()];
 | 
			
		||||
		command_header.cfl = sizeof(FISRegisterH2D) / sizeof(uint32_t);
 | 
			
		||||
		command_header.w = 0;
 | 
			
		||||
		command_header.prdtl = 1;
 | 
			
		||||
 | 
			
		||||
		auto& command_table = *(HBACommandTable*)m_dma_region->paddr_to_vaddr(command_header.ctba);
 | 
			
		||||
		memset(&command_table, 0x00, sizeof(HBACommandTable));
 | 
			
		||||
		command_table.prdt_entry[0].dba = m_data_dma_region->paddr();
 | 
			
		||||
		command_table.prdt_entry[0].dbc = 511;
 | 
			
		||||
		command_table.prdt_entry[0].i = 1;
 | 
			
		||||
 | 
			
		||||
		auto& command = *(FISRegisterH2D*)command_table.cfis;
 | 
			
		||||
		command.fis_type = FIS_TYPE_REGISTER_H2D;
 | 
			
		||||
		command.c = 1;
 | 
			
		||||
		command.command = ATA_COMMAND_IDENTIFY;
 | 
			
		||||
 | 
			
		||||
		while (m_port->tfd & (ATA_STATUS_BSY | ATA_STATUS_DRQ))
 | 
			
		||||
			continue;
 | 
			
		||||
 | 
			
		||||
		m_port->ci = 1 << slot.value();
 | 
			
		||||
 | 
			
		||||
		// FIXME: timeout
 | 
			
		||||
		do { block_until_irq(); } while (m_port->ci & (1 << slot.value()));
 | 
			
		||||
 | 
			
		||||
		return {};
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	static void print_error(uint16_t error)
 | 
			
		||||
	{
 | 
			
		||||
		dprintln("Disk error:");
 | 
			
		||||
		if (error & (1 << 11))
 | 
			
		||||
			dprintln("  Internal Error");
 | 
			
		||||
		if (error & (1 << 10))
 | 
			
		||||
			dprintln("  Protocol Error");
 | 
			
		||||
		if (error & (1 << 9))
 | 
			
		||||
			dprintln("  Persistent Communication or Data Integrity Error");
 | 
			
		||||
		if (error & (1 << 8))
 | 
			
		||||
			dprintln("  Transient Data Integrity Error");
 | 
			
		||||
		if (error & (1 << 1))
 | 
			
		||||
			dprintln("  Recovered Communications Error");
 | 
			
		||||
		if (error & (1 << 0))
 | 
			
		||||
			dprintln("  Recovered Data Integrity Error");
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void AHCIDevice::handle_irq()
 | 
			
		||||
	{
 | 
			
		||||
		ASSERT(!m_has_got_irq);
 | 
			
		||||
		uint16_t err = m_port->serr & 0xFFFF;
 | 
			
		||||
		if (err)
 | 
			
		||||
			print_error(err);
 | 
			
		||||
		m_has_got_irq = true;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void AHCIDevice::block_until_irq()
 | 
			
		||||
	{
 | 
			
		||||
		while (!__sync_bool_compare_and_swap(&m_has_got_irq, true, false))
 | 
			
		||||
			__builtin_ia32_pause();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	BAN::ErrorOr<void> AHCIDevice::read_sectors_impl(uint64_t lba, uint64_t sector_count, uint8_t* buffer)
 | 
			
		||||
	{
 | 
			
		||||
		const size_t sectors_per_page = PAGE_SIZE / sector_size();
 | 
			
		||||
		for (uint64_t sector_off = 0; sector_off < sector_count; sector_off += sectors_per_page)
 | 
			
		||||
		{
 | 
			
		||||
			uint64_t to_read = BAN::Math::min<uint64_t>(sector_count - sector_off, sectors_per_page);
 | 
			
		||||
 | 
			
		||||
			TRY(send_command_and_block(lba + sector_off, to_read, Command::Read));
 | 
			
		||||
			memcpy(buffer + sector_off * sector_size(), (void*)m_data_dma_region->vaddr(), to_read * sector_size());
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		return {};
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	BAN::ErrorOr<void> AHCIDevice::write_sectors_impl(uint64_t lba, uint64_t sector_count, const uint8_t* buffer)
 | 
			
		||||
	{
 | 
			
		||||
		const size_t sectors_per_page = PAGE_SIZE / sector_size();
 | 
			
		||||
		for (uint64_t sector_off = 0; sector_off < sector_count; sector_off += sectors_per_page)
 | 
			
		||||
		{
 | 
			
		||||
			uint64_t to_read = BAN::Math::min<uint64_t>(sector_count - sector_off, sectors_per_page);
 | 
			
		||||
 | 
			
		||||
			memcpy((void*)m_data_dma_region->vaddr(), buffer + sector_off * sector_size(), to_read * sector_size());
 | 
			
		||||
			TRY(send_command_and_block(lba + sector_off, to_read, Command::Write));
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		return {};
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	BAN::ErrorOr<void> AHCIDevice::send_command_and_block(uint64_t lba, uint64_t sector_count, Command command)
 | 
			
		||||
	{
 | 
			
		||||
		ASSERT(m_dma_region);
 | 
			
		||||
		ASSERT(m_data_dma_region);
 | 
			
		||||
		ASSERT(0 < sector_count && sector_count <= 0xFFFF + 1);
 | 
			
		||||
		
 | 
			
		||||
		ASSERT(sector_count * sector_size() <= m_data_dma_region->size());
 | 
			
		||||
 | 
			
		||||
		m_port->is = ~(uint32_t)0;
 | 
			
		||||
 | 
			
		||||
		auto slot = find_free_command_slot();
 | 
			
		||||
		ASSERT(slot.has_value());
 | 
			
		||||
		
 | 
			
		||||
		auto& command_header = ((HBACommandHeader*)m_dma_region->paddr_to_vaddr(m_port->clb))[slot.value()];
 | 
			
		||||
		command_header.cfl = sizeof(FISRegisterH2D) / sizeof(uint32_t);
 | 
			
		||||
		command_header.prdtl = 1;
 | 
			
		||||
		switch (command)
 | 
			
		||||
		{
 | 
			
		||||
			case Command::Read:
 | 
			
		||||
				command_header.w = 0;
 | 
			
		||||
				break;
 | 
			
		||||
			case Command::Write:
 | 
			
		||||
				command_header.w = 1;
 | 
			
		||||
				break;
 | 
			
		||||
			default:
 | 
			
		||||
				ASSERT_NOT_REACHED();
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		auto& command_table = *(HBACommandTable*)m_dma_region->paddr_to_vaddr(command_header.ctba);
 | 
			
		||||
		memset(&command_table, 0x00, sizeof(HBACommandTable));
 | 
			
		||||
		command_table.prdt_entry[0].dba = m_data_dma_region->paddr() & 0xFFFFFFFF;
 | 
			
		||||
		command_table.prdt_entry[0].dbau = m_data_dma_region->paddr() >> 32;
 | 
			
		||||
		command_table.prdt_entry[0].dbc = sector_count * sector_size() - 1;
 | 
			
		||||
		command_table.prdt_entry[0].i = 1;
 | 
			
		||||
 | 
			
		||||
		auto& fis_command = *(FISRegisterH2D*)command_table.cfis;
 | 
			
		||||
		memset(&fis_command, 0x00, sizeof(FISRegisterH2D));
 | 
			
		||||
		fis_command.fis_type = FIS_TYPE_REGISTER_H2D;
 | 
			
		||||
		fis_command.c = 1;
 | 
			
		||||
 | 
			
		||||
		bool need_extended = lba >= (1 << 28) || sector_count > 0xFF;
 | 
			
		||||
		ASSERT (!need_extended || (m_command_set & ATA_COMMANDSET_LBA48_SUPPORTED));
 | 
			
		||||
 | 
			
		||||
		switch (command)
 | 
			
		||||
		{
 | 
			
		||||
			case Command::Read:
 | 
			
		||||
				fis_command.command = need_extended ? ATA_COMMAND_READ_DMA_EXT : ATA_COMMAND_READ_DMA;
 | 
			
		||||
				break;
 | 
			
		||||
			case Command::Write:
 | 
			
		||||
				fis_command.command = need_extended ? ATA_COMMAND_WRITE_DMA_EXT : ATA_COMMAND_WRITE_DMA;
 | 
			
		||||
				break;
 | 
			
		||||
			default:
 | 
			
		||||
				ASSERT_NOT_REACHED();
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		fis_command.lba0 = (lba >>  0) & 0xFF;
 | 
			
		||||
		fis_command.lba1 = (lba >>  8) & 0xFF;
 | 
			
		||||
		fis_command.lba2 = (lba >> 16) & 0xFF;
 | 
			
		||||
		fis_command.device = 1 << 6;	// LBA mode
 | 
			
		||||
	
 | 
			
		||||
		fis_command.lba3 = (lba >> 24) & 0xFF;
 | 
			
		||||
		fis_command.lba4 = (lba >> 32) & 0xFF;
 | 
			
		||||
		fis_command.lba5 = (lba >> 40) & 0xFF;
 | 
			
		||||
	
 | 
			
		||||
		fis_command.count_lo = (sector_count >> 0) & 0xFF;
 | 
			
		||||
		fis_command.count_hi = (sector_count >> 8) & 0xFF;
 | 
			
		||||
 | 
			
		||||
		while (m_port->tfd & (ATA_STATUS_BSY | ATA_STATUS_DRQ))
 | 
			
		||||
			continue;
 | 
			
		||||
 | 
			
		||||
		m_port->ci = 1 << slot.value();
 | 
			
		||||
 | 
			
		||||
		// FIXME: timeout
 | 
			
		||||
		do { block_until_irq(); } while (m_port->ci & (1 << slot.value()));
 | 
			
		||||
 | 
			
		||||
		return {};
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	BAN::Optional<uint32_t> AHCIDevice::find_free_command_slot()
 | 
			
		||||
	{
 | 
			
		||||
		uint32_t slots = m_port->sact | m_port->ci;
 | 
			
		||||
		for (uint32_t i = 0; i < m_controller->command_slot_count(); i++, slots >>= 1)
 | 
			
		||||
			if (!(slots & 1))
 | 
			
		||||
				return i;
 | 
			
		||||
		return {};
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -1,4 +1,5 @@
 | 
			
		|||
#include <kernel/FS/DevFS/FileSystem.h>
 | 
			
		||||
#include <kernel/Storage/ATA/AHCI/Controller.h>
 | 
			
		||||
#include <kernel/Storage/ATA/ATABus.h>
 | 
			
		||||
#include <kernel/Storage/ATA/ATAController.h>
 | 
			
		||||
#include <kernel/Storage/ATA/ATADefinitions.h>
 | 
			
		||||
| 
						 | 
				
			
			@ -20,8 +21,8 @@ namespace Kernel
 | 
			
		|||
				dwarnln("unsupported DMA ATA Controller");
 | 
			
		||||
				return BAN::Error::from_errno(ENOTSUP);
 | 
			
		||||
			case 0x06:
 | 
			
		||||
				dwarnln("unsupported SATA Controller");
 | 
			
		||||
				return BAN::Error::from_errno(ENOTSUP);
 | 
			
		||||
				controller_ptr = new AHCIController(pci_device);
 | 
			
		||||
				break;
 | 
			
		||||
			default:
 | 
			
		||||
				ASSERT_NOT_REACHED();
 | 
			
		||||
		}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										12
									
								
								qemu.sh
								
								
								
								
							
							
						
						
									
										12
									
								
								qemu.sh
								
								
								
								
							| 
						 | 
				
			
			@ -1,8 +1,10 @@
 | 
			
		|||
#!/bin/bash
 | 
			
		||||
set -e
 | 
			
		||||
 | 
			
		||||
qemu-system-$BANAN_ARCH										\
 | 
			
		||||
	-m 128													\
 | 
			
		||||
	-smp 2													\
 | 
			
		||||
	-drive format=raw,media=disk,file=${DISK_IMAGE_PATH}	\
 | 
			
		||||
	$@														\
 | 
			
		||||
qemu-system-$BANAN_ARCH											\
 | 
			
		||||
	-m 128														\
 | 
			
		||||
	-smp 2														\
 | 
			
		||||
	-drive format=raw,id=disk,file=${DISK_IMAGE_PATH},if=none	\
 | 
			
		||||
	-device ahci,id=ahci										\
 | 
			
		||||
	-device ide-hd,drive=disk,bus=ahci.0						\
 | 
			
		||||
	$@															\
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue