上一个v0.0.11的版本实现了execve系统调用,并且可以通过该系统调用来加载ELF可执行格式的文件(例如ram disk里的cpuid程式),所以当前的v1.0.0的版本就可以创建出各种ELF可执行文件出来,例如,shell(命令行程式),ls(可以显示出ram disk里包含的文件列表的程式)等等...
# This is a sample menu.lst file. You should make some changes to it. # The old install method of booting via the stage-files has been removed. # Please install GRLDR boot strap code to MBR with the bootlace.com # utility under DOS/Win9x or Linux. color blue/green yellow/red white/magenta white/magenta timeout 10 default /default default 0 timeout 10 #zenglOX title zenglOX root (hd0,0) kernel --type=multiboot /zenglOX.bin module /initrd.img title reboot reboot title halt halt |
zenglOX_v1.0.0/build_initrd_img$ readelf -a shell ........................................ ........................................ Section Headers: [Nr] Name Type Addr Off Size ES Flg Lk Inf Al [ 0] NULL 00000000 000000 000000 00 0 0 0 [ 1] .text PROGBITS 08048054 000054 000849 00 AX 0 0 4 [ 2] .rodata PROGBITS 0804889d 00089d 00001e 00 A 0 0 1 [ 3] .eh_frame PROGBITS 080488bc 0008bc 000518 00 A 0 0 4 ........................................ ........................................ |
ZLOX_UINT32 zlox_load_elf(ZLOX_ELF32_EHDR *hdr,ZLOX_UINT8 * buf) { .................................................. .................................................. ZLOX_PAGE * tmp_page; ZLOX_UINT32 table_idx; for(i = 0; i < hdr->e_shnum; i++) { if(shdr[i].sh_type == ZLOX_SHT_PROGBITS) { tmpSheader = &shdr[i]; if(tmpSheader->sh_addr == ZLOX_NULL) continue; for( j = tmpSheader->sh_addr; j < (tmpSheader->sh_addr + tmpSheader->sh_size); (j = ((j + 0x1000) & 0xFFFFF000))) { tmp_page = zlox_get_page(j, 1, current_directory); table_idx = (j/0x1000)/ 1024; if(tmp_page->frame == 0) zlox_alloc_frame( tmp_page, 0 , 1 ); else if((current_directory->tablesPhysical[table_idx] & 0x2) == 0) zlox_page_copy(j); } } } // Flush the TLB(translation lookaside buffer) by reading and writing the page directory address again. ZLOX_UINT32 pd_addr; asm volatile("mov %%cr3, %0" : "=r" (pd_addr)); asm volatile("mov %0, %%cr3" : : "r" (pd_addr)); for(i = 0; i < hdr->e_shnum; i++) { if(shdr[i].sh_type == ZLOX_SHT_PROGBITS) { tmpSheader = &shdr[i]; if(tmpSheader->sh_addr == ZLOX_NULL) continue; zlox_memcpy((ZLOX_UINT8 *)tmpSheader->sh_addr, (ZLOX_UINT8 *)(buf + tmpSheader->sh_offset),tmpSheader->sh_size); } } .................................................. .................................................. } |
// 给用户态程式使用的分配堆函数 ZLOX_UINT32 zlox_umalloc(ZLOX_UINT32 sz) { ZLOX_PAGE * page; ZLOX_UINT32 ret = zlox_kmalloc_int(sz, 0, 0); ZLOX_UINT32 i; for(i=ret; i < ret + sz ;i+=0x1000) { page = zlox_get_page(i, 0, kernel_directory); if(page->rw == 0) page->rw = 1; } // Flush the TLB(translation lookaside buffer) by reading and writing the page directory address again. ZLOX_UINT32 pd_addr; asm volatile("mov %%cr3, %0" : "=r" (pd_addr)); asm volatile("mov %0, %%cr3" : : "r" (pd_addr)); return ret; } // 给用户态程式使用的释放堆函数 ZLOX_VOID zlox_ufree(ZLOX_VOID *p) { ZLOX_PAGE * page; ZLOX_KHP_HEADER * header = (ZLOX_KHP_HEADER *)((ZLOX_UINT32)p - sizeof(ZLOX_KHP_HEADER)); ZLOX_UINT32 sz = header->size - sizeof(ZLOX_KHP_HEADER) - sizeof(ZLOX_KHP_FOOTER); ZLOX_UINT32 i; for(i=(ZLOX_UINT32)p; i < (ZLOX_UINT32)p + sz ;i+=0x1000) { page = zlox_get_page(i, 0, kernel_directory); if(page->rw == 1) page->rw = 0; } // Flush the TLB(translation lookaside buffer) by reading and writing the page directory address again. ZLOX_UINT32 pd_addr; asm volatile("mov %%cr3, %0" : "=r" (pd_addr)); asm volatile("mov %0, %%cr3" : : "r" (pd_addr)); zlox_free(p, kheap); } |
ZLOX_DEFN_SYSCALL1(monitor_write, ZLOX_SYSCALL_MONITOR_WRITE, const char*); ZLOX_DEFN_SYSCALL1(monitor_write_hex, ZLOX_SYSCALL_MONITOR_WRITE_HEX, ZLOX_UINT32); ZLOX_DEFN_SYSCALL1(monitor_write_dec, ZLOX_SYSCALL_MONITOR_WRITE_DEC, ZLOX_UINT32); ZLOX_DEFN_SYSCALL1(monitor_put, ZLOX_SYSCALL_MONITOR_PUT, char); ZLOX_DEFN_SYSCALL1(execve, ZLOX_SYSCALL_EXECVE, const char*); ZLOX_DEFN_SYSCALL3(get_tskmsg,ZLOX_SYSCALL_GET_TSKMSG,void *,void *,ZLOX_BOOL); ZLOX_DEFN_SYSCALL1(wait, ZLOX_SYSCALL_WAIT, void *); ZLOX_DEFN_SYSCALL1(set_input_focus, ZLOX_SYSCALL_SET_INPUT_FOCUS, void *); ZLOX_DEFN_SYSCALL0(get_currentTask,ZLOX_SYSCALL_GET_CURRENT_TASK); ZLOX_DEFN_SYSCALL1(exit, ZLOX_SYSCALL_EXIT, int); ZLOX_DEFN_SYSCALL1(finish, ZLOX_SYSCALL_FINISH, void *); ZLOX_DEFN_SYSCALL1(get_args, ZLOX_SYSCALL_GET_ARGS, void *); ZLOX_DEFN_SYSCALL1(get_init_esp, ZLOX_SYSCALL_GET_INIT_ESP, void *); ZLOX_DEFN_SYSCALL1(umalloc, ZLOX_SYSCALL_UMALLOC, int); ZLOX_DEFN_SYSCALL1(ufree, ZLOX_SYSCALL_UFREE, void *); ZLOX_DEFN_SYSCALL4(read_fs,ZLOX_SYSCALL_READ_FS,void *,int,int,void *); ZLOX_DEFN_SYSCALL2(readdir_fs,ZLOX_SYSCALL_READDIR_FS,void *,int); ZLOX_DEFN_SYSCALL2(finddir_fs,ZLOX_SYSCALL_FINDDIR_FS,void *,void *); ZLOX_DEFN_SYSCALL0(get_fs_root,ZLOX_SYSCALL_GET_FS_ROOT); ZLOX_DEFN_SYSCALL2(get_frame_info,ZLOX_SYSCALL_GET_FRAME_INFO,void **,void *); ZLOX_DEFN_SYSCALL0(get_kheap,ZLOX_SYSCALL_GET_KHEAP); ZLOX_DEFN_SYSCALL3(get_version,ZLOX_SYSCALL_GET_VERSION,void *,void *,void *); ZLOX_DEFN_SYSCALL0(reboot,ZLOX_SYSCALL_REBOOT); ZLOX_DEFN_SYSCALL0(shutdown,ZLOX_SYSCALL_SHUTDOWN); static ZLOX_VOID * syscalls[ZLOX_SYSCALL_NUMBER] = { &zlox_monitor_write, &zlox_monitor_write_hex, &zlox_monitor_write_dec, &zlox_monitor_put, &zlox_execve, &zlox_get_tskmsg, &zlox_wait, &zlox_set_input_focus, &zlox_get_currentTask, &zlox_exit, &zlox_finish, &zlox_get_args, &zlox_get_init_esp, &zlox_umalloc, &zlox_ufree, &zlox_read_fs, &zlox_readdir_fs, &zlox_finddir_fs, &zlox_get_fs_root, &zlox_get_frame_info, &zlox_get_kheap, &zlox_get_version, &_zlox_reboot, &_zlox_shutdown, }; |
ZLOX_SINT32 zlox_syscall_monitor_write(const char* p1) \ { \ ZLOX_SINT32 a; \ asm volatile("int $0x80" : "=a" (a) : "0" (0), "b" ((ZLOX_SINT32)p1)); \ return a; \ } |
//zenglOX kernel main entry ZLOX_SINT32 zlox_kernel_main(ZLOX_MULTIBOOT * mboot_ptr, ZLOX_UINT32 initial_stack) { .......................................... .......................................... // 切换到ring 3的用户模式 zlox_switch_to_user_mode(); zlox_syscall_monitor_write("I'm in user mode!\n"); zlox_syscall_monitor_write("welcome to zenglOX v"); ZLOX_SINT32 major,minor,revision; zlox_syscall_get_version(&major,&minor,&revision); zlox_syscall_monitor_write_dec(major); zlox_syscall_monitor_put('.'); zlox_syscall_monitor_write_dec(minor); zlox_syscall_monitor_put('.'); zlox_syscall_monitor_write_dec(revision); zlox_syscall_monitor_write("! I will execve a shell\n" "you can input some command: ls , ps , cat , uname , cpuid , shell , reboot ...\n"); zlox_syscall_execve("shell"); //zlox_syscall_execve("cpuid"); zlox_syscall_wait(current_task); ZLOX_SINT32 ret; ZLOX_TASK_MSG msg; while(ZLOX_TRUE) { ret = zlox_syscall_get_tskmsg(current_task,&msg,ZLOX_TRUE); if(ret != 1) { zlox_syscall_wait(current_task); // 只剩下一个初始任务了,就再创建一个shell if(current_task->next == 0) { zlox_syscall_execve("shell"); zlox_syscall_wait(current_task); } } else if(msg.type == ZLOX_MT_TASK_FINISH) { zlox_syscall_finish(msg.finish_task.exit_task); } } return 0; } |
// zlox_syscall.h Defines the interface for and structures relating to the syscall dispatch system. #ifndef _ZLOX_SYSCALL_H_ #define _ZLOX_SYSCALL_H_ #include "zlox_common.h" #define ZLOX_SYSCALL_NUMBER 24 #define ZLOX_MAJOR_VERSION 1 //zenglOX 主版本号 #define ZLOX_MINOR_VERSION 0 //zenglOX 子版本号 #define ZLOX_REVISION 0 //zenglOX 修正版本号 .......................................... .......................................... |
ZLOX_SINT32 zlox_get_version(ZLOX_SINT32 * major, ZLOX_SINT32 * minor, ZLOX_SINT32 * revision) { *major = ZLOX_MAJOR_VERSION; *minor = ZLOX_MINOR_VERSION; *revision = ZLOX_REVISION; return 0; } |
// 将task任务设置为wait等待状态 ZLOX_SINT32 zlox_wait(ZLOX_TASK * task) { // 将任务状态设置为等待状态 task->status = ZLOX_TS_WAIT; // 如果task是当前任务,则进行任务切换 if(task == current_task) zlox_switch_task(); return 0; } |
// 结束当前任务,并向父任务或首任务发送结束消息 ZLOX_SINT32 zlox_exit(ZLOX_SINT32 exit_code) { ZLOX_TASK * parent_task = current_task->parent; ZLOX_TASK * notify_task = parent_task; ZLOX_TASK_MSG ascii_msg = {0}; if(parent_task == 0) return -1; // 如果父任务处于wait等待状态,则将其唤醒,并发送结束消息 if(parent_task->status == ZLOX_TS_WAIT) parent_task->status = ZLOX_TS_RUNNING; // 如果父任务已经结束了,则向第一个任务发送结束消息 else if(parent_task->status == ZLOX_TS_FINISH) { if(ready_queue->status == ZLOX_TS_WAIT) ready_queue->status = ZLOX_TS_RUNNING; else if(ready_queue->status == ZLOX_TS_FINISH) { current_task->status = ZLOX_TS_ZOMBIE; // 如果没有任务可以进行通知的话,则当前任务就变为僵死任务 return -1; } notify_task = (ZLOX_TASK *)ready_queue; } current_task->status = ZLOX_TS_FINISH; ascii_msg.type = ZLOX_MT_TASK_FINISH; ascii_msg.finish_task.exit_task = (ZLOX_TASK *)current_task; ascii_msg.finish_task.exit_code = exit_code; zlox_send_tskmsg(notify_task,&ascii_msg); zlox_switch_task(); return 0; } |
typedef enum _ZLOX_MSG_TYPE { ZLOX_MT_KEYBOARD, ZLOX_MT_TASK_FINISH, }ZLOX_MSG_TYPE; typedef enum _ZLOX_MSG_KB_TYPE { ZLOX_MKT_ASCII, }ZLOX_MSG_KB_TYPE; typedef enum _ZLOX_TSK_STATUS { ZLOX_TS_WAIT, ZLOX_TS_RUNNING, ZLOX_TS_FINISH, ZLOX_TS_ZOMBIE, }ZLOX_TSK_STATUS; typedef struct _ZLOX_TASK_MSG_KEYBOARD { ZLOX_MSG_KB_TYPE type; ZLOX_UINT32 ascii; }ZLOX_TASK_MSG_KEYBOARD; typedef struct _ZLOX_TASK ZLOX_TASK; typedef struct _ZLOX_TASK_MSG_FINISH { ZLOX_TASK * exit_task; ZLOX_SINT32 exit_code; }ZLOX_TASK_MSG_FINISH; typedef struct _ZLOX_TASK_MSG { ZLOX_MSG_TYPE type; ZLOX_TASK_MSG_KEYBOARD keyboard; ZLOX_TASK_MSG_FINISH finish_task; // 消息中存储的结束任务的相关信息 }ZLOX_TASK_MSG; typedef struct _ZLOX_TASK_MSG_LIST { ZLOX_BOOL isInit; ZLOX_SINT32 count; ZLOX_SINT32 size; ZLOX_SINT32 cur; ZLOX_SINT32 finish_task_num; ZLOX_TASK_MSG * ptr; }ZLOX_TASK_MSG_LIST; // This structure defines a 'task' - a process. struct _ZLOX_TASK { ZLOX_UINT32 sign; // Process sign ZLOX_SINT32 id; // Process ID. ZLOX_UINT32 esp, ebp; // Stack and base pointers. ZLOX_UINT32 eip; // Instruction pointer. ZLOX_UINT32 init_esp; // stack top ZLOX_PAGE_DIRECTORY * page_directory; // Page directory. ZLOX_UINT32 kernel_stack; // Kernel stack location. ZLOX_TASK_MSG_LIST msglist; // task message. ZLOX_TSK_STATUS status; // task status. ZLOX_CHAR * args; // task args ZLOX_TASK * next; // The next task in a linked list. ZLOX_TASK * prev; // the prev task ZLOX_TASK * parent; // parent task }; |
// 将消息压入消息列表,消息列表里的消息是采用的先进入的消息先处理的方式 ZLOX_SINT32 zlox_push_tskmsg(ZLOX_TASK_MSG_LIST * msglist , ZLOX_TASK_MSG * msg) { if(!msglist->isInit) // 如果没进行过初始化,则初始化消息列表 { msglist->size = ZLOX_TSK_MSGLIST_SIZE; msglist->ptr = (ZLOX_TASK_MSG *)zlox_kmalloc(msglist->size * sizeof(ZLOX_TASK_MSG)); zlox_memset((ZLOX_UINT8 *)msglist->ptr,0,msglist->size * sizeof(ZLOX_TASK_MSG)); msglist->count = 0; msglist->cur = 0; msglist->isInit = ZLOX_TRUE; } else if(msglist->count == msglist->size) // 如果消息列表数目达到了当前容量的上限,则对消息列表进行动态扩容 { ZLOX_TASK_MSG * tmp_ptr; msglist->size += ZLOX_TSK_MSGLIST_SIZE; tmp_ptr = (ZLOX_TASK_MSG *)zlox_kmalloc(msglist->size * sizeof(ZLOX_TASK_MSG)); zlox_memcpy((ZLOX_UINT8 *)(tmp_ptr + msglist->cur),(ZLOX_UINT8 *)(msglist->ptr + msglist->cur), (msglist->count - msglist->cur) * sizeof(ZLOX_TASK_MSG)); if(msglist->cur > 0) { zlox_memcpy((ZLOX_UINT8 *)(tmp_ptr + msglist->count),(ZLOX_UINT8 *)msglist->ptr, msglist->cur * sizeof(ZLOX_TASK_MSG)); } zlox_kfree(msglist->ptr); msglist->ptr = tmp_ptr; } ZLOX_UINT32 index = ((msglist->cur + msglist->count) < msglist->size) ? (msglist->cur + msglist->count) : (msglist->cur + msglist->count - msglist->size); msglist->ptr[index] = *msg; msglist->count++; return 0; } // 获取消息列表中的消息,needPop参数表示是否需要将消息弹出消息列表 ZLOX_TASK_MSG * zlox_pop_tskmsg(ZLOX_TASK_MSG_LIST * msglist,ZLOX_BOOL needPop) { ZLOX_TASK_MSG * ret; if(msglist->count <= 0) return ZLOX_NULL; ret = &msglist->ptr[msglist->cur]; if(needPop) { msglist->cur = ((msglist->cur + 1) < msglist->size) ? (msglist->cur + 1) : 0; msglist->count = (msglist->count - 1) > 0 ? (msglist->count - 1) : 0; } return ret; } |
// syscall.c Defines the implementation of a system call system.
#include "syscall.h"
DEFN_SYSCALL1(monitor_write, SYSCALL_MONITOR_WRITE, const char*);
DEFN_SYSCALL1(monitor_write_hex, SYSCALL_MONITOR_WRITE_HEX, UINT32);
DEFN_SYSCALL1(monitor_write_dec, SYSCALL_MONITOR_WRITE_DEC, UINT32);
DEFN_SYSCALL1(monitor_put, SYSCALL_MONITOR_PUT, char);
DEFN_SYSCALL1(execve, SYSCALL_EXECVE, const char*);
DEFN_SYSCALL3(get_tskmsg,SYSCALL_GET_TSKMSG,void *,void *,BOOL);
DEFN_SYSCALL1(wait, SYSCALL_WAIT, void *);
DEFN_SYSCALL1(set_input_focus, SYSCALL_SET_INPUT_FOCUS, void *);
DEFN_SYSCALL0(get_currentTask,SYSCALL_GET_CURRENT_TASK);
DEFN_SYSCALL1(exit, SYSCALL_EXIT, int);
DEFN_SYSCALL1(finish, SYSCALL_FINISH, void *);
DEFN_SYSCALL1(get_args, SYSCALL_GET_ARGS, void *);
DEFN_SYSCALL1(get_init_esp, SYSCALL_GET_INIT_ESP, void *);
DEFN_SYSCALL1(umalloc, SYSCALL_UMALLOC, int);
DEFN_SYSCALL1(ufree, SYSCALL_UFREE, void *);
DEFN_SYSCALL4(read_fs,SYSCALL_READ_FS,void *,int,int,void *);
DEFN_SYSCALL2(readdir_fs,SYSCALL_READDIR_FS,void *,int);
DEFN_SYSCALL2(finddir_fs,SYSCALL_FINDDIR_FS,void *,void *);
DEFN_SYSCALL0(get_fs_root,SYSCALL_GET_FS_ROOT);
DEFN_SYSCALL2(get_frame_info,SYSCALL_GET_FRAME_INFO,void **,void *);
DEFN_SYSCALL0(get_kheap,SYSCALL_GET_KHEAP);
DEFN_SYSCALL3(get_version,SYSCALL_GET_VERSION,void *,void *,void *);
DEFN_SYSCALL0(reboot,SYSCALL_REBOOT);
DEFN_SYSCALL0(shutdown,SYSCALL_SHUTDOWN);
|
SINT32 syscall_monitor_write(const char* p1) \ { \ SINT32 a; \ asm volatile("int $0x80" : "=a" (a) : "0" (0), "b" ((SINT32)p1)); \ return a; \ } |
// shell.c -- 命令行程式 #include "common.h" #include "syscall.h" #include "task.h" #define MAX_INPUT 100 int main(VOID * task, int argc, char * argv[]) { int ret; int count = 0; char input[MAX_INPUT]={0}; TASK_MSG msg; UNUSED(argc); UNUSED(argv); /*syscall_monitor_write("zenglOX> "); for(int i=0;i < argc;i++) { syscall_monitor_write(argv[i]); syscall_monitor_put(' '); } syscall_monitor_put('\n');*/ /*char * test = (char *)syscall_umalloc(50); strcpy(test,"hello world\n"); syscall_monitor_write(test); syscall_ufree(test);*/ syscall_monitor_write("zenglOX> "); syscall_set_input_focus(task); while(TRUE) { ret = syscall_get_tskmsg(task,&msg,TRUE); if(ret != 1) continue; if(msg.type == MT_KEYBOARD) { if(msg.keyboard.type != MKT_ASCII) continue; if(msg.keyboard.ascii == '\n') { syscall_monitor_put('\n'); if(strcmp(input,"exit") == 0) return 0; else if(syscall_execve(input) == 0) syscall_wait(task); count = 0; syscall_monitor_write("\nzenglOX> "); syscall_set_input_focus(task); continue; } else if(msg.keyboard.ascii == '\b') { if(count > 0) { syscall_monitor_write("\b \b"); input[--count] = '\0'; } continue; } else if(msg.keyboard.ascii == '\t') continue; if(count < (MAX_INPUT-1)) { input[count++] = msg.keyboard.ascii; input[count]='\0'; syscall_monitor_put((char)msg.keyboard.ascii); } } else if(msg.type == MT_TASK_FINISH) { syscall_finish(msg.finish_task.exit_task); } } return -1; } |
// entry.c -- 主入口函数 #include "common.h" #include "syscall.h" #include "task.h" int main(VOID * task, int argc, char * argv[]); int entry() { VOID * task = (VOID *)syscall_get_currentTask(); VOID * location = &main; char * args = ((char *)syscall_get_init_esp(task)) - 1; char * orig_args = (char *)syscall_get_args(task); int arg_num = 0; int ret; int length = strlen(orig_args); int i = length - 1; if(args >= orig_args) reverse_memcpy((UINT8 *)args,(UINT8 *)(orig_args + length),length + 1); else memcpy((UINT8 *)(args - length),(UINT8 *)orig_args,length + 1); args -= length; asm volatile("movl %0,%%esp"::"r"((UINT32)args)); for(;i>=0;i--) { if(args[i] == ' ' && args[i+1] != ' ' && args[i+1] != '\0') { arg_num++; asm volatile("push %0" :: "r"((UINT32)(args + i + 1))); } } if(args[0] != ' ' && args[0] != '\0') { arg_num++; asm volatile("push %0" :: "r"((UINT32)args)); } for(i=0;i < length;i++) { if(args[i] == ' ') { args[i] = '\0'; } } asm volatile(" \ movl %esp,%eax; \ push %eax; \ "); asm volatile("push %1; \ push %2; \ call *%3; \ " : "=a" (ret) : "b"(arg_num), "c"((UINT32)task), "0" (location)); syscall_exit(ret); return 0; } |
#makefile for ram disk ...................................... ...................................... shell: shell.o syscall.o entry.o common.o @echo 'building $@' $(CROSS_CC) -Wl,-eentry -o $@ $(CROSS_CLINK_FLAGS) shell.o syscall.o entry.o common.o ...................................... ...................................... |