提交 29aa8205 创建 作者: 赵鹏翀's avatar 赵鹏翀

Initial commit

上级
/*
/*
提供该示例代码是为了阐释一个概念,或者进行一个测试,并不代表着
最安全的编码实践,因此不应在应用程序或网站中使用该示例代码。对
于超出本示例代码的预期用途以外的使用所造成的偶然或继发性损失,
北京英真时代科技有限公司不承担任何责任。
*/
#include "EOSApp.h"
int main(int argc, char* argv[])
{
int i;
for (i = 1; i <= 5; i++) {
printf("Hello,world! %d\n", i);
Sleep(1000);
}
printf("Bye-bye!\n");
return 0;
}
/*
/*
提供该示例代码是为了阐释一个概念,或者进行一个测试,并不代表着
最安全的编码实践,因此不应在应用程序或网站中使用该示例代码。对
于超出本示例代码的预期用途以外的使用所造成的偶然或继发性损失,
北京英真时代科技有限公司不承担任何责任。
*/
#include "EOSApp.h"
//
// 线程函数
//
ULONG AppThread(PVOID Param);
//
// main 函数参数的意义:
// argc - argv 数组的长度,大小至少为 1,argc - 1 为命令行参数的数量。
// argv - 字符串指针数组,数组长度为命令行参数个数 + 1。其中 argv[0] 固定指向当前
// 进程所执行的可执行文件的路径字符串,argv[1] 及其后面的指针指向各个命令行
// 参数。
//
int main(int argc, char* argv[])
{
//
// 启动调试 EOS 应用程序前要特别注意下面的问题:
//
// 1、如果要在调试应用程序时能够调试进入内核并显示对应的源码,
// 必须使用 EOS 核心项目编译生成完全版本的 SDK 文件夹,然
// 后使用此文件夹覆盖应用程序项目中的 SDK 文件夹,并且 EOS
// 核心项目在磁盘上的位置不能改变。
//
HANDLE AppThreadHandle;
//
// 创建线程。
//
AppThreadHandle = CreateThread( 0, // 默认堆栈大小
AppThread, // 线程函数入口地址
NULL, // 线程函数参数
0, // 创建标志
NULL ); // 线程 ID
if (NULL == AppThreadHandle) {
return 4;
}
WaitForSingleObject(AppThreadHandle, INFINITE);
CloseHandle(AppThreadHandle);
return 0;
}
//
// 线程函数。
//
ULONG AppThread(PVOID Param)
{
printf("Hello world");
return 0;
}
/*
/*
提供该示例代码是为了阐释一个概念,或者进行一个测试,并不代表着
最安全的编码实践,因此不应在应用程序或网站中使用该示例代码。对
于超出本示例代码的预期用途以外的使用所造成的偶然或继发性损失,
北京英真时代科技有限公司不承担任何责任。
*/
#include "EOSApp.h"
int main(int argc, char* argv[])
{
int i;
for (i = 1; i <= 5; i++) {
printf("Hello,world! %d\n", i);
Sleep(1000);
}
printf("Bye-bye!\n");
return 0;
}
/*
/*
提供该示例代码是为了阐释一个概念,或者进行一个测试,并不代表着
最安全的编码实践,因此不应在应用程序或网站中使用该示例代码。对
于超出本示例代码的预期用途以外的使用所造成的偶然或继发性损失,
北京英真时代科技有限公司不承担任何责任。
*/
#include "EOSApp.h"
//
// main 函数参数的意义:
// argc - argv 数组的长度,大小至少为 1,argc - 1 为命令行参数的数量。
// argv - 字符串指针数组,数组长度为命令行参数个数 + 1。其中 argv[0] 固定指向当前
// 进程所执行的可执行文件的路径字符串,argv[1] 及其后面的指针指向各个命令行
// 参数。
// 例如通过命令行内容 "a:\hello.exe -a -b" 启动进程后,hello.exe 的 main 函
// 数的参数 argc 的值为 3,argv[0] 指向字符串 "a:\hello.exe",argv[1] 指向
// 参数字符串 "-a",argv[2] 指向参数字符串 "-b"。
//
int main(int argc, char* argv[])
{
//
// 启动调试 EOS 应用程序前要特别注意下面的问题:
//
// 1、如果要在调试应用程序时能够调试进入内核并显示对应的源码,
// 必须使用 EOS 核心项目编译生成完全版本的 SDK 文件夹,然
// 后使用此文件夹覆盖应用程序项目中的 SDK 文件夹,并且 EOS
// 核心项目在磁盘上的位置不能改变。
//
STARTUPINFO StartupInfo;
PROCESS_INFORMATION ProcInfo;
ULONG ulExitCode; // 子进程退出码
INT nResult = 0; // main 函数返回值。0 表示成功,非 0 表示失败。
printf("Create a process and wait for the process exit...\n\n");
//
// 使子进程和父进程使用相同的标准句柄。
//
StartupInfo.StdInput = GetStdHandle(STD_INPUT_HANDLE);
StartupInfo.StdOutput = GetStdHandle(STD_OUTPUT_HANDLE);
StartupInfo.StdError = GetStdHandle(STD_ERROR_HANDLE);
//
// 创建子进程。
//
if (CreateProcess("A:\\Hello.exe", NULL, 0, &StartupInfo, &ProcInfo)) {
//
// 创建子进程成功,等待子进程运行结束。
//
WaitForSingleObject(ProcInfo.ProcessHandle, INFINITE);
//
// 得到并输出子进程的退出码。
//
GetExitCodeProcess(ProcInfo.ProcessHandle, &ulExitCode);
printf("\nThe process exit with %d.\n", ulExitCode);
//
// 关闭不再使用的句柄。
//
CloseHandle(ProcInfo.ProcessHandle);
CloseHandle(ProcInfo.ThreadHandle);
} else {
printf("CreateProcess Failed, Error code: 0x%X.\n", GetLastError());
nResult = 1;
}
return nResult;
}
/*
/*
提供该示例代码是为了阐释一个概念,或者进行一个测试,并不代表着
最安全的编码实践,因此不应在应用程序或网站中使用该示例代码。对
于超出本示例代码的预期用途以外的使用所造成的偶然或继发性损失,
北京英真时代科技有限公司不承担任何责任。
*/
#include "EOSApp.h"
//
// main 函数参数的意义:
// argc - argv 数组的长度,大小至少为 1,argc - 1 为命令行参数的数量。
// argv - 字符串指针数组,数组长度为命令行参数个数 + 1。其中 argv[0] 固定指向当前
// 进程所执行的可执行文件的路径字符串,argv[1] 及其后面的指针指向各个命令行
// 参数。
// 例如通过命令行内容 "a:\hello.exe -a -b" 启动进程后,hello.exe 的 main 函
// 数的参数 argc 的值为 3,argv[0] 指向字符串 "a:\hello.exe",argv[1] 指向
// 参数字符串 "-a",argv[2] 指向参数字符串 "-b"。
//
int main(int argc, char* argv[])
{
//
// 启动调试 EOS 应用程序前要特别注意下面的问题:
//
// 1、如果要在调试应用程序时能够调试进入内核并显示对应的源码,
// 必须使用 EOS 核心项目编译生成完全版本的 SDK 文件夹,然
// 后使用此文件夹覆盖应用程序项目中的 SDK 文件夹,并且 EOS
// 核心项目在磁盘上的位置不能改变。
//
STARTUPINFO StartupInfo;
PROCESS_INFORMATION ProcInfoOne, ProcInfoTwo;
ULONG ulExitCode; // 子进程退出码
INT nResult = 0; // main 函数返回值。0 表示成功,非 0 表示失败。
printf("Create two processes and wait for the processes exit...\n\n");
//
// 使子进程和父进程使用相同的标准句柄。
//
StartupInfo.StdInput = GetStdHandle(STD_INPUT_HANDLE);
StartupInfo.StdOutput = GetStdHandle(STD_OUTPUT_HANDLE);
StartupInfo.StdError = GetStdHandle(STD_ERROR_HANDLE);
//
// 为一个应用程序同时创建两个子进程。
//
if (CreateProcess("A:\\Hello.exe", NULL, 0, &StartupInfo, &ProcInfoOne)
&& CreateProcess("A:\\Hello.exe", NULL, 0, &StartupInfo, &ProcInfoTwo)) {
//
// 创建子进程成功,等待子进程运行结束。
//
WaitForSingleObject(ProcInfoOne.ProcessHandle, INFINITE);
WaitForSingleObject(ProcInfoTwo.ProcessHandle, INFINITE);
//
// 得到并输出子进程的退出码。
//
GetExitCodeProcess(ProcInfoOne.ProcessHandle, &ulExitCode);
printf("\nThe process one exit with %d.\n", ulExitCode);
GetExitCodeProcess(ProcInfoTwo.ProcessHandle, &ulExitCode);
printf("\nThe process two exit with %d.\n", ulExitCode);
//
// 关闭不再使用的句柄。
//
CloseHandle(ProcInfoOne.ProcessHandle);
CloseHandle(ProcInfoOne.ThreadHandle);
CloseHandle(ProcInfoTwo.ProcessHandle);
CloseHandle(ProcInfoTwo.ThreadHandle);
} else {
printf("CreateProcess Failed, Error code: 0x%X.\n", GetLastError());
nResult = 1;
}
return nResult;
}
/*
/*
提供该示例代码是为了阐释一个概念,或者进行一个测试,并不代表着
最安全的编码实践,因此不应在应用程序或网站中使用该示例代码。对
于超出本示例代码的预期用途以外的使用所造成的偶然或继发性损失,
北京英真时代科技有限公司不承担任何责任。
*/
//
// 消费者线程函数。
//
ULONG Consumer(PVOID Param)
{
int i;
int OutIndex = 0;
for (i = 0; i < PRODUCT_COUNT; i += 2) {
while(WAIT_TIMEOUT == WaitForSingleObject(FullSemaphoreHandle, 300)){
printf("Consumer wait for full semaphore timeout\n");
}
while(WAIT_TIMEOUT == WaitForSingleObject(FullSemaphoreHandle, 300)){
printf("Consumer wait for full semaphore timeout\n");
}
WaitForSingleObject(MutexHandle, INFINITE);
printf("\t\t\tConsume a %d\n", Buffer[OutIndex]);
OutIndex = (OutIndex + 1) % BUFFER_SIZE;
printf("\t\t\tConsume a %d\n", Buffer[OutIndex]);
OutIndex = (OutIndex + 1) % BUFFER_SIZE;
ReleaseMutex(MutexHandle);
ReleaseSemaphore(EmptySemaphoreHandle, 2, NULL);
//
// 休息一会儿。让前 14 个数的消费速度比较慢,后面的较快。
//
if (i < 14) {
Sleep(2000);
} else {
Sleep(100);
}
}
return 0;
}
/*
/*
提供该示例代码是为了阐释一个概念,或者进行一个测试,并不代表着
最安全的编码实践,因此不应在应用程序或网站中使用该示例代码。对
于超出本示例代码的预期用途以外的使用所造成的偶然或继发性损失,
北京英真时代科技有限公司不承担任何责任。
*/
#include "EOSApp.h"
//
// 缓冲池。
//
#define BUFFER_SIZE 10
int Buffer[BUFFER_SIZE];
//
// 产品数量。
//
#define PRODUCT_COUNT 30
//
// 用于生产者和消费者同步的对象句柄。
//
HANDLE MutexHandle;
HANDLE EmptySemaphoreHandle;
HANDLE FullSemaphoreHandle;
//
// 生产者和消费者的线程函数
//
ULONG Producer(PVOID Param);
ULONG Consumer(PVOID Param);
//
// main 函数参数的意义:
// argc - argv 数组的长度,大小至少为 1,argc - 1 为命令行参数的数量。
// argv - 字符串指针数组,数组长度为命令行参数个数 + 1。其中 argv[0] 固定指向当前
// 进程所执行的可执行文件的路径字符串,argv[1] 及其后面的指针指向各个命令行
// 参数。
// 例如通过命令行内容 "a:\hello.exe -a -b" 启动进程后,hello.exe 的 main 函
// 数的参数 argc 的值为 3,argv[0] 指向字符串 "a:\hello.exe",argv[1] 指向
// 参数字符串 "-a",argv[2] 指向参数字符串 "-b"。
//
int main(int argc, char* argv[])
{
//
// 启动调试 EOS 应用程序前要特别注意下面的问题:
//
// 1、如果要在调试应用程序时能够调试进入内核并显示对应的源码,
// 必须使用 EOS 核心项目编译生成完全版本的 SDK 文件夹,然
// 后使用此文件夹覆盖应用程序项目中的 SDK 文件夹,并且 EOS
// 核心项目在磁盘上的位置不能改变。
//
HANDLE ProducerHandle;
HANDLE ConsumerHandle;
//
// 创建用于互斥访问缓冲池的 Mutex 对象。
//
MutexHandle = CreateMutex(FALSE, NULL);
if (NULL == MutexHandle) {
return 1;
}
//
// 创建 Empty 信号量,表示缓冲池中空缓冲区数量。初始计数和最大计数都为 BUFFER_SIZE。
//
EmptySemaphoreHandle = CreateSemaphore(BUFFER_SIZE, BUFFER_SIZE, NULL);
if (NULL == EmptySemaphoreHandle) {
return 2;
}
//
// 创建 Full 信号量,表示缓冲池中满缓冲区数量。初始计数为 0,最大计数为 BUFFER_SIZE。
//
FullSemaphoreHandle = CreateSemaphore(0, BUFFER_SIZE, NULL);
if (NULL == FullSemaphoreHandle) {
return 3;
}
//
// 创建生产者线程。
//
ProducerHandle = CreateThread( 0, // 默认堆栈大小
Producer, // 线程函数入口地址
NULL, // 线程函数参数
0, // 创建标志
NULL ); // 线程 ID
if (NULL == ProducerHandle) {
return 4;
}
//
// 创建消费者线程。
//
ConsumerHandle = CreateThread( 0,
Consumer,
NULL,
0,
NULL );
if (NULL == ConsumerHandle) {
return 5;
}
//
// 等待生产者线程和消费者线程结束。
//
WaitForSingleObject(ProducerHandle, INFINITE);
WaitForSingleObject(ConsumerHandle, INFINITE);
//
// 关闭句柄
//
CloseHandle(MutexHandle);
CloseHandle(EmptySemaphoreHandle);
CloseHandle(FullSemaphoreHandle);
CloseHandle(ProducerHandle);
CloseHandle(ConsumerHandle);
return 0;
}
//
// 生产者线程函数。
//
ULONG Producer(PVOID Param)
{
int i;
int InIndex = 0;
for (i = 0; i < PRODUCT_COUNT; i++) {
WaitForSingleObject(EmptySemaphoreHandle, INFINITE);
WaitForSingleObject(MutexHandle, INFINITE);
printf("Produce a %d\n", i);
Buffer[InIndex] = i;
InIndex = (InIndex + 1) % BUFFER_SIZE;
ReleaseMutex(MutexHandle);
ReleaseSemaphore(FullSemaphoreHandle, 1, NULL);
//
// 休息一会。每 500 毫秒生产一个数。
//
Sleep(500);
}
return 0;
}
//
// 消费者线程函数。
//
ULONG Consumer(PVOID Param)
{
int i;
int OutIndex = 0;
for (i = 0; i < PRODUCT_COUNT; i++) {
WaitForSingleObject(FullSemaphoreHandle, INFINITE);
WaitForSingleObject(MutexHandle, INFINITE);
printf("\t\t\tConsume a %d\n", Buffer[OutIndex]);
OutIndex = (OutIndex + 1) % BUFFER_SIZE;
ReleaseMutex(MutexHandle);
ReleaseSemaphore(EmptySemaphoreHandle, 1, NULL);
//
// 休息一会儿。让前 10 个数的消费速度比较慢,后面的较快。
//
if (i < 10) {
Sleep(2000);
} else {
Sleep(100);
}
}
return 0;
}
#include "EOSApp.h"
#include "EOSApp.h"
//
// main 函数参数的意义:
// argc - argv 数组的长度,大小至少为 1,argc - 1 为命令行参数的数量。
// argv - 字符串指针数组,数组长度为命令行参数个数 + 1。其中 argv[0] 固定指向当前
// 进程所执行的可执行文件的路径字符串,argv[1] 及其后面的指针指向各个命令行
// 参数。
// 例如通过命令行内容 "a:\hello.exe -a -b" 启动进程后,hello.exe 的 main 函
// 数的参数 argc 的值为 3,argv[0] 指向字符串 "a:\hello.exe",argv[1] 指向
// 参数字符串 "-a",argv[2] 指向参数字符串 "-b"。
//
int main(int argc, char* argv[])
{
//
// 启动调试 EOS 应用程序前要特别注意下面的问题:
//
// 1、如果要在调试应用程序时能够调试进入内核并显示对应的源码,
// 必须使用 EOS 核心项目编译生成完全版本的 SDK 文件夹,然
// 后使用此文件夹覆盖应用程序项目中的 SDK 文件夹,并且 EOS
// 核心项目在磁盘上的位置不能改变。
//
// 2、在启动调试应用程序之前必须首先删除/禁用所有的断点,在断
// 点中断 (int 3) 被命中后才能重新添加/启用断点,否则启动
// 调试会失败。
//
#ifdef _DEBUG
__asm("int $3\n nop");
#endif
/* TODO: 在此处添加自己的代码 */
//
// 开始死循环,这样应用程序进程就不会结束。
//
printf("Endless loop!\n");
for(;;) {
}
return 0;
}
/*
/*
提供该示例代码是为了阐释一个概念,或者进行一个测试,并不代表着
最安全的编码实践,因此不应在应用程序或网站中使用该示例代码。对
于超出本示例代码的预期用途以外的使用所造成的偶然或继发性损失,
北京英真时代科技有限公司不承担任何责任。
*/
PRIVATE
VOID
ConsoleCmdPhysicalMemory(
IN HANDLE StdHandle
)
{
BOOL IntState;
ULONG_PTR PfnArray[1];
IntState = KeEnableInterrupts(FALSE); // 关中断
//
// 输出物理页数量和物理内存数量(以字节为单位)
//
fprintf(StdHandle, "Page Count: %d.\n", MiTotalPageFrameCount);
fprintf(StdHandle, "Memory Count: %d * %d = %d Byte.\n",
MiTotalPageFrameCount, PAGE_SIZE,
MiTotalPageFrameCount * PAGE_SIZE);
//
// 输出零页数量和空闲页数量
//
fprintf(StdHandle, "\nZeroed Page Count: %d.\n", MiZeroedPageCount);
fprintf(StdHandle, "Free Page Count: %d.\n", MiFreePageCount);
//
// 输出已使用的物理页数量
//
fprintf(StdHandle, "\nUsed Page Count: %d.\n", MiTotalPageFrameCount - MiZeroedPageCount - MiFreePageCount);
//////////////////////////////////////////////////////////////////////////
// 分配一个物理页
//
MiAllocateAnyPages(1, PfnArray);
fprintf(StdHandle, "\n****** After Allocate One Page ******\n");
fprintf(StdHandle, "Zeroed Page Count: %d.\n", MiZeroedPageCount);
fprintf(StdHandle, "Free Page Count: %d.\n", MiFreePageCount);
fprintf(StdHandle, "Used Page Count: %d.\n", MiTotalPageFrameCount - MiZeroedPageCount - MiFreePageCount);
//////////////////////////////////////////////////////////////////////////
//
// 然后再释放这个物理页
//
MiFreePages(1, PfnArray);
fprintf(StdHandle, "\n****** After Free One Page ******\n");
fprintf(StdHandle, "Zeroed Page Count: %d.\n", MiZeroedPageCount);
fprintf(StdHandle, "Free Page Count: %d.\n", MiFreePageCount);
fprintf(StdHandle, "Used Page Count: %d.\n", MiTotalPageFrameCount - MiZeroedPageCount - MiFreePageCount);
KeEnableInterrupts(IntState); // 开中断
}
/*
/*
提供该示例代码是为了阐释一个概念,或者进行一个测试,并不代表着
最安全的编码实践,因此不应在应用程序或网站中使用该示例代码。对
于超出本示例代码的预期用途以外的使用所造成的偶然或继发性损失,
北京英真时代科技有限公司不承担任何责任。
*/
PRIVATE
VOID
ConsoleCmdVM(
IN HANDLE StdHandle,
IN PCSTR Arg
)
{
BOOL IntState;
ULONG ProcID;
PPROCESS pProcCtrlBlock;
PMMVAD_LIST pVadList;
PLIST_ENTRY pListEntry;
PMMVAD pVad;
ULONG Index, TotalVpnCount, AllocatedVpnCount, FreeVpnCount, VpnCount;
STATUS Status;
const char* OutputFormat = NULL;
//
// 从命令参数字符串中获得进程 ID。
//
ProcID = atoi(Arg);
if(0 == ProcID) {
fprintf(StdHandle, "Please input a valid process ID.\n");
return;
}
//
// 由进程 ID 获得进程控制块
//
Status = ObRefObjectById(ProcID, PspProcessType, (PVOID*)&pProcCtrlBlock);
if (!EOS_SUCCESS(Status)) {
fprintf(StdHandle, "%d is an invalid process ID.\n", ProcID);
return;
}
IntState = KeEnableInterrupts(FALSE); // 关中断
//
// 将进程控制块中 VAD 链表的指针保存下来,方便后面使用
//
pVadList = &pProcCtrlBlock->Pas->VadList;
//
// 输出 VAD 链表中记录的起始页框号,结束页框号
//
OutputFormat = "Total Vpn from %d to %d. (0x%X - 0x%X)\n\n";
fprintf(StdHandle, OutputFormat,
pVadList->StartingVpn, pVadList->EndVpn,
pVadList->StartingVpn * PAGE_SIZE, (pVadList->EndVpn + 1) * PAGE_SIZE - 1);
//
// 遍历 VAD 链表,输出所有 VAD 的起始页框号,结束页框号和包含的虚拟页框数量
//
Index = AllocatedVpnCount = 0;
for(pListEntry = pVadList->VadListHead.Next;
pListEntry != &pVadList->VadListHead;
pListEntry = pListEntry->Next) {
Index++;
pVad = CONTAINING_RECORD(pListEntry, MMVAD, VadListEntry);
VpnCount = pVad->EndVpn - pVad->StartingVpn + 1;
OutputFormat = "%d# Vad Include %d Vpn From %d to %d. (0x%X - 0x%X)\n";
fprintf(StdHandle, OutputFormat,
Index, VpnCount, pVad->StartingVpn, pVad->EndVpn,
pVad->StartingVpn * PAGE_SIZE, (pVad->EndVpn + 1) * PAGE_SIZE - 1);
AllocatedVpnCount += VpnCount;
}
//
// 统计虚拟页框总数、已分配的虚拟页框和未分配的虚拟页框
//
TotalVpnCount = pVadList->EndVpn - pVadList->StartingVpn + 1;
OutputFormat = "\nTotal Vpn Count: %d.\n";
fprintf(StdHandle, OutputFormat, TotalVpnCount);
OutputFormat = "Allocated Vpn Count: %d.\n";
fprintf(StdHandle, OutputFormat, AllocatedVpnCount);
FreeVpnCount = TotalVpnCount - AllocatedVpnCount;
OutputFormat = "Free Vpn Count: %d.\n\n";
fprintf(StdHandle, OutputFormat, FreeVpnCount);
//
// 输出物理页的零页数量和空闲页数量
//
OutputFormat = "Zeroed Physical Page Count: %d.\n";
fprintf(StdHandle, OutputFormat, MiZeroedPageCount);
OutputFormat = "Free Physical Page Count: %d.\n\n";
fprintf(StdHandle, OutputFormat, MiFreePageCount);
//////////////////////////////////////////////////////////////////////////
//
// 分配一块新的虚拟内存。但是没有使用 MEM_COMMIT 标志为其分配物理页。
//
PVOID BaseAddress = 0;
SIZE_T RegionSize = 1;
Status = MmAllocateVirtualMemory(&BaseAddress, &RegionSize, MEM_RESERVE, TRUE);
if (!EOS_SUCCESS(Status)) {
fprintf(StdHandle, "Allocate virtual memory at 0x%X faild.\n", BaseAddress);
goto VM_RETURN;
}
//
// 输出新分配的内存的基址和大小
//
OutputFormat = "New VM's base address: 0x%X. Size: 0x%X.\n\n";
fprintf(StdHandle, OutputFormat, BaseAddress, RegionSize);
//
// 遍历 VAD 链表,输出所有 VAD 的起始页框号,结束页框号和包含的虚拟页框数量
//
Index = AllocatedVpnCount = 0;
for(pListEntry = pVadList->VadListHead.Next;
pListEntry != &pVadList->VadListHead;
pListEntry = pListEntry->Next) {
Index++;
pVad = CONTAINING_RECORD(pListEntry, MMVAD, VadListEntry);
VpnCount = pVad->EndVpn - pVad->StartingVpn + 1;
OutputFormat = "%d# Vad Include %d Vpn From %d to %d. (0x%X - 0x%X)\n";
fprintf(StdHandle, OutputFormat,
Index, VpnCount, pVad->StartingVpn, pVad->EndVpn,
pVad->StartingVpn * PAGE_SIZE, (pVad->EndVpn + 1) * PAGE_SIZE - 1);
AllocatedVpnCount += VpnCount;
}
//
// 统计已分配的虚拟页框和未分配的虚拟页框
//
OutputFormat = "\nAllocated Vpn Count: %d.\n";
fprintf(StdHandle, OutputFormat, AllocatedVpnCount);
FreeVpnCount = TotalVpnCount - AllocatedVpnCount;
OutputFormat = "Free Vpn Count: %d.\n\n";
fprintf(StdHandle, OutputFormat, FreeVpnCount);
//
// 输出物理页的零页数量和空闲页数量
//
OutputFormat = "Zeroed Physical Page Count: %d.\n";
fprintf(StdHandle, OutputFormat, MiZeroedPageCount);
OutputFormat = "Free Physical Page Count: %d.\n\n";
fprintf(StdHandle, OutputFormat, MiFreePageCount);
//////////////////////////////////////////////////////////////////////////
//
// 释放刚刚分配的虚拟内存。
//
RegionSize = 0; // 所释放虚拟内存的大小必须赋值为 0
MmFreeVirtualMemory(&BaseAddress, &RegionSize, MEM_RELEASE, TRUE);
//
// 输出释放的的虚拟内存的基址和大小
//
OutputFormat = "Free VM's base address: 0x%X. Size: 0x%X.\n\n";
fprintf(StdHandle, OutputFormat, BaseAddress, RegionSize);
//
// 遍历 VAD 链表,输出所有 VAD 的起始页框号,结束页框号和包含的虚拟页框数量
//
Index = AllocatedVpnCount = 0;
for(pListEntry = pVadList->VadListHead.Next;
pListEntry != &pVadList->VadListHead;
pListEntry = pListEntry->Next) {
Index++;
pVad = CONTAINING_RECORD(pListEntry, MMVAD, VadListEntry);
VpnCount = pVad->EndVpn - pVad->StartingVpn + 1;
OutputFormat = "%d# Vad Include %d Vpn From %d to %d. (0x%X - 0x%X)\n";
fprintf(StdHandle, OutputFormat,
Index, VpnCount, pVad->StartingVpn, pVad->EndVpn,
pVad->StartingVpn * PAGE_SIZE, (pVad->EndVpn + 1) * PAGE_SIZE - 1);
AllocatedVpnCount += VpnCount;
}
//
// 统计已分配的虚拟页框和未分配的虚拟页框
//
OutputFormat = "\nAllocated Vpn Count: %d.\n";
fprintf(StdHandle, OutputFormat, AllocatedVpnCount);
FreeVpnCount = TotalVpnCount - AllocatedVpnCount;
OutputFormat = "Free Vpn Count: %d.\n\n";
fprintf(StdHandle, OutputFormat, FreeVpnCount);
//
// 输出物理页的零页数量和空闲页数量
//
OutputFormat = "Zeroed Physical Page Count: %d.\n";
fprintf(StdHandle, OutputFormat, MiZeroedPageCount);
OutputFormat = "Free Physical Page Count: %d.\n\n";
fprintf(StdHandle, OutputFormat, MiFreePageCount);
VM_RETURN:
KeEnableInterrupts(IntState); // 开中断
ObDerefObject(pProcCtrlBlock);
}
/*
/*
提供该示例代码是为了阐释一个概念,或者进行一个测试,并不代表着
最安全的编码实践,因此不应在应用程序或网站中使用该示例代码。对
于超出本示例代码的预期用途以外的使用所造成的偶然或继发性损失,
北京英真时代科技有限公司不承担任何责任。
*/
ULONG PfnArray[2];
//
// 访问未映射物理内存的虚拟地址会触发异常。
// 必须注释或者删除该行代码才能执行后面的代码。
//
*((PINT)0xE0000000) = 100;
//
// 从内核申请两个未用的物理页。
// 由 PfnArray 数组返回两个物理页的页框号。
//
MiAllocateZeroedPages(2, PfnArray);
OutputFormat = "New page frame number: 0x%X, 0x%X\n";
fprintf(StdHandle, OutputFormat, PfnArray[0], PfnArray[1]);
//
// 使用 PfnArray[0] 页做为页表,映射基址为 0xE00000000 的 4M 虚拟地址。
//
IndexOfDirEntry = (0xE0000000 >> 22); // 虚拟地址的高 10 位是 PDE 标号
((PMMPTE_HARDWARE)0xC0300000)[IndexOfDirEntry].PageFrameNumber = PfnArray[0];
((PMMPTE_HARDWARE)0xC0300000)[IndexOfDirEntry].Valid = 1; // 有效
((PMMPTE_HARDWARE)0xC0300000)[IndexOfDirEntry].Writable = 1; // 可写
MiFlushEntireTlb(); // 刷新快表
//
// 根据 PDE 的标号计算其映射的页表所在虚拟地址的基址
//
PageTableBase = 0xC0000000 + IndexOfDirEntry * PAGE_SIZE;
//
// 将 PfnArray[1] 放入页表 PfnArray[0] 的两个 PTE 中,
// 分别映射基址为 0xE0000000 和 0xE0001000 的 4K 虚拟地址
//
IndexOfTableEntry = (0xE0000000 >> 12) & 0x3FF; // 虚拟地址的 12-22 位是 PTE 标号
((PMMPTE_HARDWARE)PageTableBase)[IndexOfTableEntry].PageFrameNumber = PfnArray[1];
((PMMPTE_HARDWARE)PageTableBase)[IndexOfTableEntry].Valid = 1; // 有效
((PMMPTE_HARDWARE)PageTableBase)[IndexOfTableEntry].Writable = 1; // 可写
MiFlushEntireTlb(); // 刷新快表
IndexOfTableEntry = (0xE0001000 >> 12) & 0x3FF; // 虚拟地址的 12-22 位是 PTE 标号
((PMMPTE_HARDWARE)PageTableBase)[IndexOfTableEntry].PageFrameNumber = PfnArray[1];
((PMMPTE_HARDWARE)PageTableBase)[IndexOfTableEntry].Valid = 1; // 有效
((PMMPTE_HARDWARE)PageTableBase)[IndexOfTableEntry].Writable = 1; // 可写
MiFlushEntireTlb(); // 刷新快表
//
// 测试
//
OutputFormat = "Read Memory 0xE0001000: %d\n";
fprintf(StdHandle, OutputFormat, *((PINT)0xE0001000));
*((PINT)0xE0000000) = 100; // 写共享内存
fprintf(StdHandle, OutputFormat, *((PINT)0xE0001000));
;
;
; 提供该示例代码是为了阐释一个概念,或者进行一个测试,并不代表着
; 最安全的编码实践,因此不应在应用程序或网站中使用该示例代码。对
; 于超出本示例代码的预期用途以外的使用所造成的偶然或继发性损失,
; 北京英真时代科技有限公司不承担任何责任。
;
global _getcr3 ; 将标号声明为全局的,使其可在外部被引用
[section .text] ; 代码段
;
; C 语言函数原型: ULONG getcr3()
;
_getcr3:
;{
push ebp
mov ebp, esp
mov eax, cr3 ; 将 CR3 寄存器中的值复制到 EAX 寄存器中。
; 根据 C 与汇编的函数调用约定,EAX 寄存器中的值做为函数的返回值。
leave
ret
;}
/*
/*
提供该示例代码是为了阐释一个概念,或者进行一个测试,并不代表着
最安全的编码实践,因此不应在应用程序或网站中使用该示例代码。对
于超出本示例代码的预期用途以外的使用所造成的偶然或继发性损失,
北京英真时代科技有限公司不承担任何责任。
*/
#include "EOSApp.h"
/*
二级页表映射机制将物理内存分为 4K 大小的页,每页对应一个
页框号(PFN: Page Frame Number),物理页 0x0-0x0FFF 对应
的 PFN 为 0,0x1000-0x1FFF 对应的 PFN 为 1,依此类推。所
以,将 PFN 左移 12 位可以获得物理页的基址。
CR3 寄存器在其高 20 位中保存了页目录(Page Directory)的
页框号。低 12 位保留未用。
31 12 11 0
+-----------------------+------------+
CR3 | PFN of Page Direcotry | Reserved |
+-----------------------+------------+
*/
#define CR3_SHIFT 12 // CR3 寄存器的值右移 12 位获得页目录的页框号
/*
二级页表映射机制中的页目录和页表在进程的 4G 虚拟地址空间中的
位置如下图
进程的 4G 虚拟地址空间
----------+-----------------------+
0x00000000| |
| |
| |
用户地址 | |
空间 | |
(低 2G)| |
| |
| |
| |
| |
----------+-----------------------+
0x80000000| |
+-----------------------+------------
| |0xC0000000
| |
内核地址 | |
空间 +-----------------------+ 1024 个页表(占用从
(高 2G)| 一个页目录(占用从 | 0xC0000000 起的 4M)
| 0xC0300000 起的 4K) |
+-----------------------+
| |
+-----------------------+------------
0xFFFFFFFF| |
----------+-----------------------+
*/
#define PDE_BASE ((ULONG_PTR)0xC0300000) // 页目录在虚拟地址空间的基址
#define PTE_BASE ((ULONG_PTR)0xC0000000) // 页表在虚拟地址空间的基址
#define PTE_SIZE 0x4 // 页目录项和页表项都是 4 字节
#define PTE_PER_TABLE 0x400 // 页目录中有 1024 个 PDE,页表中有 1024 个 PTE
#define PAGE_SIZE 0x1000 // 物理页、页目录、页表的大小都是 4096 字节
#define PDI_SHIFT 22 // PDE 的标号左移 22 位获得虚拟地址的高 10 位
#define PTI_SHIFT 12 // PTE 的标号左移 12 位获得虚拟地址的 22-12 位
/*
页目录项(PDE: Page Directory Entry)和页表项(PTE: Page Table Entry)
都是 4 个字节,各个位(只列出该程序关心的)的功能可以参考下图
31 12 11 1 0
+----------------------+----------+-+
PDE/PTE | PFN | |P|
+----------------------+----------+-+
第 0 位为 0 时表示该项无效,为 1 时表示有效。高 20 位是 PDE/PTE 映射的
页框号。
*/
typedef struct _MMPTE_HARDWARE
{
ULONG Valid : 1; // 存在位 0
ULONG DoNotCare : 11; // 不关心这些位 1-11
ULONG PageFrameNumber : 20; // 页框号 12-31
}MMPTE_HARDWARE, *PMMPTE_HARDWARE;
ULONG getcr3(); // 声明在汇编文件中实现的函数,使其可以在下面被调用。
int main(int argc, char* argv[])
{
//
// 启动调试 EOS 应用程序前要特别注意下面的问题:
//
// 1、如果要在调试应用程序时能够调试进入内核并显示对应的源码,
// 必须使用 EOS 核心项目编译生成完全版本的 SDK 文件夹,然
// 后使用此文件夹覆盖应用程序项目中的 SDK 文件夹,并且 EOS
// 核心项目在磁盘上的位置不能改变。
//
ULONG PfnOfPageDirectory;
ULONG PageTotal = 0;
ULONG IndexOfDirEntry;
ULONG IndexOfTableEntry;
PMMPTE_HARDWARE pPde;
PMMPTE_HARDWARE pPte;
ULONG_PTR PageTableBase;
ULONG_PTR VirtualBase;
const char* OutputFormat = NULL;
// Sleep(10000); // 等待 10 秒
__asm("cli"); // 关中断
//
// 输出 CR3 中页目录的页框号
//
OutputFormat = "\nCR3->0x%X\n";
PfnOfPageDirectory = (getcr3() >> CR3_SHIFT);
printf(OutputFormat, PfnOfPageDirectory);
//
// 第一层循环,遍历页目录中的 PDE
//
for(IndexOfDirEntry = 0; IndexOfDirEntry < PTE_PER_TABLE; IndexOfDirEntry++)
{
pPde = (PMMPTE_HARDWARE)(PDE_BASE + IndexOfDirEntry * PTE_SIZE);
//
// 跳过无效的 PDE
//
if(!pPde->Valid)
continue;
//
// 输出 PDE 信息,格式如下:
// PDE: 标号 (映射的 4M 虚拟地址的基址)->所映射页表的页框号
//
OutputFormat = "PDE: 0x%X (0x%X)->0x%X\n";
VirtualBase = (IndexOfDirEntry << PDI_SHIFT);
printf(OutputFormat, IndexOfDirEntry, VirtualBase, pPde->PageFrameNumber);
//
// 根据 PDE 的标号计算其映射的页表所在虚拟地址的基址
//
PageTableBase = PTE_BASE + IndexOfDirEntry * PAGE_SIZE;
//
// 第二层循环,遍历页表中的 PTE
//
for(IndexOfTableEntry = 0; IndexOfTableEntry < PTE_PER_TABLE; IndexOfTableEntry++)
{
pPte = (PMMPTE_HARDWARE)(PageTableBase + IndexOfTableEntry * PTE_SIZE);
//
// 跳过无效的 PTE
//
if(!pPte->Valid)
continue;
//
// 输出 PTE 信息,格式如下:
// PTE: 标号 (映射的 4K 虚拟地址的基址)->所映射物理页的页框号
//
OutputFormat = "\t\tPTE: 0x%X (0x%X)->0x%X\n";
VirtualBase = (IndexOfDirEntry << PDI_SHIFT) | (IndexOfTableEntry << PTI_SHIFT);
printf(OutputFormat, IndexOfTableEntry, VirtualBase, pPte->PageFrameNumber);
//
// 统计占用的物理页数
//
PageTotal++;
} // 第二层循环结束
} // 第一层循环结束
//
// 输出占用的物理页数,和物理内存数
//
OutputFormat = "\nPhysical Page Total: %d\n";
printf(OutputFormat, PageTotal);
OutputFormat = "Physical Memory Total: %d\n\n";
printf(OutputFormat, PageTotal * PAGE_SIZE);
__asm("sti"); // 开中断
// Sleep(60000); // 等待 60 秒
return 0;
}
#include <stdio.h>
#include <windows.h>
#define MAX_SIZE 1000
#define ALLOC_MIN_SIZE 10//最小分配空间大小.
#define RED FOREGROUND_RED
#define GREEN FOREGROUND_GREEN
#define BLUE FOREGROUND_BLUE
typedef struct Bound{
union {
struct Bound * preLink;//头部域前驱
struct Bound * upLink;//尾部域,指向结点头部
};
int tag;//0标示空闲,1表示占用
int size;//仅仅表示 可用空间,不包括 头部 和 尾部空间
struct Bound * nextLink;//头部后继指针.
}*Space;
#define FOOT_LOC(p) ((p)+(p->size)-1)//尾部域位置
void initSpace(Space * freeSpace,Space * pav){
//有2个空间是为了 查找空间的邻接点,防止出界用的。
*freeSpace = (Space)malloc((MAX_SIZE+2)*sizeof(struct Bound));
Space head = *freeSpace;
head->tag = 1;//设置边界已占用
head++;//指向第一个节点..
head->tag = 0;//设置节点空闲.
head->preLink = head->nextLink = head;//循环双链表..
head->size = MAX_SIZE;
*pav = head;//设置头指针
Space foot = FOOT_LOC(head);
foot->tag = 0;
foot->upLink = head;
foot++;
foot->tag = 1;//设置 边界 已占用
}
Space userSpace[MAX_SIZE] = {NULL};//用户空间数组.
int usCount = 0;
Space allocBoundTag(Space * pav,int size){
Space p = * pav;
for (;p != NULL && p->size < size && p->nextLink != *pav ; p = p->nextLink) ;
if (p == NULL || p->size < size ){
return NULL;
}
*pav = p->nextLink;
if (p->size - size > ALLOC_MIN_SIZE){//从高位截取p,不破坏指针间的关系.
p->size -= size;
Space foot = FOOT_LOC(p);
foot->upLink = p;
foot->tag = 0;
p = foot + 1;
p->size = size;
foot = FOOT_LOC(p);
p->tag = foot->tag = 1;
foot->upLink = p;
}
else{//分配后剩余空间小于 ALLOC_MIN_SIZE
if (p = *pav){//只剩下一个空间了,清空指针
*pav = NULL;
p->tag = 1;
}
else{//直接分配 p->size个空间出去
Space foot = FOOT_LOC(p);
foot->tag =p->tag = 1;
p->preLink->nextLink = p->nextLink;
p->nextLink->preLink = p->preLink;
}
}
userSpace[usCount] = p;
usCount++;
return p;
}
//回收空间,合并 邻接空闲空间.
void reclaimBoundTag(Space * pav,Space sp){
Space pre = NULL;//前一个空间
Space next = NULL;//后一个空间..
Space foot = NULL;
int pTag = -1;
int nTag = -1;
int i = 0;
if(*pav != NULL)
{
pre = (sp -1)->upLink;//前一个空间
pTag = pre->tag;
next = sp + sp->size;//后一个空间..
nTag = next->tag;
}
if ((*pav != NULL && pTag == 1 && nTag == 1) || *pav == NULL){//前后都被占用,直接插入在表头.
Space foot = FOOT_LOC(sp);
foot->tag = sp->tag = 0;
if (*pav == NULL){
*pav = sp->preLink = sp->nextLink = sp;
}
else{
sp->nextLink = *pav;
sp->preLink = (*pav)->preLink;
(*pav)->preLink = sp;
sp->preLink->nextLink = sp;
*pav = sp;//将头指针指向刚释放的空间
}
}
else if(pTag == 0 && nTag == 1){//前面的可以合并..
pre->size += sp->size;
foot = FOOT_LOC(pre);
foot->tag = 0;
foot->upLink = pre;
}
else if(pTag == 1 && nTag == 0){//后面的可以合并
if(*pav == next)
{
*pav = sp;
}
sp->preLink = next->preLink;
sp->nextLink = next->nextLink;
next->preLink->nextLink = sp;
next->nextLink->preLink = sp;
sp->size += next->size;
foot = FOOT_LOC(sp);
sp->tag = foot->tag = 0;
foot->upLink = sp;
}
else{//前后都可以合并
if(*pav == next)
{
*pav = pre;
}
pre->size += sp->size + next->size;
pre->nextLink = next->nextLink;
next->nextLink->preLink = pre;
foot = FOOT_LOC(pre);
foot->upLink = pre;
}
//设置用户空间
for (i = 0; i < usCount; i++){
if (sp == userSpace[i]){
userSpace[i] = NULL;
}
}
}
/* 设置字体颜色 */
void SetColor(int color)
{
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),
FOREGROUND_INTENSITY | color);
}
void print(Space s){
printf("0x%0x %6d\t%10d 0x%0x 0x%0x\n",s,s->size,s->tag, s->preLink,s->nextLink);
}
void printSpace(Space pav){
SetColor(RED|GREEN|BLUE);
printf("空间首地址 空间大小 块标志(0:空闲,1:占用) 前驱地址 后继地址\n");
SetColor(GREEN);
int i = 0;
Space p = NULL, us = NULL;
if (pav != NULL)
{
p = pav;
print(p);
for (p = p->nextLink; p != pav; p = p->nextLink){
print(p);
i++;
}
}
for (i = 0; i < usCount; i++){
us = userSpace[i];
if (us){
printf("0x%0x %6d\t%10d\t\n",us, us->size, us->tag);
}
}
}
int main(int argc, char* argv[])
{
Space freeSpace = NULL,pav = NULL;
initSpace(&freeSpace,&pav);
int item = 0, i = 0;
unsigned long start = 0;
unsigned long joblength;
Space us = NULL;
while(1)
{
SetColor(RED|BLUE|GREEN);
printf("选择功能项:(0-退出 1-分配内存 2-回收内存 3-显示内存):");
scanf("%d",&item);
switch(item)
{
case 0:
exit(0);
case 1:
SetColor(RED|GREEN);
printf("所需内存长度:");
scanf("%*c%ld",&joblength);
allocBoundTag(&pav,joblength);
break;
case 2:
SetColor(RED|BLUE);
printf("输入要回收分区的首地址:");
scanf("%x",&start);
for (i = 0; i < usCount; i++){
us = userSpace[i];
if ((unsigned long)us == start){
reclaimBoundTag(&pav, us);
break;
}
}
if(i == usCount)
{
SetColor(RED);
printf("输入要回收分区的首地址不符合要求\n");
}
if(pav->size == MAX_SIZE)
{
usCount = 0;
}
break;
case 3:
printSpace(pav);
break;
default:
printf("没有该选项\n");
}
}
return 0;
}
\ No newline at end of file
#include <stdio.h>
#include <math.h>
#include <windows.h>
#define RED FOREGROUND_RED
#define GREEN FOREGROUND_GREEN
#define BLUE FOREGROUND_BLUE
#define M 10 /* 可利用空间总容量(2的幂次),子表的个数为M+1 */
#define N 100 /* 占用块个数的最大值 */
//伙伴系统可利用空间表的结构
typedef struct _Node{
struct _Node *llink; //指向前驱节点
int bflag; //块标志,0:空闲,1:占用
int bsize; //块大小,值为2的幂次k
struct _Node *rlink; //头部域,指向后继节点
}Node;
//可利用空间表的头结点
typedef struct HeadNode{
int nodesize; //链表的空闲块大小
Node *first; //链表的表头指针
}FreeList[M+1];
Node* start; // 全局变量start为整个生成空间的首地址
/* avail[0...M]为可利用空间表,n为申请分配量。若有不小于n的空闲块,
则分配相应的存储块,并返回首地址;否则,返回NULL */
Node* AllocBuddy(FreeList *avail, unsigned long n)
{
int i, k;
Node *pa, *pi, *pre, *suc;
//查找满足分配要求的子表即空闲块大小大于n的表
for(k = 0; k <= M && ((*avail)[k].nodesize <= n || !(*avail)[k].first); ++k)
;
if(k>M) // 分配失败返回NULL
{
printf("内存分配失败!\n");
return NULL;
}
else{ //进行分配
pa = (*avail)[k].first; //指向可分配表的第一个节点
pre = pa->llink; //分别指向前驱和后继
suc = pa->rlink;
if(pa == suc) //分配后该子表变成空表
(*avail)[k].first = NULL;
else{ //从子表删去*pa节点
pre->rlink = suc;
suc->llink = pre;
(*avail)[k].first = suc;
}
/* 将剩余块插入相应子表 */
for(i = 1; (*avail)[k-i].nodesize >= n+1; ++i)
{
pi = pa + (int)pow(2,k-i);
pi->rlink = pi;
pi->llink = pi;
pi->bflag = 0;
pi->bsize = k-i;
(*avail)[k-i].first = pi;
}
pa->bflag = 1;
pa->bsize = k - (--i);
}
return pa;
}
//返回相对起始地址为p,块大小为pow(2,k)的块的伙伴地址
Node* buddy(Node* n)
{
if((n-start)%(int)pow(2,n->bsize+1)==0) //p为前块
return n + (int)pow(2,n->bsize);
else //p为后块
return n - (int)pow(2,n->bsize);
}
// 伙伴系统的回收算法 将p所指的释放块回收到可利用空间表pav中
void Reclaim(FreeList *pav,Node* *p)
{
//
// 此处代TODO: 在此添加代码
//
}
/* 设置字体颜色 */
void SetColor(int color)
{
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),
FOREGROUND_INTENSITY | color);
}
//输出所有可用空间表
void print_free(FreeList p)
{
int i;
Node* head;
//设置字体颜色为白色
SetColor(RED|BLUE|GREEN);
printf("可利用空间:\n");
printf(" 块的大小 块的首地址\t块标志(0:空闲 1:占用) 前驱地址 后继地址\n");
SetColor(GREEN);
for(i = 0; i <= M; i++)
{
if(p[i].first) //第i个可利用空间表不同
{
head = p[i].first; //head指向链表的第一个节点的头部域(首地址)
do
{
printf("\t%d\t 0x%x\t %10d 0x%x 0x%x\n",(int)pow(2,head->bsize), head, head->bflag, head->llink, head->rlink);
head = head->rlink;
}while(head != p[i].first);
}
}
printf("\n");
}
// 输出p数组所指的已分配空间
void print_used(Node* p[])
{
int i;
//设置字体颜色为白色
SetColor(RED|BLUE|GREEN);
printf("已利用空间:\n");
printf(" 占用块块号\t占用块的首地址\t块大小\t块标志(0:空闲 1:占用)\n");
SetColor(RED);
for(i = 0; i < N; i++)
if(p[i]) // 指针不为0(指向一个占用块)
printf("\t %d\t 0x%x\t %d\t %d\n",i, p[i],(int)pow(2,p[i]->bsize), p[i]->bflag);
printf("\n");
}
int main(int argc, char* argv[])
{
/* 注意:在应用程序中不能使用断点等调试功能 */
int i, j, item;
unsigned long joblength;
FreeList avail;
Node* used_block[N] = {NULL}; //used_block数组为占用块的首地址
//初始化可利用空间
for(i = 0; i <= M; i++)
{
avail[i].nodesize = (int)pow(2,i);
avail[i].first = NULL;
}
// 在最大链表中生成一个结点
start = avail[M].first = (Node*)malloc(avail[M].nodesize * sizeof(Node));
if(start) // 生成结点成功
{
start->llink = start->rlink = start; // 初始化该结点
start->bflag = 0;
start->bsize = M;
int color = 8;
i = 0;
while(1)
{
//设置字体颜色为白色
SetColor(RED|BLUE|GREEN);
printf("选择功能项:(0-退出 1-分配主存 2-回收主存 3-显示主存):");
scanf("%d",&item);
switch(item)
{
case 0:
exit(0);
case 1:
SetColor(RED|GREEN);
printf("输入作业所需长度:");
scanf("%ld",&joblength);
if(avail[M].first && (int)pow(2, avail[M].first->bsize) == 1024)
{
i = 0;
}
used_block[i] = AllocBuddy(&avail,joblength);
++i;
break;
case 2:
SetColor(RED|BLUE);
printf("输入要回收块的块号:");
scanf("%d",&j);
if(i > 0 && j < i)
{
Reclaim(&avail,&used_block[j]);
}
else
{
SetColor(RED);
if(i == 0)
{
printf("没有可回收的内存块,请分配后,再进行回收!\n");
}
else
{
printf("输入的块号不合法\n");
}
}
break;
case 3:
print_free(avail);
print_used(used_block);
break;
default:
printf("没有该选项\n");
}
}
}
}
#include <stdio.h>
#include <stdio.h>
#include <stdlib.h>
//输出内存块页面序号
int OutputBlockofMemory(int *BlockofMemory, int BlockCount, int ReplacePage, int PageNum)
{
int i;
printf("访问页面 %d 后,", PageNum);
printf("内存中的页面号为:\t");
for(i = 0; i < BlockCount; i++)
{
if(BlockofMemory[i] < 0)
printf("# ");
else
printf("%d ", BlockofMemory[i]);
}
if(ReplacePage != -1)
printf("\t淘汰页面号为:%d", ReplacePage);
printf("\n");
return -1;
}
//输出页面引用串号
void OutputPageNumofRef(int* PageNumofRef, int PageNumRefCount)
{
int i = 0;
printf("页面引用串为:\t");
for(i = 0; i < PageNumRefCount; i++)
printf("%d ", PageNumofRef[i]);
printf("\n");
}
//内存块页面号清零
void ResetBlockofMemory(int *BlockofMemory, int BlockCount)
{
int i;
for(i = 0; i < BlockCount; i++)
BlockofMemory[i] = -1;
}
//判断页是否在内存中,如果页在内存中,返回1,否则返回0;
int PageInBlockofMemory(int PageNum, int *BlockofMemory, int BlockCount)
{
int i;
for(i = 0; i < BlockCount; i++)
if(PageNum == BlockofMemory[i])
return 1;
return 0;
}
//下次访问次序
//参数j: 页面在内存块中的位置
//参数i: 页面号在页面号引用串中的位置
int DistanceOpt(int *BlockofMemory, int *PageNumofRef, int j, int i, int PageNumRefCount)
{
int k;
for(k = i + 1; k < PageNumRefCount; k++)
if(BlockofMemory[j] == PageNumofRef[k])
return k;
return PageNumRefCount;
}
//最佳页面置换算法
void Opt(int *BlockofMemory, int *PageNumofRef, int BlockCount, int PageNumRefCount)
{
int i, j, k;
int MaxIndex1, MaxIndex2;
int MissCount = 0;
int ReplacePage;
int EmptyBlockCount = BlockCount;
printf("**********最佳页面置换算法:**********\n");
//输出页面引用串号
OutputPageNumofRef(PageNumofRef, PageNumRefCount);
for(i = 0; i < PageNumRefCount; i++)
{
if(!PageInBlockofMemory(PageNumofRef[i], BlockofMemory, BlockCount)) //页不在内存中
{
MissCount++;
if(EmptyBlockCount > 0)
{
BlockofMemory[BlockCount - EmptyBlockCount] = PageNumofRef[i];
OutputBlockofMemory(BlockofMemory, BlockCount, -1, PageNumofRef[i]);
EmptyBlockCount--;
}
else
{
MaxIndex1 = MaxIndex2 = 0;
//求出未来最长时间不被访问的页
for(j = 0; j < BlockCount; j++)
{
MaxIndex2 = DistanceOpt(BlockofMemory, PageNumofRef, j, i, PageNumRefCount);
if(MaxIndex1 < MaxIndex2)
{
MaxIndex1 = MaxIndex2;
k = j;
}
}
ReplacePage = BlockofMemory[k];
BlockofMemory[k] = PageNumofRef[i];
OutputBlockofMemory(BlockofMemory, BlockCount, ReplacePage, PageNumofRef[i]);
}
}
else
{
OutputBlockofMemory(BlockofMemory,BlockCount, -1, PageNumofRef[i]);
}
}
printf("缺页次数为: %d\n", MissCount);
printf("OPT缺页率为: %.3f\n", (float)MissCount / PageNumRefCount);
}
//先进先出页面置换算法
void Fifo(int *BlockofMemory,int *PageNumofRef,int BlockCount,int PageNumRefCount)
{
int i;
int ReplacePage;
int ReplaceIndex = 0;
int MissCount = 0;
int EmptyBlockCount = BlockCount;
printf("**********先进先出页面置换算法:**********\n");
//输出页面引用串号
OutputPageNumofRef(PageNumofRef,PageNumRefCount);
for(i = 0; i < PageNumRefCount; i++)
{
if(!PageInBlockofMemory(PageNumofRef[i], BlockofMemory, BlockCount)) //页不在内存中
{
MissCount++;
if(EmptyBlockCount > 0)
{
BlockofMemory[BlockCount - EmptyBlockCount] = PageNumofRef[i];
OutputBlockofMemory(BlockofMemory, BlockCount, -1, PageNumofRef[i]);
EmptyBlockCount--;
}
else
{
ReplacePage = BlockofMemory[ReplaceIndex];
BlockofMemory[ReplaceIndex] = PageNumofRef[i];
ReplaceIndex = (ReplaceIndex + 1) % BlockCount;
OutputBlockofMemory(BlockofMemory, BlockCount, ReplacePage, PageNumofRef[i]);
}
}
else
OutputBlockofMemory(BlockofMemory, BlockCount, -1, PageNumofRef[i]);
}
printf("缺页次数为:%d\n", MissCount);
printf("FIFO缺页率为:%.3f\n", (float)MissCount / PageNumRefCount);
}
int main()
{
int *BlockofMemory; //内存物理块
const int BlockCount = 5;
int PageNumofRef[] = {7,0,1,2,0,3,0,4,2,3,0,1,1,7,0,1,0,3}; //页面号引用串
int PageNumRefCount = sizeof(PageNumofRef) / sizeof(PageNumofRef[0]);
BlockofMemory = (int*)malloc(BlockCount * sizeof(int));
if(BlockofMemory == (int*)NULL)
{
printf("内存分配出错\n");
exit(1);
}
ResetBlockofMemory(BlockofMemory, BlockCount);
Opt(BlockofMemory, PageNumofRef, BlockCount, PageNumRefCount);
ResetBlockofMemory(BlockofMemory,BlockCount);
Fifo(BlockofMemory, PageNumofRef, BlockCount, PageNumRefCount);
free(BlockofMemory);
return 0;
}
//最近最久未使用页面置换算法
//最近最久未使用页面置换算法
void Lru(int *BlockofMemory, int *PageNumofRef, int BlockCount, int PageNumRefCount)
{
int i;
int MissCount = 0;
printf("************最近最久未使用页面置换算法:************\n");
//输出页面引用串号
OutputPageNumofRef(PageNumofRef, PageNumRefCount);
for(i = 0; i < PageNumRefCount; i++)
{
if(!PageInBlockofMemory(PageNumofRef[i], BlockofMemory, BlockCount)) //页不在内存中
{
MissCount++;
//
// 在此添加代码,实现 LRU 页面置换算法
//
}
else
OutputBlockofMemory(BlockofMemory, BlockCount, -1, PageNumofRef[i]);
}
printf("缺页次数为:%d\n", MissCount);
printf("LRU缺页率为:%.3f\n", (float)MissCount / PageNumRefCount);
}
/*
/*
提供该示例代码是为了阐释一个概念,或者进行一个测试,并不代表着
最安全的编码实践,因此不应在应用程序或网站中使用该示例代码。对
于超出本示例代码的预期用途以外的使用所造成的偶然或继发性损失,
北京英真时代科技有限公司不承担任何责任。
*/
#include "EOSApp.h"
int main(int argc, char* argv[])
{
//
// 启动调试 EOS 应用程序前要特别注意下面的问题:
//
// 1、如果要在调试应用程序时能够调试进入内核并显示对应的源码,
// 必须使用 EOS 核心项目编译生成完全版本的 SDK 文件夹,然
// 后使用此文件夹覆盖应用程序项目中的 SDK 文件夹,并且 EOS
// 核心项目在磁盘上的位置不能改变。
//
static char Buffer[512]; // EOS 的栈空间有限,使用 static 关键字就不从栈上分配内存了。
int c;
HANDLE hCom1;
ULONG nLength;
ULONG nResult;
printf("This program is used to test serial port, and it's used with SerialChat.exe, make sure SerialChat.exe is running on Windows.\n");
//
// 以可读、可写的方式打开串口设备 COM1
//
hCom1 = CreateFile( "COM1",
GENERIC_READ | GENERIC_WRITE,
0,
OPEN_EXISTING,
0 );
if (INVALID_HANDLE_VALUE == hCom1) {
printf("CreateFile error:%d\n", GetLastError());
return 1;
}
for (;;) {
//
// 读取从控制台输入的字符串。
//
printf(">>");
gets(Buffer);
nLength = strlen(Buffer);
//
// 将从控制台输入的字符串发送到串口设备(字符串结束符'\0'也发送)。
//
if (!WriteFile(hCom1, Buffer, nLength + 1, &nResult)) {
printf("WriteFile error:%d\n", GetLastError());
break;
}
//
// 如果输入的是“exit”则退出程序。
//
if (0 == stricmp(Buffer, "exit")) {
break;
}
//
// 从串口设备逐个接收字符并显示到控制台,直到收到字符串结束符号'\0'为止。
//
printf("<<");
for (;;) {
if (!ReadFile(hCom1, Buffer, 1, &nResult)) {
printf("ReadFile error:%d\n", GetLastError());
goto RETURN;
}
if ('\0' == *Buffer) {
putchar('\n');
break;
}
putchar(*Buffer);
}
}
RETURN:
//
// 关闭串口设备 COM1
//
CloseHandle(hCom1);
return 0;
}
#include <windows.h>
#include <windows.h>
#include <stdio.h>
#include <tchar.h>
#define BUFSIZE 512
DWORD WINAPI InstanceThread(void*);
VOID GetAnswerToRequest(char*, LPDWORD);
int main(VOID)
{
BOOL fConnected = FALSE;
DWORD dwThreadId = 0;
HANDLE hPipe = INVALID_HANDLE_VALUE, hThread = NULL;
LPTSTR lpszPipename = TEXT("\\\\.\\pipe\\engintime.oslab.com1");
// The main loop creates an instance of the named pipe and
// then waits for a client to connect to it. When the client
// connects, a thread is created to handle communications
// with that client, and this loop is free to wait for the
// next client connect request. It is an infinite loop.
_tprintf( TEXT("\n必须先启动本应用程序,然后再启动OS Lab调试\nSerialChat: awaiting client connection on %s\n"), lpszPipename);
hPipe = CreateNamedPipe(
lpszPipename, // pipe name
PIPE_ACCESS_DUPLEX, // read/write access
PIPE_TYPE_MESSAGE | // message type pipe
PIPE_READMODE_MESSAGE | // message-read mode
PIPE_WAIT, // blocking mode
PIPE_UNLIMITED_INSTANCES, // max. instances
BUFSIZE, // output buffer size
BUFSIZE, // input buffer size
0, // client time-out
NULL); // default security attribute
if (hPipe == INVALID_HANDLE_VALUE)
{
_tprintf(TEXT("CreateNamedPipe failed, GLE=%d.\n"), GetLastError());
return -1;
}
// Wait for the client to connect; if it succeeds,
// the function returns a nonzero value. If the function
// returns zero, GetLastError returns ERROR_PIPE_CONNECTED.
fConnected = ConnectNamedPipe(hPipe, NULL) ?
TRUE : (GetLastError() == ERROR_PIPE_CONNECTED);
if (fConnected)
{
printf("Client connected success.\n");
// Create a thread for this client.
hThread = CreateThread(
NULL, // no security attribute
0, // default stack size
InstanceThread, // thread proc
(LPVOID) hPipe, // thread parameter
0, // not suspended
&dwThreadId); // returns thread ID
if (hThread == NULL)
{
_tprintf(TEXT("CreateThread failed, GLE=%d.\n"), GetLastError());
return -1;
}
else CloseHandle(hThread);
}
else
// The client could not connect, so close the pipe.
CloseHandle(hPipe);
while(1);
return 0;
}
DWORD WINAPI InstanceThread(void* lpvParam)
// This routine is a thread processing function to read from and reply to a client
// via the open pipe connection passed from the main loop. Note this allows
// the main loop to continue executing, potentially creating more threads of
// of this procedure to run concurrently, depending on the number of incoming
// client connections.
{
HANDLE hHeap = GetProcessHeap();
char* pchRequest = (char*)HeapAlloc(hHeap, 0, BUFSIZE*sizeof(char));
char* pchReply = (char*)HeapAlloc(hHeap, 0, BUFSIZE*sizeof(char));
DWORD cbBytesRead = 0, cbReplyBytes = 0, cbWritten = 0;
BOOL fSuccess = FALSE;
HANDLE hPipe = NULL;
// Do some extra error checking since the app will keep running even if this
// thread fails.
if (lpvParam == NULL)
{
printf( "\nERROR - Pipe Server Failure:\n");
printf( " InstanceThread got an unexpected NULL value in lpvParam.\n");
printf( " InstanceThread exitting.\n");
if (pchReply != NULL) HeapFree(hHeap, 0, pchReply);
if (pchRequest != NULL) HeapFree(hHeap, 0, pchRequest);
return (DWORD)-1;
}
if (pchRequest == NULL)
{
printf( "\nERROR - Pipe Server Failure:\n");
printf( " InstanceThread got an unexpected NULL heap allocation.\n");
printf( " InstanceThread exitting.\n");
if (pchReply != NULL) HeapFree(hHeap, 0, pchReply);
return (DWORD)-1;
}
if (pchReply == NULL)
{
printf( "\nERROR - Pipe Server Failure:\n");
printf( " InstanceThread got an unexpected NULL heap allocation.\n");
printf( " InstanceThread exitting.\n");
if (pchRequest != NULL) HeapFree(hHeap, 0, pchRequest);
return (DWORD)-1;
}
// Print verbose messages. In production code, this should be for debugging only.
printf("Now, receiving and processing messages.\n");
// The thread's parameter is a handle to a pipe object instance.
hPipe = (HANDLE) lpvParam;
// Loop until done reading
while (1)
{
// Read client requests from the pipe. This simplistic code only allows messages
// up to BUFSIZE characters in length.
ZeroMemory(pchRequest,BUFSIZE*sizeof(char));
printf("<<");
do{
fSuccess = ReadFile(
hPipe, // handle to pipe
pchRequest, // buffer to receive data
BUFSIZE*sizeof(char), // size of buffer
&cbBytesRead, // number of bytes read
NULL); // not overlapped I/O
if (!fSuccess || cbBytesRead == 0)
{
if (GetLastError() == ERROR_BROKEN_PIPE)
{
_tprintf(TEXT("InstanceThread: client disconnected.\n"), GetLastError());
}
else
{
_tprintf(TEXT("InstanceThread ReadFile failed, GLE=%d.\n"), GetLastError());
}
break;
}
printf( "%c", pchRequest[0]);
if ('\0' == *(pchRequest)) {
break;
}
}while(TRUE);
// Process the incoming message.
GetAnswerToRequest(pchReply, &cbReplyBytes);
// Write the reply to the pipe.
fSuccess = WriteFile(
hPipe, // handle to pipe
pchReply, // buffer to write from
cbReplyBytes, // number of bytes to write
&cbWritten, // number of bytes written
NULL); // not overlapped I/O
if (!fSuccess || cbReplyBytes != cbWritten)
{
_tprintf(TEXT("InstanceThread WriteFile failed, GLE=%d.\n"), GetLastError());
break;
}
}
// Flush the pipe to allow the client to read the pipe's contents
// before disconnecting. Then disconnect the pipe, and close the
// handle to this pipe instance.
FlushFileBuffers(hPipe);
DisconnectNamedPipe(hPipe);
CloseHandle(hPipe);
HeapFree(hHeap, 0, pchRequest);
HeapFree(hHeap, 0, pchReply);
printf("InstanceThread exitting.\n");
return 1;
}
VOID GetAnswerToRequest(char* pchReply,
LPDWORD pchBytes)
{
printf("\n>>");
gets(pchReply);
*pchBytes = (strlen(pchReply)+1)*sizeof(char);
}
/*
/*
提供该示例代码是为了阐释一个概念,或者进行一个测试,并不代表着
最安全的编码实践,因此不应在应用程序或网站中使用该示例代码。对
于超出本示例代码的预期用途以外的使用所造成的偶然或继发性损失,
北京英真时代科技有限公司不承担任何责任。
*/
/*
在下面的函数中实现了 SCAN 磁盘调度算法(电梯算法)。
该算法优先考虑磁头移动的方向,然后再考虑移动距离最短。
*/
PREQUEST
IopDiskSchedule(
VOID
)
{
PLIST_ENTRY pListEntry;
PREQUEST pRequest;
LONG Offset;
ULONG InsideShortestDistance = 0xFFFFFFFF;
ULONG OutsideShortestDistance = 0xFFFFFFFF;
PREQUEST pNextRequest = NULL;
//
// 需要遍历请求队列一次或两次
//
while (TRUE) {
for (pListEntry = RequestListHead.Next; // 请求队列中的第一个请求是链表头指向的下一个请求。
pListEntry != &RequestListHead; // 遍历到请求队列头时结束循环。
pListEntry = pListEntry->Next) {
//
// 根据链表项获得请求的指针
//
pRequest = CONTAINING_RECORD(pListEntry, REQUEST, ListEntry);
//
// 计算请求对应的线程所访问的磁道与当前磁头所在磁道的偏移(方向由正负表示)
//
Offset = pRequest->Cylinder - CurrentCylinder;
if (0 == Offset) {
//
// 如果线程要访问的磁道与当前磁头所在磁道相同,可立即返回。
//
pNextRequest = pRequest;
goto RETURN;
} else if (ScanInside && Offset > 0) {
//
// 记录向内移动距离最短的线程
//
if (Offset < InsideShortestDistance) {
InsideShortestDistance = Offset;
pNextRequest = pRequest;
}
} else if (!ScanInside && Offset < 0) {
//
// 记录向外移动距离最短的线程
//
if (-Offset < OutsideShortestDistance) {
OutsideShortestDistance = -Offset;
pNextRequest = pRequest;
}
}
}
//
// 如果第一次遍历没有线程访问指定方向上的磁道,就变换方向,
// 进行第二次遍历。在这两次遍历中一定能找到合适的线程。
//
if (NULL == pNextRequest)
ScanInside = !ScanInside;
else
break;
}
RETURN:
return pNextRequest;
}
/*
/*
提供该示例代码是为了阐释一个概念,或者进行一个测试,并不代表着
最安全的编码实践,因此不应在应用程序或网站中使用该示例代码。对
于超出本示例代码的预期用途以外的使用所造成的偶然或继发性损失,
北京英真时代科技有限公司不承担任何责任。
*/
/*
在下面的函数中实现了 SSTF (Shortest Seek Time First) 磁盘调度算法。
该算法选择这样的线程,其要求访问的磁道与当前磁头所在的磁道距离最近,
以使每次的寻道时间最短,但这种算法却不能保证平均寻道时间最短。
*/
PREQUEST
IopDiskSchedule(
VOID
)
{
PLIST_ENTRY pListEntry;
PREQUEST pRequest;
LONG Offset;
ULONG ShortestDistance = 0xFFFFFFFF;
PREQUEST pNextRequest;
//
// 遍历请求队列选择这样的请求,其对应的线程所访问的磁道与当前磁头所在的磁道距离最近。
//
for (pListEntry = RequestListHead.Next; // 请求队列中的第一个请求是链表头指向的下一个请求。
pListEntry != &RequestListHead; // 遍历到请求队列头时结束循环。
pListEntry = pListEntry->Next) {
//
// 根据链表项获得请求的指针
//
pRequest = CONTAINING_RECORD(pListEntry, REQUEST, ListEntry);
//
// 计算请求对应的线程所访问的磁道与当前磁头所在磁道的偏移
//
Offset = pRequest->Cylinder - CurrentCylinder;
//
// 记录下最短的距离和对应的请求的指针
// 注意,由于 ShortestDistance 被初始化为最大的无符号整型,
// 所以在第一次循环时,条件语句的布尔表达式的值一定为真。
//
if (abs(Offset) < ShortestDistance) {
ShortestDistance = abs(Offset);
pNextRequest = pRequest;
}
}
//
// 循环结束后,pNextRequest 指向的请求对应的线程所访问
// 的磁道与当前磁头所在的磁道距离最短。
//
return pNextRequest;
}
++ "a/13\346\211\253\346\217\217FAT12\346\226\207\344\273\266\347\263\273\347\273\237\347\256\241\347\220\206\347\232\204\350\275\257\347\233\230/void.txt"
/*
/*
提供该示例代码是为了阐释一个概念,或者进行一个测试,并不代表着
最安全的编码实践,因此不应在应用程序或网站中使用该示例代码。对
于超出本示例代码的预期用途以外的使用所造成的偶然或继发性损失,
北京英真时代科技有限公司不承担任何责任。
*/
STATUS
FatWriteFile(
IN PVCB Vcb,
IN PFCB File,
IN ULONG Offset,
IN ULONG BytesToWrite,
OUT PVOID Buffer,
OUT PULONG BytesWriten
)
{
STATUS Status;
// 由于在将新分配的簇插入簇链尾部时,必须知道前一个簇的簇号,
// 所以定义了“前一个簇号”和“当前簇号”两个变量。
USHORT PrevClusterNum, CurrentClusterNum;
USHORT NewClusterNum;
ULONG ClusterIndex;
ULONG FirstSectorOfCluster;
ULONG OffsetInSector;
ULONG i;
// 写入的起始位置不能超出文件大小(并不影响增加文件大小或增加簇,想想原因?)
if (Offset > File->FileSize)
return STATUS_SUCCESS;
// 根据簇的大小,计算写入的起始位置在簇链的第几个簇中(从 0 开始计数)
ClusterIndex = Offset / FatBytesPerCluster(&Vcb->Bpb);
// 顺着簇链向后查找写入的起始位置所在簇的簇号。
PrevClusterNum = 0;
CurrentClusterNum = File->FirstCluster;
for (i = ClusterIndex; i > 0; i--) {
PrevClusterNum = CurrentClusterNum;
CurrentClusterNum = FatGetFatEntryValue(Vcb, PrevClusterNum);
}
// 如果写入的起始位置还没有对应的簇,就增加簇
if (0 == CurrentClusterNum || CurrentClusterNum >= 0xFF8) {
// 为文件分配一个空闲簇
FatAllocateOneCluster(Vcb, &NewClusterNum);
// 将新分配的簇安装到簇链中
if (0 == File->FirstCluster)
File->FirstCluster = NewClusterNum;
else
FatSetFatEntryValue(Vcb, PrevClusterNum, NewClusterNum);
CurrentClusterNum = NewClusterNum;
}
// 计算当前簇的第一个扇区的扇区号。簇从 2 开始计数。
FirstSectorOfCluster = Vcb->FirstDataSector + (CurrentClusterNum - 2) * Vcb->Bpb.SectorsPerCluster;
// 计算写位置在扇区内的字节偏移。
OffsetInSector = Offset % Vcb->Bpb.BytesPerSector;
// 为了简单,暂时只处理一个簇包含一个扇区的情况。
// 并且只处理写入的数据在一个扇区范围内的情况。
Status = IopReadWriteSector( Vcb->DiskDevice,
FirstSectorOfCluster,
OffsetInSector,
(PCHAR)Buffer,
BytesToWrite,
FALSE );
if (!EOS_SUCCESS(Status))
return Status;
// 如果文件长度增加了则必须修改文件的长度。
if (Offset + BytesToWrite > File->FileSize) {
File->FileSize = Offset + BytesToWrite;
// 如果是数据文件则需要同步修改文件在磁盘上对应的 DIRENT 结构
// 体。目录文件的 DIRENT 结构体中的 FileSize 永远为 0,无需修改。
if (!File->AttrDirectory)
FatWriteDirEntry(Vcb, File);
}
// 返回实际写入的字节数量
*BytesWriten = BytesToWrite;
return STATUS_SUCCESS;
}
/*
/*
提供该示例代码是为了阐释一个概念,或者进行一个测试,并不代表着
最安全的编码实践,因此不应在应用程序或网站中使用该示例代码。对
于超出本示例代码的预期用途以外的使用所造成的偶然或继发性损失,
北京英真时代科技有限公司不承担任何责任。
*/
#include "EOSApp.h"
#define BUFFER_SIZE 256
BYTE Buffer[BUFFER_SIZE];
//
// main 函数参数的意义:
// argc - argv 数组的长度,大小至少为 1,argc - 1 为命令行参数的数量。
// argv - 字符串指针数组,数组长度为命令行参数个数 + 1。其中 argv[0] 固定指向当前
// 进程所执行的可执行文件的路径字符串,argv[1] 及其后面的指针指向各个命令行
// 参数。
// 例如通过命令行内容 "a:\hello.exe -a -b" 启动进程后,hello.exe 的 main 函
// 数的参数 argc 的值为 3,argv[0] 指向字符串 "a:\hello.exe",argv[1] 指向
// 参数字符串 "-a",argv[2] 指向参数字符串 "-b"。
//
int main(int argc, char* argv[])
{
//
// 启动调试 EOS 应用程序前要特别注意下面的问题:
//
// 1、如果要在调试应用程序时能够调试进入内核并显示对应的源码,
// 必须使用 EOS 核心项目编译生成完全版本的 SDK 文件夹,然
// 后使用此文件夹覆盖应用程序项目中的 SDK 文件夹,并且 EOS
// 核心项目在磁盘上的位置不能改变。
//
HANDLE hFileRead = INVALID_HANDLE_VALUE;
HANDLE hFileWrite = INVALID_HANDLE_VALUE;
HANDLE hOutput;
ULONG m, n;
int Result = 1; // 返回值 1,表示执行失败
//
// 命令行语法:A:\EOSApp.exe read_file_name [write_file_name] [-a]
// 举例:A:\EOSApp.exe A:\a.txt
// 表示将 a.txt 文件中的内容输出到屏幕上
// A:\EOSApp.exe A:\a.txt A:\b.txt
// 表示将 a.txt 文件中的内容写入 b.txt 文件中。b.txt 文件原有的内容会被覆盖。
// A:\EOSApp.exe A:\a.txt A:\b.txt -a
// 表示将 a.txt 文件中的内容附加到 b.txt 文件的末尾。
//
if (argc < 2 || argc > 4)
{
printf("Error: Invalid argument count!\n"
"Valid command line: EOSApp.exe read_file_name [write_file_name] [-a]\n");
goto RETURN;
}
//
// 以只读的方式,打开要读取的文件
//
hFileRead = CreateFile(argv[1], GENERIC_READ, 0, OPEN_EXISTING, 0);
if (INVALID_HANDLE_VALUE == hFileRead)
{
printf("Open file \"%s\" error: %d\n", argv[1], GetLastError());
goto RETURN;
}
//
// 如果命令行参数中有要写入的文件,就使用写入文件句柄做为输出句柄,
// 否则使用标准输出(屏幕)句柄做为输出句柄。
//
if (argc > 2)
{
//
// 以只写的方式,打开要写入的文件
//
hFileWrite = CreateFile(argv[2], GENERIC_WRITE, 0, OPEN_EXISTING, 0);
if (INVALID_HANDLE_VALUE == hFileWrite)
{
printf("Open file \"%s\" error: %d\n", argv[2], GetLastError());
goto RETURN;
}
//
// 如果是增加写,则将文件指针移动到文件的末尾。
//
if (4 == argc && 0 == stricmp(argv[3], "-a"))
{
SetFilePointer(hFileWrite, GetFileSize(hFileWrite), FILE_BEGIN);
}
hOutput = hFileWrite;
}
else
{
hOutput = GetStdHandle(STD_OUTPUT_HANDLE);
}
while (TRUE)
{
//
// 尝试读取 BUFFER_SIZE 个字节,实际读取到的字节数由 m 返回。
//
ReadFile(hFileRead, Buffer, BUFFER_SIZE, &m);
//
// 将实际读取到的 m 个字节写入输出句柄。
//
if (!WriteFile(hOutput, Buffer, m, &n))
{
printf("Write file error: %d\n", GetLastError());
goto RETURN;
}
//
// 如果实际读取的字节数少于预期,说明文件读取完毕。
//
if (m < BUFFER_SIZE)
break;
}
//
// 返回值 0,表示执行成功
//
Result = 0;
RETURN:
//
// 关闭文件
//
if (hFileRead != INVALID_HANDLE_VALUE)
CloseHandle(hFileRead);
if (hFileWrite != INVALID_HANDLE_VALUE)
CloseHandle(hFileWrite);
return Result;
}
Operating System
Operating System
FAT12 File System
\ No newline at end of file
++ "a/14\350\257\273\346\226\207\344\273\266\345\222\214\345\206\231\346\226\207\344\273\266/b.txt"
11111111111111111111111111111111111111111111111111111111111111111111111111111111222222222222222222222222222222222222222222222222222222222222222222222222222222223333333333333333333333333333333333333333333333333333333333333333333333333333333344444444444444444444444444444444444444444444444444444444444444444444444444444444555555555555555555555555555555555555555555555555555555555555555555555555555555556666666666666666666666666666666666666666666666666666666666666666666666666666666677777777777777777777777777777777777777777777777777777777777777777777777777777777888888888888888888888888888888888888888888888888888888888888888888888888888888889999999999999999999999999999999999999999999999999999999999999999999999999999999900000000000000000000000000000000000000000000000000000000000000000000000000000000aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbcccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
11111111111111111111111111111111111111111111111111111111111111111111111111111111222222222222222222222222222222222222222222222222222222222222222222222222222222223333333333333333333333333333333333333333333333333333333333333333333333333333333344444444444444444444444444444444444444444444444444444444444444444444444444444444555555555555555555555555555555555555555555555555555555555555555555555555555555556666666666666666666666666666666666666666666666666666666666666666666666666666666677777777777777777777777777777777777777777777777777777777777777777777777777777777888888888888888888888888888888888888888888888888888888888888888888888888888888889999999999999999999999999999999999999999999999999999999999999999999999999999999900000000000000000000000000000000000000000000000000000000000000000000000000000000aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbcccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
\ No newline at end of file
OS Lab
OS Lab
\ No newline at end of file
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论