OSDN Git Service

カーネルイメージ作成ツール追加
[mochi/master.git] / src / tools / makedisk / makedisk.c
1 /******************************************************************************/
2 /* src/tools/makedisk/makedisk.c                                              */
3 /*                                                                 2017/07/11 */
4 /* Copyright (C) 2017 Mochi.                                                  */
5 /******************************************************************************/
6 /******************************************************************************/
7 /* インクルード                                                               */
8 /******************************************************************************/
9 #include <errno.h>
10 #include <fcntl.h>
11 #include <stdarg.h>
12 #include <stdbool.h>
13 #include <stdint.h>
14 #include <stdio.h>
15 #include <stdlib.h>
16 #include <string.h>
17 #include <unistd.h>
18 #include <sys/stat.h>
19 #include <sys/types.h>
20
21
22 /******************************************************************************/
23 /* 定義                                                                       */
24 /******************************************************************************/
25 /* パーティションテーブル定義 */
26 #define PT_STATUS_BOOT          ( 0x80 )    /** ブート可能 */
27 #define PT_TYPE_MOCHI_BOOTER    ( 0x30 )    /** MochiBooter用パーティション */
28 #define PT_TYPE_MOCHI_KERNEL    ( 0x31 )    /** MochiKernel用パーティション */
29
30 /* 引数定義 */
31 #define OPTION_CYLINDER_DEFAULT ( 10 )      /** 引数シリンダ数デフォルト値 */
32 #define OPTION_HEAD_DEFAULT     ( 16 )      /** 引数ヘッド数デフォルト値   */
33 #define OPTION_SECTOR_DEFAULT   ( 63 )      /** 引数セクタ数デフォルト値   */
34
35 /* シリンダ定義 */
36 #define CYLINDER_MIN            (    0 )    /** シリンダ最小値 */
37 #define CYLINDER_MAX            ( 1023 )    /** シリンダ最大値 */
38
39 /* ヘッド定義 */
40 #define HEAD_MIN                (   0 )     /** セクタ最小値 */
41 #define HEAD_MAX                ( 254 )     /** セクタ最大値 */
42
43 /* セクタ定義 */
44 #define SECTOR_MIN              (  1 )      /** セクタ最小値 */
45 #define SECTOR_MAX              ( 63 )      /** セクタ最大値 */
46
47 /** バッファサイズ */
48 #define BUFFER_SIZE             ( 512 )     /** 読込みバッファサイズ */
49
50 /** アボートマクロ */
51 #define ABORT( ... )                    \
52     {                                   \
53         /* エラー出力 */                \
54         fprintf( stderr, __VA_ARGS__ ); \
55         fprintf( stderr, "\n" );        \
56                                         \
57         /* USAGE出力 */                 \
58         printUsage( EXIT_FAILURE );     \
59     }
60
61 /** CS設定マクロ */
62 #define SET_CYL_SEC( _CYLINDER, _SECTOR )   \
63     ( ( ( _CYLINDER & 0x0300 ) << 6 ) |     \
64       ( ( _SECTOR   & 0x003F ) << 8 ) |     \
65       (   _CYLINDER & 0x00FF        )   )
66
67 /** CYLINDER取得マクロ */
68 #define GET_CYLINDER( _CYLSEC )     \
69     ( ( ( _CYLSEC >> 6 ) & 0x0300 ) | ( _CYLSEC & 0x00FF ) )
70
71 /** SECTOR取得マクロ */
72 #define GET_SECTOR( _CYLSEC ) ( ( _CYLSEC >> 8 ) & 0x3F )
73
74 /** CHSアドレス */
75 typedef struct {
76     uint16_t cylSec;            /**< シリンダ&セクタ */
77     uint8_t  head;              /**< ヘッド          */
78 }  __attribute__( ( packed ) ) chs_t;
79
80 /** パーティションテーブル */
81 typedef struct {
82     uint8_t  status;            /**< ステータス           */
83     chs_t    chsFirstAddr;      /**< CHS先頭アドレス      */
84     uint8_t  type;              /**< パーティションタイプ */
85     chs_t    chsLastAddr;       /**< CHS最後尾アドレス    */
86     uint32_t lbaFirstAddr;      /**< LBA先頭アドレス      */
87     uint32_t lbaSize;           /**< LBAサイズ            */
88 } __attribute__( ( packed ) ) pt_t;
89
90 /** MBR */
91 typedef struct {
92     uint8_t code[ 446 ];        /**< ブートストラップコード */
93     pt_t    partitionTbl[ 4 ];  /**< パーティションテーブル */
94     uint8_t signature[ 2 ];     /**< ブートシグネチャ       */
95 } __attribute__( ( packed ) ) mbr_t;
96
97
98 /******************************************************************************/
99 /* ローカル関数プロトタイプ宣言                                               */
100 /******************************************************************************/
101 /* オプションチェック */
102 static void checkOptions( int32_t argNum,
103                           char    *pArg[],
104                           char    **ppDiskPath,
105                           char    **ppIplPath,
106                           char    **ppBootPath,
107                           char    **ppKernelPath );
108 /* CHSアドレス取得 */
109 static chs_t getChs( uint32_t lba );
110
111 /* USAGE出力 */
112 static void printUsage( int status );
113
114 /* IPLバイナリ書込み */
115 static void writeIpl( int  diskFd,
116                       char *pIplPath );
117
118 /* ブートローダバイナリ書込み */
119 static chs_t writeBoot( int   diskFd,
120                         char  *pBootPath,
121                         chs_t chsFirstAddr );
122
123 /* カーネルバイナリ書込み */
124 static chs_t writeKernel( int   diskFd,
125                           char  *pKernelPath,
126                           chs_t chsFirstAddr  );
127
128 /* パーティションエントリ書込み */
129 static void writePartitionEntry( int      diskFd,
130                                  uint32_t no,
131                                  pt_t     *pPe    );
132
133
134 /******************************************************************************/
135 /* グローバル変数定義                                                         */
136 /******************************************************************************/
137 uint32_t cylinder;  /* 仮想ディスクのシリンダ数 */
138 uint32_t head;      /* 仮想ディスクのヘッド数   */
139 uint32_t sector;    /* 仮想ディスクのセクタ数   */
140
141
142 /******************************************************************************/
143 /* グローバル関数定義                                                         */
144 /******************************************************************************/
145 /******************************************************************************/
146 /**
147  * @brief       makedisk
148  * @details     仮想マシン用ディスクイメージを作成する。
149  * 
150  * param[in]    argNum  引数の数
151  * param[in]    *pArg[] 引数
152  * 
153  * retval       EXIT_SUCCESS 正常終了
154  * retval       EXIT_FAILURE 異常終了
155  */
156 /******************************************************************************/
157 int main( int  argNum,
158           char *pArg[] )
159 {
160     int      diskFd;        /* 仮想ディスクファイルディスクリプタ */
161     char     *pDiskPath;    /* 仮想ディスクパス                   */
162     char     *pIplPath;     /* IPLバイナリパス                    */
163     char     *pBootPath;    /* ブートローダバイナリパス           */
164     char     *pKernelPath;  /* カーネルバイナリパス               */
165     char     end;           /* 仮想ディスク最終バイト             */
166     chs_t    chs;           /* CHSアドレス                        */
167     off_t    offset;        /* オフセット                         */
168     int32_t  size;          /* 書込みサイズ                       */
169     
170     /* 初期化 */
171     end = 0;
172     memset( &chs, 0, sizeof ( chs_t ) );
173     
174     /* オプションチェック */
175     checkOptions( argNum,
176                   pArg,
177                   &pDiskPath,
178                   &pIplPath,
179                   &pBootPath,
180                   &pKernelPath );
181     
182     /* 仮想ディスクオープン */
183     diskFd = open( pDiskPath,
184                    O_RDWR | O_CREAT | O_TRUNC,
185                    S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH );
186     
187     /* オープン結果判定 */
188     if ( diskFd == -1 ) {
189         /* 失敗 */
190         
191         /* アボート */
192         ABORT( "ERROR(%04u): Can't open %s. errno=%d.\n",
193                __LINE__,
194                pDiskPath,
195                errno );
196     }
197     
198     /* IPLバイナリ書込み */
199     writeIpl( diskFd, pIplPath );
200     
201     /* ブートローダバイナリ書込み */
202     chs.cylSec   = SET_CYL_SEC( 0, 1 );
203     chs.head     = 1;
204     chs = writeBoot( diskFd, pBootPath, chs );
205     
206     /* カーネルバイナリ書込み */
207     chs.cylSec = SET_CYL_SEC( GET_CYLINDER( chs.cylSec ) + 1, 1 );
208     chs.head   = 0;
209     chs = writeKernel( diskFd, pKernelPath, chs );
210     
211     /* 仮想ディスクファイルサイズチェック */
212     if ( GET_CYLINDER( chs.cylSec ) < cylinder ) {
213         /* 指定サイズ未達 */
214         
215         /* 仮想ディスクシーク */
216         offset = lseek( diskFd, cylinder * head * sector * 512 - 1, SEEK_SET );
217         
218         /* シーク結果判定 */
219         if ( ( int32_t ) offset != ( cylinder * head * sector * 512 - 1 ) ) {
220             /* 失敗 */
221             
222             /* アボート */
223             ABORT( "ERROR(%04u): Can't seek at the disk image. ret=%d, errno=%d.\n",
224                    __LINE__,
225                    ( int32_t ) offset,
226                    errno );
227         }
228         
229         /* 書込み */
230         size = ( int32_t ) write( diskFd, &end, 1 );
231         
232         /* 書込み結果判定 */
233         if ( size != 1 ) {
234             /* 失敗 */
235             
236             /* アボート */
237             ABORT( "ERROR(%04u): Can't write %s. ret=%d, errno=%d.\n",
238                    __LINE__,
239                    pDiskPath,
240                    size,
241                    errno );
242         }
243         
244     } else {
245         /* 指定サイズ過達 */
246         
247         /* アボート */
248         ABORT( "ERROR(%04u): Overwrite.CHS=%u/%u/%u > %u/%u/%u.\n",
249                __LINE__,
250                GET_CYLINDER( chs.cylSec ),
251                chs.head,
252                GET_SECTOR( chs.cylSec ),
253                cylinder,
254                head,
255                sector );
256     }
257     
258     /* 仮想ディスククローズ */
259     close( diskFd );
260     
261     /* 正常終了 */
262     return EXIT_SUCCESS;
263 }
264
265
266 /******************************************************************************/
267 /* ローカル関数定義                                                           */
268 /******************************************************************************/
269 /******************************************************************************/
270 /**
271  * @brief       オプションチェック
272  * @details     オプションが許容可能な値かチェックする。
273  * 
274  * @param[in]   argNum        引数の数
275  * @param[in]   *pArg[]       引数
276  * @param[out]  *ppDiskPath   仮想ディスクのファイルパス
277  * @param[out]  *ppIplPath    IPLバイナリのファイルパス
278  * @param[out]  *ppBootPath   ブートローダバイナリのファイルパス
279  * @param[out]  *ppKernelPath カーネルバイナリのファイルパス
280  */
281 /******************************************************************************/
282 static void checkOptions( int32_t argNum,
283                           char    *pArg[],
284                           char    **ppDiskPath,
285                           char    **ppIplPath,
286                           char    **ppBootPath,
287                           char    **ppKernelPath )
288 {
289     char opt;   /* オプション文字 */
290     
291     /* 初期化 */
292     *ppDiskPath   = NULL;                   /* 仮想ディスクパス         */
293     *ppIplPath    = NULL;                   /* IPLバイナリパス          */
294     *ppBootPath   = NULL;                   /* ブートローダバイナリパス */
295     *ppKernelPath = NULL;                   /* カーネルバイナルパス     */
296     cylinder      = OPTION_CYLINDER_DEFAULT;/* デフォルトシリンダ       */
297     head          = OPTION_HEAD_DEFAULT;    /* デフォルトヘッド         */
298     sector        = OPTION_SECTOR_DEFAULT;  /* デフォルトセクタ         */
299     
300     /* オプションが無くなるまで繰り返し */
301     while ( true ) {
302         /* オプション取得 */
303         opt = getopt( argNum, pArg, "o:i:b:k:C:H:S:h" );
304         
305         /* 取得結果判定 */
306         if ( opt == -1 ) {
307             /* オプション無し */
308             break;
309             
310         } else if ( opt == 'o' ) {
311             /* 仮想ディスクパス */
312             *ppDiskPath = optarg;
313             
314         } else if ( opt == 'i' ) {
315             /* IPLバイナリパス */
316             *ppIplPath = optarg;
317             
318         } else if ( opt == 'b' ) {
319             /* ブートローダバイナリパス */
320             *ppBootPath = optarg;
321             
322         } else if ( opt == 'k' ) {
323             /* カーネルバイナリパス */
324             *ppKernelPath = optarg;
325             
326         } else if ( opt == 'C' ) {
327             /* シリンダ */
328             cylinder = ( uint32_t ) atoi( optarg );
329             
330         } else if ( opt == 'H' ) {
331             /* ヘッダ */
332             head = ( uint32_t ) atoi( optarg );
333             
334         } else if ( opt == 'S' ) {
335             /* セクタ */
336             sector = ( uint32_t ) atoi( optarg );
337             
338         } else if ( opt == 'h' ) {
339             /* ヘルプ */
340             
341             /* USAGE出力して終了 */
342             printUsage( EXIT_SUCCESS );
343             
344         } else {
345             /* 他 */
346             
347             /* アボート */
348             ABORT( "ERROR(%04u): Unknown option!\n", __LINE__ );
349         }
350     }
351     
352     /* 仮想ディスクパス設定チェック */
353     if ( *ppDiskPath == NULL ) {
354         /* 未設定 */
355         
356         /* アボート */
357         ABORT( "ERROR(%04u): No '-o' option!\n", __LINE__ );
358     }
359     
360     /* IPLバイナリパス設定チェック */
361     if ( *ppIplPath == NULL ) {
362         /* 未設定 */
363         
364         /* アボート */
365         ABORT( "ERROR(%04u): No '-i' option!\n", __LINE__ );
366     }
367     
368     /* ブートローダバイナリパス設定チェック */
369     if ( *ppBootPath == NULL ) {
370         /* 未設定 */
371         
372         /* アボート */
373         ABORT( "ERROR(%04u): No '-b' option!\n", __LINE__ );
374     }
375     
376     /* カーネルバイナリパス設定チェック */
377     if ( *ppKernelPath == NULL ) {
378         /* 未設定 */
379         
380         /* アボート */
381         ABORT( "ERROR(%04u): No '-k' option!\n", __LINE__ );
382     }
383     
384     /* シリンダ値チェック */
385     if ( !( ( CYLINDER_MIN <= cylinder     ) &&
386             ( cylinder     <= CYLINDER_MAX )    ) ) {
387         /* 範囲外 */
388         
389         /* アボート */
390         ABORT( "ERROR(%04u): cylinder(%u) is out of range(%u-%u).\n",
391                __LINE__,
392                cylinder,
393                CYLINDER_MIN,
394                CYLINDER_MAX );
395     }
396     
397     /* ヘッド値チェック */
398     if ( !( ( HEAD_MIN <= head     ) &&
399             ( head     <= HEAD_MAX )    ) ) {
400         /* 範囲外 */
401         
402         /* アボート */
403         ABORT( "ERROR(%04u): Head(%u) is out of range(%u-%u).\n",
404                __LINE__,
405                head,
406                HEAD_MIN,
407                HEAD_MAX );
408     }
409     
410     /* セクタ値チェック */
411     if ( !( ( SECTOR_MIN <= sector     ) &&
412             ( sector     <= SECTOR_MAX )    ) ) {
413         /* 範囲外 */
414         
415         /* アボート */
416         ABORT( "ERROR(%04u): Sector(%u) is out of range(%u-%u).\n",
417                __LINE__,
418                sector,
419                CYLINDER_MIN,
420                CYLINDER_MAX );
421     }
422     
423     return;
424 }
425
426
427 /******************************************************************************/
428 /**
429  * @brief       CHSアドレス取得
430  * @details     LBAアドレスをCHSアドレスに変換して取得する。
431  * 
432  * @param[in]   lba LBAアドレス
433  * 
434  * @return      CHSアドレス
435  */
436 /******************************************************************************/
437 static chs_t getChs( uint32_t lba )
438 {
439     chs_t chs;  /* CHSアドレス */
440     
441     /* 初期化 */
442     memset( &chs, 0, sizeof ( chs_t ) );
443     
444     /* CHSアドレス設定 */
445     chs.cylSec   = SET_CYL_SEC( ( lba / sector ) / head,
446                                 lba % sector + 1 );
447     chs.head     = ( lba / sector ) % head;
448     
449     return chs;
450 }
451
452
453 /******************************************************************************/
454 /**
455  * @brief       USAGE出力
456  * @details     USAGEを出力しプログラムを終了する。
457  * 
458  * @param[in]   status 終了ステータス
459  */
460 /******************************************************************************/
461 static void printUsage( int status )
462 {
463     /* USAGE出力 */
464     fprintf( stderr, "USAGE: makedisk -o [FILE] -b [FILE] -k [FILE] [OPTION]...\n"                                 );
465     fprintf( stderr, "\n"                                                                                          );
466     fprintf( stderr, "Option:\n"                                                                                   );
467     fprintf( stderr, "  -o FILE   specify the output FILE that is a disk image.\n"                                 );
468     fprintf( stderr, "  -i FILE   specify the input FILE that is a IPL binary.\n"                                  );
469     fprintf( stderr, "  -b FILE   specify the input FILE that is a boot loader binary.\n"                          );
470     fprintf( stderr, "  -k FILE   specify the input FILE that is a kernel binary.\n"                               );
471     fprintf( stderr, "  -C NUMBER specify the NUMBER of cylinders.(default:%u)\n",         OPTION_CYLINDER_DEFAULT );
472     fprintf( stderr, "  -H NUMBER specify the NUMBER of heads.(default:%u)\n",             OPTION_HEAD_DEFAULT     );
473     fprintf( stderr, "  -S NUMBER specify the NUMBER of sectors per track.(default:%u)\n", OPTION_SECTOR_DEFAULT   );
474     fprintf( stderr, "  -h        print help.\n"                                                                   );
475     
476     /* 終了 */
477     exit( status );
478 }
479
480
481 /******************************************************************************/
482 /**
483  * @brief       IPLバイナリ書込み
484  * @details     IPLバイナリを仮想ディスクに書き込む。
485  * 
486  * @param[in]   diskFd    仮想ディスクファイルディスクリプタ
487  * @param[in]   *pIplPath IPLバイナリのファイルパス
488  */
489 /******************************************************************************/
490 static void writeIpl( int  diskFd,
491                       char *pIplPath )
492 {
493     int     iplFd;  /* IPLバイナリファイルディスクリプタ */
494     mbr_t   mbr;    /* マスタブートレコード              */
495     int32_t size;   /* サイズ                            */
496     
497     /* IPLバイナリファイルオープン */
498     iplFd = open( pIplPath, O_RDONLY );
499     
500     /* オープン結果判定 */
501     if ( iplFd == -1 ) {
502         /* 失敗 */
503         
504         /* アボート */
505         ABORT( "ERROR(%04u): Can't open %s. errno=%d.\n",
506                __LINE__,
507                pIplPath,
508                errno );
509     }
510     
511     /* IPLバイナリ読込み */
512     size = ( int32_t ) read( iplFd, &mbr, sizeof ( mbr_t ) );
513     
514     /* 読込み結果判定 */
515     if ( size != ( sizeof ( mbr_t ) ) ) {
516         /* 読込み失敗 */
517         
518         /* アボート */
519         ABORT( "ERROR(%04u): Can't read from %s. ret=%d, errno=%d.\n",
520                __LINE__,
521                pIplPath,
522                size,
523                errno );
524     }
525     
526     /* IPLバイナリを仮想ディスクに書込み */
527     size = ( int32_t ) write( diskFd, &mbr, sizeof ( mbr_t ) );
528     
529     /* 書込み結果判定 */
530     if ( size != ( sizeof ( mbr_t ) ) ) {
531         /* 書込み */
532         
533         /* アボート */
534         ABORT( "ERROR(%04u): Can't write %s. ret=%d, errno=%d.\n",
535                __LINE__,
536                pIplPath,
537                size,
538                errno );
539     }
540     
541     /* ファイルクローズ */
542     close( iplFd );
543     
544     return;
545 }
546
547
548 /******************************************************************************/
549 /**
550  * @brief       ブートローダバイナリ書込み
551  * @details     ブートローダバイナリを仮想ディスクのパーティション1番に書込む。
552  * 
553  * @param[in]   diskFd       仮想ディスクファイルディスクリプタ
554  * @param[in]   *pBootPath   ブートローダバイナリのファイルパス
555  * @param[in]   chsFirstAddr 書込み先先頭CHSアドレス
556  * 
557  * @return      書込み先最後尾CHSアドレス
558  */
559 /******************************************************************************/
560 static chs_t writeBoot( int   diskFd,
561                         char  *pBootPath,
562                         chs_t chsFirstAddr )
563 {
564     int      bootFd;                /* ブートローダファイルディスクリプタ */
565     pt_t     pe;                    /* パーティションエントリ             */
566     char     buffer[ BUFFER_SIZE ]; /* 読込みバッファ                     */
567     off_t    offset;                /* ファイルオフセット                 */
568     int32_t  readSize;              /* 読込サイズ                         */
569     int32_t  writeSize;             /* 書込みサイズ                       */
570     uint32_t fileSize;              /* ファイルサイズ                     */
571     uint32_t lbaSize;               /* ファイルサイズ(セクタ数)         */
572     uint32_t lbaFirstAddr;          /* 書込み先先頭LBAアドレス            */
573     
574     /* 初期化 */
575     fileSize = 0;
576     lbaSize  = 0;
577     lbaFirstAddr = GET_CYLINDER( chsFirstAddr.cylSec ) * head * sector +
578                    chsFirstAddr.head * sector + 
579                    GET_SECTOR( chsFirstAddr.cylSec ) - 1;
580     memset( &pe, 0, sizeof ( pt_t ) );
581     
582     /* 仮想ディスクシーク */
583     offset = lseek( diskFd, lbaFirstAddr * 512, SEEK_SET );
584     
585     /* シーク結果判定 */
586     if ( ( int32_t ) offset != ( lbaFirstAddr * 512 ) ) {
587         /* 失敗 */
588         
589         /* アボート */
590         ABORT( "ERROR(%04u): Can't seek at the disk image. ret=%d, errno=%d.\n",
591                __LINE__,
592                ( int32_t ) offset,
593                errno );
594     }
595     
596     /* ブートローダバイナリファイルオープン */
597     bootFd = open( pBootPath, O_RDONLY );
598     
599     /* オープン結果判定 */
600     if ( bootFd == -1 ) {
601         /* 失敗 */
602         
603         /* アボート */
604         ABORT( "ERROR(%04u): Can't open %s. errno=%d.\n",
605                __LINE__,
606                pBootPath,
607                errno );
608     }
609     
610     /* 読み書きバッファサイズ毎に繰り返し */
611     do {
612         /* バッファ初期化 */
613         memset( buffer, 0, BUFFER_SIZE );
614         
615         /* ブートローダバイナリ読込み */
616         readSize = read( bootFd, buffer, BUFFER_SIZE );
617         
618         /* 読込み結果判定 */
619         if ( readSize == -1 ) {
620             /* 失敗 */
621             
622             /* アボート */
623             ABORT( "ERROR(%04u): Can't read from %s. errno=%d.\n",
624                    __LINE__,
625                    pBootPath,
626                    errno );
627             
628         } else if ( readSize == 0 ) {
629             /* EOF */
630             
631             break;
632         }
633         
634         /* 書込み */
635         writeSize = write( diskFd, buffer, readSize );
636         
637         /* 書込み結果判定 */
638         if ( writeSize != readSize ) {
639             /* 失敗 */
640             
641             /* アボート */
642             ABORT( "ERROR(%04u): Can't write %s. errno=%d.\n",
643                    __LINE__,
644                    pBootPath,
645                    errno );
646         }
647         
648         /* ファイルサイズ更新 */
649         fileSize += writeSize;
650         lbaSize++;
651     } while ( writeSize == BUFFER_SIZE );
652     
653     /* パーティションテーブル設定 */
654     pe.status       = PT_STATUS_BOOT;
655     pe.chsFirstAddr = chsFirstAddr;
656     pe.type         = PT_TYPE_MOCHI_BOOTER;
657     pe.chsLastAddr  = getChs( lbaFirstAddr + lbaSize - 1 );
658     pe.lbaFirstAddr = lbaFirstAddr;
659     pe.lbaSize      = lbaSize;
660     writePartitionEntry( diskFd, 1, &pe );
661     
662     /* ファイルクローズ */
663     close( bootFd );
664     
665     return pe.chsLastAddr;
666 }
667
668
669 /******************************************************************************/
670 /**
671  * @brief       カーネルバイナリ書込み
672  * @details     カーネルバイナリを仮想ディスクのパーティション2番に書込む。
673  * 
674  * @param[in]   diskFd       仮想ディスクファイルディスクリプタ
675  * @param[in]   *pKernelPath カーネルバイナリのファイルパス
676  * @param[in]   chsFirstAddr 書込み先先頭CHSアドレス
677  * 
678  * @return      書込み先最後尾CHSアドレス
679  */
680 /******************************************************************************/
681 static chs_t writeKernel( int   diskFd,
682                           char  *pKernelPath,
683                           chs_t chsFirstAddr  )
684 {
685     int      kernelFd;              /* カーネルファイルディスクリプタ */
686     pt_t     pe;                    /* パーティションエントリ         */
687     char     buffer[ BUFFER_SIZE ]; /* 読込みバッファ                 */
688     off_t    offset;                /* ファイルオフセット             */
689     int32_t  readSize;              /* 読込サイズ                     */
690     int32_t  writeSize;             /* 書込みサイズ                   */
691     uint32_t fileSize;              /* ファイルサイズ                 */
692     uint32_t lbaSize;               /* ファイルサイズ(セクタ数)     */
693     uint32_t lbaFirstAddr;          /* 書込み先先頭LBAアドレス        */
694     
695     /* 初期化 */
696     fileSize     = 0;
697     lbaSize      = 0;
698     lbaFirstAddr = GET_CYLINDER( chsFirstAddr.cylSec ) * head * sector +
699                    chsFirstAddr.head * sector + 
700                    GET_SECTOR( chsFirstAddr.cylSec ) - 1;
701     memset( &pe, 0, sizeof ( pt_t ) );
702     
703     /* 仮想ディスクシーク */
704     offset = lseek( diskFd, lbaFirstAddr * 512, SEEK_SET );
705     
706     /* シーク結果判定 */
707     if ( ( int32_t ) offset != ( lbaFirstAddr * 512 ) ) {
708         /* 失敗 */
709         
710         /* アボート */
711         ABORT( "ERROR(%04u): Can't seek at the disk image. ret=%d, errno=%d.\n",
712                __LINE__,
713                ( int32_t ) offset,
714                errno );
715     }
716     
717     /* カーネルバイナリファイルオープン */
718     kernelFd = open( pKernelPath, O_RDONLY );
719     
720     /* オープン結果判定 */
721     if ( kernelFd == -1 ) {
722         /* 失敗 */
723         
724         /* アボート */
725         ABORT( "ERROR(%04u): Can't open %s. errno=%d.\n",
726                __LINE__,
727                pKernelPath,
728                errno );
729     }
730     
731     /* 読み書きバッファサイズ毎に繰り返し */
732     do {
733         /* バッファ初期化 */
734         memset( buffer, 0, BUFFER_SIZE );
735         
736         /* ブートローダバイナリ読込み */
737         readSize = read( kernelFd, buffer, BUFFER_SIZE );
738         
739         /* 読込み結果判定 */
740         if ( readSize == -1 ) {
741             /* 失敗 */
742             
743             /* アボート */
744             ABORT( "ERROR(%04u): Can't read from %s. errno=%d.\n",
745                    __LINE__,
746                    pKernelPath,
747                    errno );
748             
749         } else if ( readSize == 0 ) {
750             /* EOF */
751             
752             break;
753         }
754         
755         /* 書込み */
756         writeSize = write( diskFd, buffer, readSize );
757         
758         /* 書込み結果判定 */
759         if ( writeSize != readSize ) {
760             /* 失敗 */
761             
762             /* アボート */
763             ABORT( "ERROR(%04u): Can't write %s. errno=%d.\n",
764                    __LINE__,
765                    pKernelPath,
766                    errno );
767         }
768         
769         /* ファイルサイズ更新 */
770         fileSize += writeSize;
771         lbaSize++;
772     } while ( writeSize == BUFFER_SIZE );
773     
774     /* パーティションテーブル設定 */
775     pe.status       = 0;
776     pe.chsFirstAddr = chsFirstAddr;
777     pe.type         = PT_TYPE_MOCHI_KERNEL;
778     pe.chsLastAddr  = getChs( lbaFirstAddr + lbaSize - 1 );
779     pe.lbaFirstAddr = lbaFirstAddr;
780     pe.lbaSize      = lbaSize;
781     writePartitionEntry( diskFd, 2, &pe );
782     
783     /* ファイルクローズ */
784     close( kernelFd );
785     
786     return pe.chsLastAddr;
787 }
788
789
790 /******************************************************************************/
791 /**
792  * @brief       パーティションエントリ書込み
793  * @details     パーティションテーブルのエントリを仮想ディスクに書き込む。
794  * 
795  * @param[in]   diskFd 仮想ディスクファイルディスクリプタ
796  * @param[in]   no     パーティション番号
797  * @param[in]   *pPe   パーティションエントリ
798  */
799 /******************************************************************************/
800 static void writePartitionEntry( int      diskFd,
801                                  uint32_t no,
802                                  pt_t     *pPe    )
803 {
804     int     iplFd;  /* IPLバイナリファイルディスクリプタ */
805     mbr_t   mbr;    /* マスタブートレコード              */
806     off_t   offset; /* ファイルオフセット                */
807     int32_t size;   /* サイズ                            */
808     
809     /* 仮想ディスクシーク */
810     offset = lseek( diskFd, 0, SEEK_SET );
811     
812     /* シーク結果判定 */
813     if ( ( int32_t ) offset != 0 ) {
814         /* 失敗 */
815         
816         /* アボート */
817         ABORT( "ERROR(%04u): Can't seek at the disk image. ret=%d, errno=%d.\n",
818                __LINE__,
819                ( int32_t ) offset,
820                errno );
821     }
822     
823     /* MBR読込み */
824     size = ( int32_t ) read( diskFd, &mbr, sizeof ( mbr_t ) );
825     
826     /* 読込み結果判定 */
827     if ( size != ( sizeof ( mbr_t ) ) ) {
828         /* 読込み失敗 */
829         
830         /* アボート */
831         ABORT( "ERROR(%04u): Can't read from MBR. ret=%d, errno=%d.\n",
832                __LINE__,
833                size,
834                errno );
835     }
836     
837     /* パーティションエントリ設定 */
838     mbr.partitionTbl[ no - 1 ] = *pPe;
839     
840     /* 仮想ディスクシーク */
841     offset = lseek( diskFd, 0, SEEK_SET );
842     
843     /* シーク結果判定 */
844     if ( ( int32_t ) offset != 0 ) {
845         /* 失敗 */
846         
847         /* アボート */
848         ABORT( "ERROR(%04u): Can't seek at the disk image. ret=%d, errno=%d.\n",
849                __LINE__,
850                ( int32_t ) offset,
851                errno );
852     }
853     
854     /* MBR書込み */
855     size = ( int32_t ) write( diskFd, &mbr, sizeof ( mbr_t ) );
856     
857     /* 書込み結果判定 */
858     if ( size != ( sizeof ( mbr_t ) ) ) {
859         /* 書込み */
860         
861         /* アボート */
862         ABORT( "ERROR(%04u): Can't write MBR. ret=%d, errno=%d.\n",
863                __LINE__,
864                size,
865                errno );
866     }
867     
868     return;
869 }
870
871
872 /******************************************************************************/