ubuntu下安裝bochslinux
安裝gcc編譯環境ios
sudo apt-get install build-essentialgit
sudo apt-get install xorg-dev
sudo apt-get install fort77
sudo apt-get install libgtk2.0-dev
sudo apt-get install libwxgtk3.0-devgithub
下載bochs最新版本
http://bochs.sourceforge.net/ubuntu
wget https://nchc.dl.sourceforge.net/project/bochs/bochs/2.6.9/bochs-2.6.9.tar.gzapp
安裝命令
清理:
sudo rm -rf /opt/local/bin/*
sudo rm -rf /opt/local/share/bochsoop
$tar vxzf bochs-2.6.9.tar.gz
$cd bochs-2.6.9
$./configure --enable-debugger --enable-disasm
$ ./configure --with-x11 --with-wx --enable-debugger --enable-disasm --enable-all-optimizations --enable-readline --enable-long-phy-address --enable-debugger-gui --prefix=/opt/localui
修改Makefile(新版不須要)
LIBS =
-lz -lrt -lm -lpthread 操作系統
$make
$cp bochs bochsdbg
$sudo make install.net
安裝nasm
sudo apt-get install nasm
編譯boot.asm
nasm boot.asm -o boot.bin
此處的boot.asm是一段彙編代碼,在屏幕上打印出hello, OS world!
代碼以下:
org 07c00h ; 告訴編譯器程序加載到7c00處 mov ax, cs mov ds, ax mov es, ax call DispStr ; 調用顯示字符串例程 jmp $ ; 無限循環 DispStr: mov ax, BootMessage mov bp, ax ; ES:BP = 串地址 mov cx, 16 ; CX = 串長度 mov ax, 01301h ; AH = 13, AL = 01h mov bx, 000ch ; 頁號爲0(BH = 0) 黑底紅字(BL = 0Ch,高亮) mov dl, 0 int 10h ; 10h 號中斷 ret BootMessage: db "Hello, OS world!" times 510-($-$$) db 0 ; 填充剩下的空間,使生成的二進制代碼剛好爲512字節 dw 0xaa55 ; 結束標誌
用bximage命令來建立img文件
$ bximage ======================================================================== bximage Disk Image Creation / Conversion / Resize and Commit Tool for Bochs $Id: bximage.cc 13069 2017-02-12 16:51:52Z vruppert $ ======================================================================== 1. Create new floppy or hard disk image 2. Convert hard disk image to other format (mode) 3. Resize hard disk image 4. Commit 'undoable' redolog to base image 5. Disk image info 0. Quit Please choose one [0] 1 Create image Do you want to create a floppy disk image or a hard disk image? Please type hd or fd. [hd] fd Choose the size of floppy disk image to create. Please type 160k, 180k, 320k, 360k, 720k, 1.2M, 1.44M, 1.68M, 1.72M, or 2.88M. [1.44M] What should be the name of the image? [a.img] Creating floppy image 'a.img' with 2880 sectors The following line should appear in your bochsrc: floppya: image="a.img", status=inserted
使用dd命令將它寫進剛剛建立的軟盤映像a.img的第一個扇區
dd if=boot.bin of=a.img bs=512 count=1 conv=notrunc
此時還須要配置bochs的配置文件bochsrc,標準的配置文件格式爲
############################################################### # Configuration file for Bochs ############################################################### # how much memory the emulated machine will have megs: 32 # filename of ROM images romimage: file=/opt/local/share/bochs/BIOS-bochs-latest #/opt/share/bochs/BIOS-bochs-latest vgaromimage: file=/opt/local/share/bochs/VGABIOS-lgpl-latest #/usr/share/vgabios/vgabios.bin # what disk images will be used floppya: 1_44=a.img, status=inserted # choose the boot disk. boot: floppy # where do we send log messages? # log: bochsout.txt # disable the mouse mouse: enabled=0 # enable key mapping, using US layout as default. # keyboard_mapping: enabled=1, map=/opt/local/share/bochs/keymaps/x11-pc-us.map keyboard: keymap=/opt/local/share/bochs/keymaps/x11-pc-us.map
接着即可以執行
bochs -f bochsrc
來運行bochsrc虛擬機。
nasm彙編直接生成可啓動的軟盤鏡像(根據30天自制操做系統)
; hello-os ; TAB=4 DB 0xeb, 0x4e, 0x90 DB "HELLOIPL" ; DW 512 ; DB 1 ; DW 1 ; DB 2 ; DW 224 ; DW 2880 ; DB 0xf0 ; DW 9 ; DW 18 ; DW 2 ; DD 0 ; DD 2880 ; DB 0,0,0x29 ; DD 0xffffffff ; DB "HELLO-OS " ; DB "FAT12 " ; times 18 db 0 ; ; DB 0xb8, 0x00, 0x00, 0x8e, 0xd0, 0xbc, 0x00, 0x7c DB 0x8e, 0xd8, 0x8e, 0xc0, 0xbe, 0x74, 0x7c, 0x8a DB 0x04, 0x83, 0xc6, 0x01, 0x3c, 0x00, 0x74, 0x09 DB 0xb4, 0x0e, 0xbb, 0x0f, 0x00, 0xcd, 0x10, 0xeb DB 0xee, 0xf4, 0xeb, 0xfd ; DB 0x0a, 0x0a ; DB "hello, world" DB 0x0a ; DB 0 times 510-($-$$) db 0 DB 0x55, 0xaa ; DB 0xf0, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00 times 4600 db 0 ; DB 0xf0, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00 times 1469432 db 0 ;
nasm -o helloos.img helloos.asm
生成的img大小和1.4M軟盤一致。能夠直接啓動
; hello-os ; TAB=4 ORG 0x7c00 ; ; JMP SHORT entry DB 0x90 DB "HELLOIPL" ; DW 512 ; DB 1 ; DW 1 ; DB 2 ; DW 224 ; DW 2880 ; DB 0xf0 ; DW 9 ; DW 18 ; DW 2 ; DD 0 ; DD 2880 ; DB 0,0,0x29 ; DD 0xffffffff ; DB "HELLO-OS " ; DB "FAT12 " ; ; entry: MOV AX,0 ; MOV SS,AX MOV SP,0x7c00 MOV DS,AX MOV ES,AX MOV SI,msg putloop: MOV AL,[SI] ADD SI,1 ; CMP AL,0 JE fin MOV AH,0x0e ; MOV BX,15 ; INT 0x10 ; JMP putloop fin: HLT ; JMP fin ; msg: DB 0x0a, 0x0a ; DB "hello,myworld" DB 0x0a ; DB 0 times 510-($-$$) db 0 DB 0x55, 0xaa ; DB 0xf0, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00 times 4600 db 0 ; DB 0xf0, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00 times 1469432 db 0 ;
===========================================================
運行linux0.00
克隆項目到本地硬盤
git clone https://github.com/voidccc/linux0.00.git
cd linux0.00
生成軟盤映像a.img(bximage)
修改Makefile以下
# Makefile for linux 0.00 all: disk disk: boot head dd bs=32 if=boot of=a.img skip=1 dd bs=512 if=head of=a.img skip=8 seek=1 boot: boot.s as86 -0 -a -o boot.o boot.s ld86 -0 -s -o boot boot.o head: head.s as --32 -o head.o head.s ld -m elf_i386 -Ttext 0 -e startup_32 -o head head.o clean: rm -f core boot *.o head
主要改變:as改了as --32,不然在64位系統中不能彙編,另外在原項目中直接寫到映像文件Image,的到的文件大小6k多雖然也能在bochs中啓動,但不是標準的軟盤映像,這裏用a.img代替
修改.bochsrc(根據bochs安裝位置)
############################################################### # Configuration file for Bochs ############################################################### # how much memory the emulated machine will have megs: 32 # filename of ROM images romimage: file=/opt/local/share/bochs/BIOS-bochs-latest #/opt/share/bochs/BIOS-bochs-latest vgaromimage: file=/opt/local/share/bochs/VGABIOS-lgpl-latest #/usr/share/vgabios/vgabios.bin # what disk images will be used floppya: 1_44=a.img, status=inserted #ata0-master: type=disk, path="hdc.img", mode=flat, cylinders=410, heads=16, spt=38 # choose the boot disk. boot: a # where do we send log messages? # log: bochsout.txt # disable the mouse mouse: enabled=0 # enable key mapping, using US layout as default. # keyboard_mapping: enabled=1, map=/opt/local/share/bochs/keymaps/x11-pc-us.map keyboard: keymap=/opt/local/share/bochs/keymaps/x11-pc-us.map
$ cat boot.s
! voidccc created 20120913 ! 本文件編譯方法 ! as86 -0 -a -o boot.o boot.s ! ld86 -0 -s -o boot boot.o ! 說明 ! 這是512K的引導扇區,作了以下的工做: ! 1 使用BIOS的0x13中斷,讀取真正內核到內存 ! 2 將內核移動到內存開始位置 ! 3 設置保護模式下的初始GDT/IDT ! 4 切換到保護模式 ! 5 跳轉到內核開始位置執行 !mov cx,#0x2000 here need modify BOOTSEG = 0x07c0 SYSSEG = 0x1000 !內核先被加載到的位置 SYSLEN = 17 !內核佔用的磁盤扇區數,在使用int 13讀取內核時用到 entry start !入口點 start: jmpi go,#BOOTSEG !段間跳轉到 !BIOS已經將本程序加載到0x07c0的位置,目前是在實模式下,啓動時段寄存器的缺省值是00,因此這句實際仍是跳轉到go,0的位置,同時段間跳轉會修改CS和IP的值,這句執行完後,CS被設置爲0x07c0,IP被設置爲go go: mov ax,cs !讓DS和SS都指向0x07c0段,由於段寄存器只能接受寄存器的 mov ds,ax mov ss,ax mov sp,#0x400 !使用BIOS中斷調用加載內核代碼到0x10000處,BIOS的0x13中斷具體使用方式此處不作深究。 !只要知道實模式下初始的中斷向量表是在跳轉到0x07c0以前,已經由BIOS設置好就行。 load_system: mov dx,#0x0000 mov cx,#0x0002 mov ax,#SYSSEG mov es,ax xor bx,bx ! 清空bx,ES:BX(0x10000:0x0000)是讀入緩衝區位置 mov ax,#0x200+SYSLEN int 0x13 jnc ok_load !若沒有發生錯誤則跳轉繼續運行,不然死循環 die: jmp die ok_load: cli !關閉中斷,之因此要關閉中斷,是由於此時已經將內核加載完畢,而加載內核是須要使用BIOS提供的0x13中斷的,因此在加載完內核前不能關閉中斷。然後續要轉入保護模式而且使用多任務,在內核徹底準備好後續操做前,要將中斷關閉。不然中斷會破壞內核的初始化。後續再開啓多任務時,會再次開啓中斷。 mov ax,#SYSSEG !爲rep指令作準備,把要內核要開始移動的位置,放入DS:SI,目的地位置放入ES:DI,移動次數放入cx,cx是移動次數4096(0x1000轉換爲10進制)次 mov ds,ax xor ax,ax mov es,ax mov cx,#0x2000 sub si,si sub di,di rep movw !每次移動一個字 !加載IDT和GDT基地址寄存器IDTR和GDTR !由於剛使用了ds,如今要先回復ds mov ax,#BOOTSEG mov ds,ax lidt idt_48 !加載idt,給保護模式用的,48位 lgdt gdt_48 !加載gdt,給保護模式用的,48位 !設置CR0中的PE位,進入保護模式 mov ax,#0x0001 lmsw ax !將ax放入CR0 !雖然執行LMSW指令之後切換到了保護模式,但該指令規定其後必須緊隨一條段間跳轉指令以 !刷新CPU的指令緩衝隊列。所以在LMSW指令後,CPU仍是繼續執行下一條指令 !此處0,8已是保護模式的地址,8是選擇符,0是偏移地址 !跳轉到段選擇符是8,偏移0的地址處,段選擇符8轉化爲16位2進製爲 !0000000000001 0 00 !|--描述符索引--|--GDT/LDT--|--特權級--| !其中0爲GDT 1爲LDT !其中00爲特權級0 11爲特權級3 !其中描述符索引1是CS段選擇符,可詳見下面gdt的定義 !jmpi 有反作用,會設置CS的值 jmpi 0,8 !下面是GDT的內容,3個段描述符, !第一個不用,第2個是代碼段,第三個是數據段 gdt: !段描述符0,不用 .word 0,0,0,0 !段描述符1, !0x07FF十進制是2047,段限長, !0x0000 段基地址, !0x9A00 代碼段,可讀可執行 !0x00c0 段屬性顆粒度4k .word 0x07FF,0x0000,0x9A00,0x00c0 !段描述符2, !0x07FF十進制是2047,段限長, !0x0000 段基地址, !0x9200 數據段,可讀可寫 !0x00c0 段屬性顆粒度4k .word 0x07FF,0x0000,0x9200,0x00c0 !?? !下面的數據用於存放到IDTR和GDTR裏 !IDTR |---32位表基地址---|--16位表長度--| !GDTR |---32位表基地址---|--16位表長度--| !word. 16位長度,32位基地址 idt_48: .word 0,0,0 gdt_48: .word 0x7ff,0x7c00+gdt,0 !引導扇區的標誌 .org 510 .word 0xAA55
$ cat head.s
# head.s contains the 32-bit startup code. # Two L3 task multitasking. The code of tasks are in kernel area, # just like the Linux. The kernel code is located at 0x10000. # # voidccc 20120921 # 編譯方法 # as --32 -o head.o head.s # 這是一個運行在保護模式下的AT&T彙編寫的多任務內核 # 代碼包括 # 1 初始化設置代碼 # 2 時鐘中斷代碼 # 3 系統調用中斷代碼 # 4 任務a和任務b的代碼 # 在初始化完成以後程序移動到任務0開始執行,並在時鐘中斷控制下進行任務0和任務1之間的切換 # 書上代碼須要修改的地方 # movl scr_loc, %bx => movlscr_loc, %ebx # movl $65, %al => movb $65, %al # movl $66, %al => movb $66, %al # align 2 => align 4 # align 3 => align 8 SCRN_SEL = 0x18 TSS0_SEL = 0x20 LDT0_SEL = 0x28 TSS1_SEL = 0x30 LDT1_SEL = 0x38 #定時器初始值,即每隔10毫秒發送一次中斷請求。因爲8254芯片的時鐘輸入頻率爲1193180 Hz,因此芯片每隔1193190/100次計數,就會發出一個時鐘中斷請求信號,也就是每隔10毫秒左右(1秒的1/100) LATCH = 11930 .text # startup_32是特殊的標號,表示保護程序的開始位置 startup_32: #首先加載DS SS ESP,全部段的線性基地址都是0, #做爲三個段之一的CS此處不用從新設置,徹底是由於本次執行是從boot用長跳轉jmpi指令過來的,這個指令有反作用,會設置CS寄存器的值爲長跳轉的段寄存器 movl $0x10, %eax mov %ax, %ds lss init_stack, %esp #從新設置IDT和GDT表 call setup_idt #設置IDT,先把256箇中斷門都填默認處理過程的描述符 call setup_gdt #設置GDT movl $0x10, %eax #在改變了GDT以後從新加載全部段寄存器 mov %ax,%ds mov %ax,%es mov %ax,%fs mov %ax,%gs lss init_stack, %esp #設置8253定時芯片。把計數器通道0設置成每隔10毫秒想中斷控制器發送一箇中斷請求信號 movb $0x36, %al #控制字:設置通道0工做方式在3,計數初值採用二進制。 movl $0x43, %edx #8253芯片控制字寄存器寫端口 outb %al, %dx movl $LATCH, %eax #初始計數值設置爲LATCH, 100HZ movl $0x40, %edx #通道0的端口 outb %al, %dx #分兩次把初始計數值寫入通道0 movb %ah, %al outb %al, %dx #在IDT表第8和第128(0x80)項處分別設置定製中斷門描述符和系統調用陷阱門描述符 movl $0x00080000, %eax #中斷程序屬內核,即eax高字是內核代碼段選擇符0x0008 movw $timer_interrupt, %ax#設置定時中斷門描述符取定時中斷處理程序地址 movw $0x8E00, %dx #中斷門類型是14(屏蔽中斷) movl $0x08, %ecx #開機時BIOS設置的時鐘中斷向量號8,這裏直接使用 lea idt(,%ecx,8),%esi #把IDT描述符0x80地址放入ESI movl %eax, (%esi) movl %edx,4(%esi) movw $system_interrupt, %ax movw $0xef00, %dx movl $0x80, %ecx lea idt(,%ecx,8),%esi movl %eax,(%esi) movl %edx,4(%esi) #爲人工移動到任務0準備堆棧 pushfl #復位標誌寄存器 andl $0xffffbfff, (%esp) popfl movl $TSS0_SEL, %eax #把任務0的TSS段選擇符加載到任務寄存器TR ltr %ax movl $LDT0_SEL, %eax #把任務0的LDT段選擇符加載到局部描述符表寄存器LDTR lldt %ax #TR和DTR只須要人工加載一次,之後CPU會自動處理 movl $0, current #把當前任務號0保存在current變量中 sti #如今開啓中斷,並在棧中營造中斷返回時的場景 pushl $0x17 #把任務0當前局部控件數據段(堆棧段)選擇符入棧 pushl $init_stack #把堆棧指針入棧 pushfl #把標誌寄存器值入棧 pushl $0x0f #把當前局部控件代碼段選擇符入棧 pushl $task0 #把代碼指針入棧 iret #執行中斷返回指令,從而切換到特權級3的任務0中執行 #如下是設置GDT和IDT中描述符的子程序 setup_gdt: lgdt lgdt_opcode #使用6字節操做數lgdt_opcode設置GDT表位置和長度 ret #這段代碼暫時設置IDT表中全部256箇中斷門描述符都爲同一個默認值,均使用默認的中斷處理過程ignore_int,設置的具體方法是:首先在eax和edx寄存器對中分別設置好默認中斷門描述符的0-3字節和4-7字節的內容,而後利用寄存器對循環往IDT表中填充默認中斷門描述符內容。 setup_idt: lea ignore_int, %edx movl $0x00080000, %eax #選擇符爲0x0008 movw %dx, %ax movw $0x8E00, %dx #中斷門類型,特權級爲0 lea idt, %edi mov $256, %ecx #循環設置全部256個門描述符 rp_idt: movl %eax, (%edi) movl %edx, 4(%edi) addl $8, %edi dec %ecx jne rp_idt lidt lidt_opcode #最後用6字節操做數加載IDTR寄存器 ret #顯示字符子程序 write_char: push %gs pushl %ebx mov $SCRN_SEL, %ebx mov %bx, %gs movl scr_loc, %ebx shl $1, %ebx movb %al, %gs:(%ebx) shr $1, %ebx incl %ebx cmpl $2000, %ebx jb 1f # ?? movl $0, %ebx 1: movl %ebx, scr_loc popl %ebx pop %gs ret # 如下是3箇中斷處理程序:默認中斷,定時中斷,系統調用中斷。 # ignore_int是默認的中斷處理程序,若系統產生了其餘中斷,則會在屏幕上顯示一個字符'C' .align 4 ignore_int: push %ds pushl %eax movl $0x10, %eax mov %ax, %ds movl $67, %eax call write_char popl %eax pop %ds iret #這是定時中斷處理程序,其中主要執行任務切換操做。 .align 4 timer_interrupt: push %ds pushl %eax movl $0x10, %eax mov %ax, %ds movb $0x20, %al outb %al, $0x20 movl $1, %eax cmpl %eax, current je 1f movl %eax, current ljmp $TSS1_SEL, $0 jmp 2f 1: movl $0, current ljmp $TSS0_SEL, $0 2: popl %eax pop %ds iret #系統調用中斷 int0x80 處理程序,該示例只有一個顯示字符功能 .align 4 system_interrupt: push %ds pushl %edx pushl %ecx pushl %ebx pushl %eax movl $0x10, %edx mov %dx, %ds call write_char popl %eax popl %ebx popl %ecx popl %edx pop %ds iret /*******************************************/ #數據區。沒有專門定義,是和代碼區混合編寫的。 current: .long 0 #當前的任務號(0或者1) scr_loc: .long 0 #屏幕當前顯示位置,從左上到右下順序 .align 4 #書上是 .align 2 lidt_opcode: .word 256*8-1 #16位表長,無法經過減法得到長度,是經過調用fill填充的 .long idt #32位基地址 lgdt_opcode: .word (end_gdt-gdt)-1 #16位表長,能夠經過減法得到長度。 .long gdt #32位基地址 .align 8 #書上是 .align 3 idt: .fill 256,8,0 # 256個門描述符,每一個8字節,共佔用2KB gdt: #段描述符,可結合段描述符具體格式看 .quad 0x0000000000000000 #第1描述符,不用,quad是4字節寬度 .quad 0x00c09a00000007ff #第2描述符,內核代碼段,基地址0 段限長7ff,2047字節,選擇符0x08 = 1:0:00 # | | # +----+ 高地址 方便查表的格式 # | 00 | | 00 c0 9a 00 | # +----+ | 00 00 07 ff | # | c0 | # +----+ # | 9a | # +----+ # | 00 | # +----+ # | 00 | # +----+ # | 00 | # +----+ # | 07 | # +----+ 低地址 # | ff | # +----+ # | | .quad 0x00c09200000007ff #第3描述符,內核數據段,基地址0 只有TYPE段類型與第2描述符不同, 選擇符0x08 = 10:0:00 .quad 0x00c0920b80000002 #第4描述符 .word 0x0068,tss0,0xe900,0x0#第5描述符,TSS0段的描述符,基地址tss0,段限長104(0x68) # | | # +--------+ 高地址 方便查表的格式 # | 0x0000 | | 00 00 e9 00 | # +--------+ | tss0 00 68 | # | 0xe900 | # +--------+ # | tss0 | # +--------+ # | 0x0068 | # +--------+ 低地址 # | | .word 0x0040,ldt0,0xe200,0x0#第6描述符,LDT0段的描述符,基地址ldt0,段限長0x40 .word 0x0068,tss1,0xe900,0x0#第7描述符,TSS1段的描述符,基地址tss1,段限長0x68 .word 0x0040,ldt1,0xe200,0x0#第8描述符,LDT1段的描述符,基地址ldt1,段限長0x40 end_gdt: #用來計算gdt表的長度 .fill 128,4,0 #初始內核堆棧空間,後續給任務0當作內核數據段 init_stack: #剛進入保護模式時用於加載SS:ESP堆棧指針 .long init_stack #堆棧段偏移位置 .word 0x10 #堆棧段起始地址,同數據段 #下面是任務0的LDT表段中的局部段描述符 .align 8 #書上是 .align 3 ldt0: .quad 0x0000000000000000 #第1個描述符,不用 .quad 0x00c0fa00000003ff #第2個描述符,局部代碼段描述符,基地址是0,段限長3ff .quad 0x00c0f200000003ff #第3個描述符,局部數據段描述符,基地址是0,段限長3ff #下面是任務0的TSS段的內容 tss0: .long 0 .long krn_stk0, 0x10 # .long 0,0,0,0,0 # esp1, ssl1, esp2, ss2, cr3 .long 0,0,0,0,0 # eip, eflags, eax, ecx, edx .long 0,0,0,0,0 # ebx, esp, ebp, esi, edi .long 0,0,0,0,0,0 # es, cs, ss, ds, fs, gs .long LDT0_SEL, 0x8000000 # .fill 128,4,0 # krn_stk0: #下面是任務1的LDT表段內容和TSS段內容 .align 8 #書上是 .align 3 ldt1: .quad 0x0000000000000000 # 第1個描述符 .quad 0x00c0fa00000003ff # 第2個描述符 .quad 0x00c0f200000003ff # 第3個描述符 tss1: .long 0 #同tss0 .long krn_stk1, 0x10 .long 0,0,0,0,0 .long task1, 0x200 # eip eflags .long 0,0,0,0 .long usr_stk1,0,0,0 .long 0x17,0x0f,0x17,0x17,0x17,0x17 .long LDT1_SEL, 0x8000000 .fill 128,4,0 #任務1的內核棧空間 krn_stk1: #下面是任務0和任務1的程序 task0: movl $0x17, %eax #首先讓DS指向任務的局部數據段 movw %ax, %ds movb $65, %al #把須要顯示的字符A放入AL寄存器中 #書上寫的是 movl $65 %al int $0x80 #執行系統調用 movl $0xfff, %ecx #執行循環,起延時做用 1: loop 1b jmp task0 task1: movl $0x17, %eax movw %ax, %ds movb $66, %al #把須要顯示的字符B放入AL寄存器中 #書上寫的是 movl $66 %al int $0x80 #系統調用 movl $0xfff, %ecx #延時一段時間,並跳轉到開始出繼續循環顯示 1: loop 1b jmp task1 .fill 128,4,0 #任務1的用戶棧空間 usr_stk1:
啓動