手機寫作業系統之 製作第1個啟動盤

南门桥外發表於2024-04-25

2.手機寫作業系統之
製作第1個啟動盤
建立目錄

一般手機上沒有檔案工具,需要下載一個檔案管理。
在手機裡使用檔案管理建立目錄
A/ya/
再建立子目錄
code
out
final
termux對手機目錄的訪問加上/sdcard,比如:
cd /sdcard/A/ya

啟動程式boot

看看有名的boot程式
電腦開始啟動後,首先在磁碟0號磁軌0號扇區處尋找boot程式,這個程式只有512位元組大小,如果是以0x55,0xAA兩個位元組結尾,電腦將認為這是一個boot程式,然後電腦將這個程式讀入記憶體地址0x7c00:0000處開始執行。
一個最簡單的boot.asm
使用文字編輯器:
[BITS 16]
[ORG 0x7c00]

jmp main
ns db 'hello world!'
main:
mov ax, cs
mov ds, ax
mov es, ax
mov cx,12 ;迴圈12次
mov bx,0 ;從陣列[0]開始
mov ah,0eh
next:
mov al,[ns+bx]
int 10h
inc bx
dec cx
jnz next ;cx不為0則繼續
po:
jmp po
times 510-($-$$) db 0
db 0x55
db 0xAA

將它儲存到手機裡的A/ya/code目錄下
我們分析一下這個程式
$表示本指令地址 $$表示程式開始地址
times 510-($-$$) db 0 就是填入510-(本指令地址-程式開始地址)這麼多個0
我們給它中間加點語句,讓它在螢幕上顯示Hello World

這裡我們生成可執行檔案格式
開啟termux,輸入命令
cd /sdcard/A/ya
nasm code/boot.asm -o out/boot.bin

把boot.bin寫入啟動盤,用Hex editor將512 b大小的boot.bin複製到A盤映象檔案中,這樣做麻煩。為此使用兩個軟體工具:
create_img.cpp 建立啟動盤
write_in_img.cpp 向啟動盤寫入資料

create_img.cpp

include

include <stdio.h>

include

include<stdlib.h>

//argv[1]=目標檔案 創立映象檔案, 內容全為0,大小1474560
using namespace std;

int main (int argc,char* argv[])
{
int i;
for (i = 1; i <= argc; i++)
{
printf("argv[%d]=%s\n",i,argv[i]);
}
FILE *tof;
tof = fopen( argv[1],"r"); //只讀方式開啟一個binary目標檔案
if( tof ==NULL) // 第一次需建立目標檔案
{
printf("\nerror on open file,will creat new file\n");
tof = fopen (argv[1],"wb");
fseek(tof, 1474559, SEEK_SET); //相當於寫入那麼多0
putc(0, tof); // 寫第1474560位元組,1.44M軟盤大小
}
printf("done\n");
fclose(tof); //關檔案禁止讀寫才能對檔案刪除及改名
return 0;
}

write_in_img.cpp

include

include <stdio.h>

include

include <stdlib.h>

//argv[1]=目標檔案 argv[2]=原始檔 argv[3]=寫入偏移量十進位制 用法: ./write_in_img.o a.img setup.bin 0

using namespace std;

long get_file_size( FILE *fp )
{
if ( fp == NULL) return -1;
fseek(fp, 0L, SEEK_END );
return ftell( fp );
}

int main (int argc,char* argv[])
{
int i;
int ch;
int k = atoi(argv[3]); // 轉換得到寫入偏移量
FILE *fromf, *tof, *temp;
fromf = fopen( argv[2], "r" ); //只讀方式開啟原始檔
tof = fopen( argv[1],"r"); //只讀方式開啟目標檔案
if( tof ==NULL) // 第一次需建立目標檔案
{
printf("\nerror on open file,use create_img.o to creat img file\n");
exit( 0 );
}
temp = fopen("t.img", "w+" ); //建立一個用於讀寫的空檔案,中間檔案,大小為0
fseek(tof, 0L, SEEK_SET ); //從新定位到檔案開頭
for (int i =0; i < k; i++) // 保留目標檔案第一部分
{
ch = getc( tof );
putc(ch, temp);
}
long ja = get_file_size( fromf );
fseek(fromf, 0L, SEEK_SET ); //定位到原始檔開頭
for (int i =0; i < ja; i++) // 複製檔案第二部分
{
ch = getc( fromf );
putc(ch, temp);
}
fseek ( tof, ja+k, SEEK_SET ); //指標指向從檔案頭開始ja+K個位元組
ch = getc( tof );
i = 0;
while ( ch != EOF ) // 複製最後的第三部分
{
putc(ch, temp); // 寫入檔案
ch = getc( tof );
i++;
}
fclose(tof); //關檔案禁止讀寫才能對檔案刪除及改名
fclose(fromf);
fclose(temp);
remove(argv[1]);
rename("t.img",argv[1]);
return 0;
}

下面我們將在虛擬機器上模擬boot檔案從軟盤上啟動的效果。

準備工作:
修改g.sh檔案:

!/bin/sh

echo "=啟動 ya=="
cd /sdcard/A/ya/
make
cd ~
cp -f /sdcard/A/ya/out ./
cd out
chmod 755 ./*

執行命令,當前目錄下生成a.img檔案

./create_img.o a.img

執行命令,向a.img寫入程式碼,內容是boot.bin

寫入磁碟位置從0偏移量起始,佔1個扇區512位元組

./write_in_img.o a.img boot.bin 0

結果複製到手機

cp -f ./a.img /sdcard/A/ya/final
cd ~
rm -r out

將g.sh存於手機目錄A/ya

修改makefile檔案:
######################

宣告要編譯的所有組成,這裡的ya是本工程名稱,可以取任何名字,這裡就用ya

######################
ya:out/boot.bin out/create_img.o out/write_in_img.o

開始對各部分編譯

out/boot.bin:code/boot.asm
nasm code/boot.asm -o out/boot.bin

製作核心映象工具

out/create_img.o:code/create_img.cpp
clang++ code/create_img.cpp -o out/create_img.o

寫入檔案,argv[1]=目標檔案 argv[2]=原始檔 argv[3]=寫入偏移量

out/write_in_img.o:code/write_in_img.cpp
clang++ code/write_in_img.cpp -o out/write_in_img.o

######################
存為makefile,放在手機A/ya目錄下

以上工作準備好了,開始使用sh + makefile製作啟動盤
方法:
開啟termux
cp -f /sdcard/A/ya/g.sh ./
執行
sh g.sh

檢視手機目錄A/ya/final,有a.img,用磁碟編輯工具檢視a.img內容,為1474560位元組,而且已經把boot.bin內容複製到a.img。
開啟Limbo,開始設定,Machine 下拉選單選new 填寫名稱ya點create 在彈出的選單點選最下的Custom User Interface,Display 選VNC。Removable 勾選Floppy A --> open --> 手機目錄下的A/ya/final/a.img
點選三角形Run --> 開啟 RVNC,填寫127.0.0.1:1 及名稱,點OK,顯示:
Booting from Floppy...
Hello world!

相關文章