GiraffeOS设计与实现(6)-执行任务

(由于之前的blog已经关闭了,所以将此文章迁移至这里,并非转载)

今天更正了下之前写文章里面的一些错误之类的东西。看之前的文章,应该已经可以正常的启动那个CPU1了。回头想想,可能有人还是没操作成功,估计是不知道怎么编译汇编成BIN,或者是不知道怎么将BIN的内容拷贝到内存上?本节我们将对这个问题,继续讲解下。

任务开始

本节的标题是执行任务,的确目的是执行一个用户定义的任务。回头看之前贴过的汇编代码。

;
;
; PROJECT: GiraffeOS
; FILE: ap_boot.asm
; PURPOSE: Boot code for application processors
; PROGRAMMER: BorisJineman([email protected])
; UPDATE HISTORY:
; Created 2013-3-21
;
; The Boot Code Start With 0x00080000
; The Data On 0x00081000

;
; Segment selectors
;
%define KERNEL_CS (0x8)
%define KERNEL_DS (0x10)
%define MAIN_CS (0x18)
%define MAIN_DS (0x20)

; 16 bit code
BITS 16 ;start with bit16(real mode)

_APstart:
cli

test_real_start:
xor ax, ax ;clear ax,ds,ss
mov ds, ax
mov ss, ax

mov ax, 08000H ;set seg 0x00080000
mov ds, ax
mov bx, 01000H
mov cx, 100 ;loop to 100

mov ax, 00H ;begin with 0
s: mov [bx], ax ;just write
inc bx ;bx++
inc bx ;bx++
inc ax ;value++
loop s ;go loop

in ax, 92h ; enable A20
or ax, 00000010b
out 92h, ax

xor ax, ax ;clear ax,ds,ss
mov ds, ax
mov ss, ax

mov ax, 08000H ;set the seg 0x00080000
mov ds, ax

mov eax, 00H + APgdt – _APstart
lgdt [eax]

mov eax, cr0 ; start cpu protect mode,32bit,
or eax, 1
mov cr0, eax

jmp dword KERNEL_CS:000080000H + protected_mode_begin – _APstart

BITS 32

protected_mode_begin:

mov ax, MAIN_DS
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
mov ss, ax

mov esp, 00F000000h ; the stack 0x7F000000

start_main:
jmp $
jmp MAIN_CS:0 ; main fun ptr 0x70000000

hlt

; GDT reg
APgdt:
; Limit
dw 5*8-1
; Base
dd 080000H + gdt – _APstart

; GDT table
gdt:
dw 0x0 ; Null descriptor
dw 0x0
dw 0x0
dw 0x0

dw 0xffff ; Kernel code descriptor 0x00000000~0xFFFFFFFF
dw 0x0000
dw 0x9a00
dw 0x00cf

dw 0xffff ; Kernel data descriptor 0x00000000~0xFFFFFFFF
dw 0x0000
dw 0x9200
dw 0x00cf

dw 0xffff ; Main code descriptor 0x70000000~0xFFFFFFFF
dw 0x0000
dw 0x9a00
dw 0x70c8

dw 0xffff ; Main data descriptor 0x70000000~0xFFFFFFFF
dw 0x0000
dw 0x9200
dw 0x70c8

注意找到“protected_mode_begin”的这个地方,这个地方已经被引导到保护模式,并且设置了栈指针指向0x7F000000。

然后再注意“start_main”这个地方,紧接着就会执行到这里,这里就已经开始进入到用户真正的任务了,用户可以将具体的任务用汇编写到这里。

如何编译

编译的话,需要大家使用nasm,什么是nasm,请移步http://www.nasm.us/。

将代码保存成.asm后缀的文件,然后直接使用“nasm {文件名}”即可。最后将会在目录中发现一个同名文件,但是没有后缀名。

经过如上步骤,如果没有报错,那就代表编译成功了。

如何拷贝到内存

拿着上面编译生成的文件,看其中的数据(byte数组),具体怎么拷贝出来,可以从网上搜winhex。我是用这个软件。方便。

将拷贝出来的数组,写到前面讲的有一个发INIT-SIPI-SIPI的代码里面,在代码的前面,我之前说过要拷贝一份引导代码过去,没错,这就是那个引导代码。我将这部分代码再贴出来一次。

/* * loader.c * * Created on: 2013-3-21 * Author: BorisJineman * purpose: This code is currently just boot CPU1, written by BorisJineman. * More features will be supported later. * Let us wait and see. */

#include <ntddk.h> // various NT definitions
#include "loader.h"

DRIVER_INITIALIZE DriverEntry;
DRIVER_UNLOAD UnloadGiraffeOS;

APIC * pAPIC=0;

NTSTATUS DriverEntry(__in PDRIVER_OBJECT DriverObject,__in PUNICODE_STRING RegistryPath)
{

unsigned long has_local_apic=0;
unsigned long pa=0;
PHYSICAL_ADDRESS PhysicalAddress;
unsigned char * p_mem=0;

unsigned int acpi_ICR1_temp=0;
unsigned int acpi_ICR2_temp=0;

LARGE_INTEGER startTime;
LARGE_INTEGER currentTime;

unsigned char ap_boot_code[149] = {
0xFA, 0x31, 0xC0, 0x8E, 0xD8, 0x8E, 0xD0, 0xB8, 0x00, 0x80, 0x8E, 0xD8, 0xBB, 0x00, 0x10, 0xB9,
0x64, 0x00, 0xB8, 0x00, 0x00, 0x89, 0x07, 0x43, 0x43, 0x40, 0xE2, 0xF9, 0xE5, 0x92, 0x83, 0xC8,
0x02, 0xE7, 0x92, 0x31, 0xC0, 0x8E, 0xD8, 0x8E, 0xD0, 0xB8, 0x00, 0x80, 0x8E, 0xD8, 0x66, 0xB8,
0x67, 0x00, 0x00, 0x00, 0x67, 0x0F, 0x01, 0x10, 0x0F, 0x20, 0xC0, 0x66, 0x83, 0xC8, 0x01, 0x0F,
0x22, 0xC0, 0x66, 0xEA, 0x4A, 0x00, 0x08, 0x00, 0x08, 0x00, 0x66, 0xB8, 0x20, 0x00, 0x8E, 0xD8,
0x8E, 0xC0, 0x8E, 0xE0, 0x8E, 0xE8, 0x8E, 0xD0, 0xBC, 0x00, 0x00, 0x00, 0x0F, 0xEB, 0xFE, 0xEA,
0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0xF4, 0x27, 0x00, 0x6D, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x9A, 0xCF, 0x00, 0xFF, 0xFF, 0x00,
0x00, 0x00, 0x92, 0xCF, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x9A, 0xC8, 0x70, 0xFF, 0xFF, 0x00,
0x00, 0x00, 0x92, 0xC8, 0x70
};

// detect local apic
__asm {
mov eax, 1;
cpuid;
shr edx, 9; // if there is a local apic, then bit 9 will be set
and edx, 0x1;
mov has_local_apic, edx;
}

if (!has_local_apic)
return 0;

pa = 0xFEE00000;
__asm {
mov ecx, 0x1B; // offset into apicbase
rdmsr; //Load MSR specified by ECX into EDX:EAX
mov edx, eax;
and edx, 0xFFFFF000; // bits 31:12 contain the APICBASE address for the local apic
mov pa, edx;
}

memset(&PhysicalAddress,0,sizeof(PHYSICAL_ADDRESS));
PhysicalAddress.LowPart = (unsigned long)pa;
pAPIC= (APIC *)MmMapIoSpace(PhysicalAddress, sizeof(APIC), MmNonCached);

memset(&PhysicalAddress,0,sizeof(PHYSICAL_ADDRESS));
PhysicalAddress.LowPart = (unsigned long)0x00080000;
p_mem= (unsigned char *)MmMapIoSpace(PhysicalAddress, sizeof(ap_boot_code), MmNonCached);
memcpy(p_mem,&ap_boot_code,sizeof(ap_boot_code));
MmUnmapIoSpace(p_mem, sizeof(ap_boot_code));

CMOS_WRITE(0x0f,0x0a); //System Shutdown Code

acpi_ICR2_temp=0x01000000; //select cpu 1
acpi_ICR1_temp=0x00004500; //send init ipi
*(unsigned long *)((unsigned char *)pAPIC + 0x310)=acpi_ICR2_temp;
*(unsigned long *)((unsigned char *)pAPIC + 0x300)=acpi_ICR1_temp;

KeQuerySystemTime(&startTime);
while(1){
KeQuerySystemTime(&currentTime);
if((currentTime.QuadPart-startTime.QuadPart) >= 10*10000) break;
}

acpi_ICR2_temp=0x01000000; //select cpu 1
acpi_ICR1_temp=0x00004680; //send start ipi and start from 0x00080000
*(unsigned long *)((unsigned char *)pAPIC + 0x310)=acpi_ICR2_temp;
*(unsigned long *)((unsigned char *)pAPIC + 0x300)=acpi_ICR1_temp;

KeQuerySystemTime(&startTime);
while(1){
KeQuerySystemTime(&currentTime);
if((currentTime.QuadPart-startTime.QuadPart) >= 2) break;
}

acpi_ICR2_temp=0x01000000; //select cpu 1
acpi_ICR1_temp=0x00004680; //send start ipi and start from 0x00080000
*(unsigned long *)((unsigned char *)pAPIC + 0x310)=acpi_ICR2_temp;
*(unsigned long *)((unsigned char *)pAPIC + 0x300)=acpi_ICR1_temp;

KeQuerySystemTime(&startTime);
while(1){
KeQuerySystemTime(&currentTime);
if((currentTime.QuadPart-startTime.QuadPart) >= 10*10000) break;
}

return 0;
}

VOID UnloadGiraffeOS(__in PDRIVER_OBJECT DriverObject)
{

unsigned int acpi_ICR1_temp;
unsigned int acpi_ICR2_temp;

//to stop the cpu 1 ,just send init ipi

CMOS_WRITE(0x0f,0x0a); //System Shutdown Code

acpi_ICR2_temp=0x01000000; //select cpu 1
acpi_ICR1_temp=0x00004500; //send init ipi
*(unsigned long *)((unsigned char *)pAPIC + 0x310)=acpi_ICR2_temp;
*(unsigned long *)((unsigned char *)pAPIC + 0x300)=acpi_ICR1_temp;

MmUnmapIoSpace(pAPIC, sizeof(APIC));

}

可以在上述代码中,找到一个ap_boot_code的数组,这个数组就是ap_boot.asm的编译结果。

改革开放进入C时代

用汇编写任务的确很麻烦,所以有人就会问能不能写C代码,当然能。就是需要做点操作。具体的操作就是,一个jmp。一个jmp MAIN_CODE:0即可。这句跳转的意思指,直接跳转到0x70000000处开始执行代码。具体的C代码,用户可以参考这种方式直接写到这里。推荐用户用gcc编译代码,其实是先方式和上面是先ap_boot代码的实现方式差不多,都是编译成Bin文件,然后拷贝到相对应的一段内存上,然后运行。

这里可能涉及一些makefile的编写,以及裸奔x86时遇到的和在学校学C语言不一样的地方。这些东西我还是在下一节里面具体讲,因为真的是太多了。

同时GiraffeOS的代码也得跟进了。

言谢

这篇文章真的是拖了很久,本来想写,不过由于最近各种事情的发生,弄得我真的没有心思写了,跳票一段时间,请各位观众海涵,~

未完,待续……

你可能感兴趣的:(c,汇编,task,功能,GiraffeOS)