OSDN Git Service

MochiBooterの大幅改造(ATA-PIOreadによるカーネルロード)、VMイメージ作成ツール追加など
[mochi/master.git] / src / booter / Driver / DriverAta.c
diff --git a/src/booter/Driver/DriverAta.c b/src/booter/Driver/DriverAta.c
new file mode 100644 (file)
index 0000000..2ac7c68
--- /dev/null
@@ -0,0 +1,323 @@
+/******************************************************************************/
+/* src/booter/Driver/DriverAta.c                                              */
+/*                                                                 2017/07/11 */
+/* Copyright (C) 2017 Mochi.                                                  */
+/******************************************************************************/
+/******************************************************************************/
+/* インクルード                                                               */
+/******************************************************************************/
+/* 共通ヘッダ */
+#include <stddef.h>
+#include <stdint.h>
+#include <hardware/ATA/ATA.h>
+#include <hardware/IA32/IA32Instruction.h>
+#include <hardware/I8259A/I8259A.h>
+#include <MLib/Basic/MLibBasic.h>
+
+/* 外部モジュールヘッダ */
+#include <Cmn.h>
+#include <Debug.h>
+#include <Driver.h>
+#include <IntMng.h>
+
+
+/******************************************************************************/
+/* 定義                                                                       */
+/******************************************************************************/
+/* デバッグトレースログ出力マクロ */
+#ifdef DEBUG_LOG_ENABLE
+#define DEBUG_LOG( ... )                   \
+    DebugLogOutput( CMN_MODULE_DRIVER_ATA, \
+                    __LINE__,              \
+                    __VA_ARGS__ )
+#else
+#define DEBUG_LOG( ... )
+#endif
+
+/** リトライ最大回数 */
+#define ATA_RETRY        ( 50000 )
+
+/* 割込みフラグ */
+#define ATA_INT_FLAG_ON  ( 1 )      /** 割込みフラグON  */
+#define ATA_INT_FLAG_OFF ( 0 )      /** 割込みフラグOFF */
+
+
+/******************************************************************************/
+/* ローカル関数プロトタイプ宣言                                               */
+/******************************************************************************/
+/* 状態待ち合わせ */
+static void AtaWaitStatus( uint8_t mask,
+                           uint8_t status );
+/* 割込み待ち合わせ */
+static void AtaWaitInterrupt( void );
+
+
+/******************************************************************************/
+/* グローバル変数定義                                                         */
+/******************************************************************************/
+/** 割込みフラグ */
+static volatile uint32_t gInterruptFlag;
+
+
+/******************************************************************************/
+/* グローバル関数定義                                                         */
+/******************************************************************************/
+/******************************************************************************/
+/**
+ * @brief           ATAドライバ初期化
+ * @details         ATAドライバを初期化する。
+ */
+/******************************************************************************/
+void DriverAtaInit( void )
+{
+    /* デバッグトレースログ出力 */
+    DEBUG_LOG( "%s() start.", __func__ );
+    
+    /* 割込みフラグ初期化 */
+    gInterruptFlag = ATA_INT_FLAG_OFF;
+    
+    /* 割込み許可設定 */
+    IntMngPicAllowIrq( I8259A_IRQ14 );
+    
+    /* 割込みハンドラ登録 */
+    IntMngHdlSet( INTMNG_PIC_VCTR_BASE + I8259A_IRQ14,
+                  DriverAtaHandler );
+    
+    /* デバッグトレースログ出力 */
+    DEBUG_LOG( "%s() end.", __func__ );
+    
+    return;
+}
+
+
+/******************************************************************************/
+/**
+ * @brief       ATA割込みハンドラ
+ * @details     ATAからの割込みを処理する。
+ * 
+ * @param[in]   intNo 割込み番号
+ */
+/******************************************************************************/
+void DriverAtaHandler( uint32_t intNo )
+{
+    /* デバッグトレースログ出力 *//*
+    DEBUG_LOG( "%s() start. intNo=%#X", __func__, intNo );*/
+    
+    /* 割込みフラグ設定 */
+    gInterruptFlag = ATA_INT_FLAG_ON;
+    
+    /* EOI命令発行 */
+    IntMngPicEoi( I8259A_IRQ14 );
+    
+    /* デバッグトレースログ出力 *//*
+    DEBUG_LOG( "%s() end.", __func__ );*/
+    
+    return;
+}
+
+
+/******************************************************************************/
+/**
+ * @brief           ディスク読み込み
+ * @details         ディスクからデータを読み込む
+ * 
+ * @param[in/out]   *pAddr データ格納先アドレス
+ * @param[in]       lba    ディスク上アドレス(LBA)
+ * @param[in]       size   読み込みサイズ(セクタ)
+ */
+/******************************************************************************/
+CmnRet_t DriverAtaRead( void     *pAddr,
+                        uint32_t lba,
+                        size_t   size    )
+{
+    uint8_t           status;        /* Status レジスタ値     */
+    volatile uint32_t sectorCnt;     /* 1コマンド読込みサイズ */
+    
+    /* デバッグトレースログ出力 */
+    DEBUG_LOG( "%s() start. *pAddr=%p, lba=%#X, size=%u",
+               __func__,
+               pAddr,
+               lba,
+               size );
+    
+    /* 1コマンド毎に繰り返し */
+    while ( size > 0 ) {
+        /* アイドル状態待ち合わせ */
+        AtaWaitStatus( ATA_STATUS_BSY | ATA_STATUS_DRQ, 0 );
+        
+        /* デバイスアドレス設定 */
+        IA32InstructionOutByte( ATA_PORT_DEV_HEAD, 0 );
+        
+        /* アイドル状態待ち合わせ */
+        AtaWaitStatus( ATA_STATUS_BSY | ATA_STATUS_DRQ, 0 );
+        
+        /* Featuresレジスタ設定 */
+        IA32InstructionOutByte( ATA_PORT_FEATURES, 0 );
+        
+        /* LBA設定 */
+        IA32InstructionOutByte( ATA_PORT_DEV_HEAD,
+                                ATA_DEV_HEAD_LBA | ATA_LBA_TO_DEV_HEAD( lba ) );
+        IA32InstructionOutByte( ATA_PORT_CYL_HIGH,
+                                ATA_LBA_TO_CYL_HIGH( lba ) );
+        IA32InstructionOutByte( ATA_PORT_CYL_LOW,
+                                ATA_LBA_TO_CYL_LOW( lba ) );
+        IA32InstructionOutByte( ATA_PORT_SECTOR_NUM,
+                                ATA_LBA_TO_SECTOR_NUM( lba ) );
+        
+        /* 読込みサイズ判定 */
+        if ( size >= ATA_SECTOR_CNT_MAX ) {
+            /* Sector Count 最大値以上 */
+            
+            /* 設定 */
+            sectorCnt  = ATA_SECTOR_CNT_MAX;    /* Sector Count */
+            size      -= ATA_SECTOR_CNT_MAX;    /* 読込みサイズ */
+            lba       += ATA_SECTOR_CNT_MAX;    /* LBA          */
+            
+            /* サイズ設定 */
+            IA32InstructionOutByte( ATA_PORT_SECTOR_CNT, 0 );
+            
+        } else {
+            /* Sector Count 最大値未満 */
+            
+            /* 設定 */
+            sectorCnt = size;                   /* Sector Count */
+            size      = 0;                      /* 読込みサイズ */
+            
+            /* サイズ設定 */
+            IA32InstructionOutByte( ATA_PORT_SECTOR_CNT, sectorCnt );
+        }
+        
+        /* 割込みフラグOFF */
+        gInterruptFlag = ATA_INT_FLAG_OFF;
+        
+        /* コマンド書き込み */
+        IA32InstructionOutByte( ATA_PORT_COMMAND, ATA_CMD_READ_SECTOR );
+        
+        /* デバッグトレースログ出力 */
+        DEBUG_LOG( "%s() command write. cnt=%u", __func__, sectorCnt );
+        
+        /* 1セクタサイズ毎繰り返し */
+        for ( ; sectorCnt > 0; sectorCnt-- ) {
+            /* 割り込み待ち合わせ */
+            AtaWaitInterrupt();
+            
+            /* アイドル状態待ち合わせ */
+            AtaWaitStatus( ATA_STATUS_BSY, 0 );
+            
+            /* ステータスレジスタ取得 */
+            IA32InstructionInByte( &status, ATA_PORT_STATUS );
+            
+            /* 割込みフラグOFF */
+            gInterruptFlag = ATA_INT_FLAG_OFF;
+            
+            /* データ転送要求有無判定 */
+            if ( MLIB_BASIC_HAVE_FLAG( status, ATA_STATUS_DRQ ) ) {
+                /* データ転送要求有 */
+                
+                /* デバッグトレースログ出力 */
+                DEBUG_LOG( "%s() read. pAddr=%p, sectorCnt=%u.",
+                           __func__,
+                           pAddr,
+                           sectorCnt );
+                
+                /* データ転送 */
+                IA32InstructionRepInsw( pAddr,
+                                        ATA_PORT_DATA,
+                                        ATA_TRANSFER_COUNT );
+                
+                /* 格納先アドレス更新 */
+                pAddr += ATA_TRANSFER_COUNT * 2;
+                
+            } else {
+                /* データ転送要求無 */
+                
+                /* デバッグトレースログ出力 */
+                DEBUG_LOG( "%s() end. ret=CMN_FAILURE", __func__ );
+                
+                return CMN_FAILURE;
+            }
+            
+            /* 1PIO転送サイクル待ち */
+            IA32InstructionInByte( &status, ATA_PORT_ALT_STATUS );
+        }
+    }
+    
+    /* デバッグトレースログ出力 */
+    DEBUG_LOG( "%s() end. ret=CMN_SUCCESS", __func__ );
+    
+    return CMN_SUCCESS;
+}
+
+
+/******************************************************************************/
+/* ローカル関数定義                                                           */
+/******************************************************************************/
+/******************************************************************************/
+/**
+ * @brief           状態待ち合わせ
+ * @details         Statusレジスタが指定状態になるのを待ち合わせる。
+ * 
+ * @param[in]       mask   レジスタマスク値
+ * @param[in]       status 状態
+ */
+/******************************************************************************/
+static void AtaWaitStatus( uint8_t mask,
+                           uint8_t status )
+{
+    uint8_t  value;     /* Statusレジスタ値 */
+    uint32_t retry;     /* リトライ回数     */
+    
+    /* デバッグトレースログ出力 *//*
+    DEBUG_LOG( "%s() start. mask=%#X, status=%#X", __func__, mask, status );*/
+    
+    /* アイドル状態になるまで繰り返し */
+    for ( retry = 0; retry <= ATA_RETRY; retry++ ) {
+        /* Statusレジスタ読込 */
+        IA32InstructionInByte( &value, ATA_PORT_STATUS );
+        
+        /* 状態判定 */
+        if ( ( value & mask ) == status ) {
+            /* 状態一致 */
+            
+            /* デバッグトレースログ出力 *//*
+            DEBUG_LOG( "%s() end." );*/
+            
+            return;
+        }
+    }
+    
+    /* デバッグトレースログ出力 */
+    DEBUG_LOG( "%s() retry out.", __func__ );
+    
+    /* アボート */
+    CmnAbort();
+}
+
+
+/******************************************************************************/
+/**
+ * @brief           割込み待ち合わせ
+ * @details         ATAデバイスから割り込みが発生するのを待ち合わせる。
+ */
+/******************************************************************************/
+static void AtaWaitInterrupt( void )
+{
+    /* デバッグトレースログ出力 *//*
+    DEBUG_LOG( "%s() start.", __func__ );*/
+    
+    /* 割込みが発生するまで繰り返し */
+    while ( gInterruptFlag == ATA_INT_FLAG_OFF ) {
+        /* 未発生 */
+        
+        /* hlt命令実行 */
+        IA32InstructionHlt();
+    }
+    
+    /* デバッグトレースログ出力 *//*
+    DEBUG_LOG( "%s() end.", __func__ );*/
+    
+    return;
+}
+
+
+/******************************************************************************/