| @@ -0,0 +1,96 @@ | ||
| #ifndef TYPES_H | ||
| #define TYPES_H | ||
|
|
||
| typedef unsigned long Pointer; | ||
| typedef unsigned long size_t; | ||
| typedef long ssize_t; | ||
| typedef int pid_t; | ||
| typedef unsigned char Byte; | ||
| typedef int (*IrqHandler)(int); | ||
|
|
||
| typedef struct{ | ||
| long back_link; | ||
| long esp0; | ||
| long ss0; | ||
| long esp1; | ||
| long ss1; | ||
| long esp2; | ||
| long ss2; | ||
| long cr3; | ||
| long eip; | ||
| long eflags; | ||
| long eax,ecx,edx,ebx; | ||
| long esp; | ||
| long ebp; | ||
| long esi; | ||
| long edi; | ||
| long es; | ||
| long cs; | ||
| long ss; | ||
| long ds; | ||
| long fs; | ||
| long gs; | ||
| long ldt; | ||
| long io; | ||
| }Tss; | ||
|
|
||
| typedef struct { | ||
| long gs; | ||
| long fs; | ||
| long ds; | ||
| long es; | ||
| long edi; | ||
| long esi; | ||
| long ebp; | ||
| long _esp; | ||
| long ebx; | ||
| long edx; | ||
| long ecx; | ||
| long eax; | ||
| long eip; | ||
| long cs; | ||
| long eflags; | ||
| long esp; | ||
| long ss; | ||
| }Registers; | ||
|
|
||
|
|
||
| typedef struct message Message; | ||
| struct message{ | ||
| int type; | ||
| pid_t src; | ||
| union{ | ||
| struct{Pointer cr2,cr3;}; | ||
| char msg[64 - 8]; | ||
| }; | ||
| }; | ||
| typedef struct intelink Interrput; | ||
| struct intelink{ | ||
| Message message; | ||
| Interrput *next; | ||
| }; | ||
| typedef struct proc Proc; | ||
| struct proc{ | ||
| pid_t pid; | ||
| long counter; | ||
| long timeout; | ||
| int pri; | ||
| int flags; | ||
| pid_t getfrom,wait; | ||
| Pointer core; | ||
| Pointer esp0; | ||
| Registers *registers; | ||
| char pname[16]; | ||
| Message message; | ||
| Interrput *interruptlink; | ||
| struct proc *next,*prev; | ||
| struct proc *sendlink; | ||
| }; | ||
|
|
||
| union{ | ||
| Proc proc; | ||
| char stack[KERNEL_STACK_SIZE]; | ||
| }Task; | ||
|
|
||
|
|
||
| #endif |
| @@ -0,0 +1,60 @@ | ||
| /* | ||
| * (c) LuoZH 2011 | ||
| * 这个文件的目录好像很深的样子,这个文件主要就是定义几个供内核操作IO使用 | ||
| * 的C语言宏,没有其他什么的.可以看出,我很多东西都抄linux的,这算不算抄? | ||
| * 额,差点忘了,这段引至linux,版权不归我所有,好吧,上面版权那行无效.希望linus | ||
| * 等人看到不会揍我,我是无辜的:-) | ||
| */ | ||
| #define outb(value,port) \ | ||
| asm("out %%al,%%dx"::"a"(value),"d"(port)) | ||
| #define outw(value,port) \ | ||
| asm("out %%ax,%%dx"::"a"(value),"d"(port)) | ||
| //下面这个其实我不是很理解,为何这样就能返回_v的值` | ||
| #define inb(port) ({\ | ||
| unsigned char _v; \ | ||
| asm volatile("in %%dx,%%al":"=a"(_v):"d"(port)); \ | ||
| _v;\ | ||
| }) | ||
| #define inw(port) ({\ | ||
| unsigned short _v; \ | ||
| asm volatile("in %%dx,%%ax":"=a"(_v):"d"(port)); \ | ||
| _v;\ | ||
| }) | ||
| //下面是带延时功能的 | ||
| #define outb_p(value,port) \ | ||
| asm("out %%al,%%dx\n"\ | ||
| "jmp 1f\n" \ | ||
| "1:jmp 1f\n" \ | ||
| "1:"::"a"(value),"d"(port) \ | ||
| ) | ||
| #define outw_p(value,port) \ | ||
| asm("out %%ax,%%dx\n"\ | ||
| "jmp 1f\n" \ | ||
| "1:jmp 1f\n" \ | ||
| "1:"::"a"(value),"d"(port) \ | ||
| ) | ||
| #define inb_p(port) ({\ | ||
| unsigned char _v; \ | ||
| asm volatile("in %%dx,%%al\n" \ | ||
| "jmp 1f\n" \ | ||
| "1:jmp 1f\n" \ | ||
| "1:":"=a"(_v):"d"(port));\ | ||
| _v; \ | ||
| }) | ||
| #define inw_p(port) ({\ | ||
| unsigned short _v; \ | ||
| asm volatile("in %%dx,%%al\n" \ | ||
| "jmp 1f\n" \ | ||
| "1:jmp 1f\n" \ | ||
| "1:":"=a"(_v):"d"(port));\ | ||
| _v; \ | ||
| }) | ||
|
|
||
| #define sti() asm("sti") | ||
| #define cli() asm("cli") | ||
| #define wait() asm("wait") | ||
| #define hlt() asm("hlt") | ||
| #define invalidate() \ | ||
| asm("mov %%cr3,%%eax\n\t" \ | ||
| "mov %%eax,%%cr3\n\t" \ | ||
| :::"%eax") |
| @@ -0,0 +1,47 @@ | ||
| # Makefile for all | ||
| # | ||
| .PHONY:clear install make all | ||
|
|
||
| # Directories | ||
| i = $r/include | ||
| s = none | ||
| l = $r/lib | ||
| m = $r/mm | ||
|
|
||
| #kernel entry | ||
| entry = 0x305000 | ||
| vpath %.h $r/include/ | ||
|
|
||
| # Programs, flags, etc. | ||
| AS = as | ||
| CC = gcc | ||
| LD = ld | ||
|
|
||
| ASFLAGS = --32 | ||
| CFLAGS = -I $i -m32 -c -std=gnu99 -nostdinc -fno-stack-protector -Wall | ||
| LDFLAGS = -m elf_i386 -Ttext $(entry) -nostdlib \ | ||
| -L $l -lc #--oformat binary | ||
|
|
||
| HEAD = stdio.h malloc.h stddef.h stdarg.h | ||
|
|
||
| OBJS = setup.o main.o console.o printk.o panic.o x86.o trap.o proc.o\ | ||
| mm.o\ | ||
| clock.o | ||
|
|
||
| LIBS = $l/libc.a | ||
| # What to make. | ||
| # | ||
| $s:$(OBJS) $(LIBS) | ||
| $(LD) $(OBJS) -o $@ $(LDFLAGS) | ||
|
|
||
| %.o:%.S | ||
| $(CC) $< -o $@ $(CFLAGS) | ||
|
|
||
| %.o:%.c | ||
| $(CC) $< -o $@ $(CFLAGS) | ||
|
|
||
| %.o:%.s | ||
| $(AS) $< -o $@ $(ASFLAGS) | ||
|
|
||
| clear: | ||
| -rm *.o -rf |
| @@ -0,0 +1,108 @@ | ||
| #include "kernel.h" | ||
| #include <time.h> | ||
|
|
||
| volatile unsigned long jiffies = 0; | ||
| static time_t startup_time; | ||
| void unready(Proc *rp); | ||
| void pick_proc(void); | ||
|
|
||
|
|
||
| Registers *clock_handler(Registers *reg){ | ||
| act_proc->registers = reg; | ||
| static Message m = {.type = HARD_INT}; | ||
| if(!(jiffies % 10)) interrupt(CLOCK_PID,&m); | ||
| //if(act_proc != proc_ptr) printk("%s -> %s\n",act_proc->pname,proc_ptr->pname); | ||
| act_proc = proc_ptr; | ||
| tss->esp0 = act_proc->esp0; | ||
| ldcr3(act_proc->core); | ||
| return act_proc->registers; | ||
| } | ||
|
|
||
| #define CMOS_READ(addr) ({\ | ||
| outb_p(0x80 | addr,0x70); \ | ||
| inb_p(0x71);\ | ||
| }) | ||
|
|
||
| #define BCD_TO_BIN(val) ((val) = ((val) & 0xf) + ((val) >> 4)* 10) | ||
|
|
||
| #define MINUTE 60 | ||
| #define HOUR (60 * MINUTE) | ||
| #define DAY (24 * HOUR) | ||
| #define YEAR (365 * DAY) | ||
|
|
||
| static time_t mktime(Time *tm){ | ||
| time_t res; | ||
| static const int month[12] = { | ||
| 0, | ||
| 31, | ||
| 31 + 28, | ||
| 31 + 28 + 31, | ||
| 31 + 28 + 31 + 30, | ||
| 31 + 28 + 31 + 30 + 31, | ||
| 31 + 28 + 31 + 30 + 31 + 30, | ||
| 31 + 28 + 31 + 30 + 31 + 30 + 31, | ||
| 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31, | ||
| 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30, | ||
| 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31, | ||
| 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31 + 30, | ||
| }; | ||
|
|
||
| res = YEAR * (tm->year) + DAY * (tm->year + 3) / 4; | ||
| res += DAY * month[tm->month]; | ||
| if(tm->month > 1 && (!(tm->year % 4))) | ||
| res += DAY; | ||
| res += DAY * (tm->day - 1); | ||
| res += HOUR * tm->hour; | ||
| res += MINUTE * tm->minute; | ||
| res += tm->second; | ||
| return res; | ||
| } | ||
|
|
||
| static Time *cmos_time(void){ | ||
| static Time time; | ||
| do{ | ||
| time.second = CMOS_READ(0); | ||
| time.minute = CMOS_READ(2); | ||
| time.hour = CMOS_READ(4); | ||
| time.day = CMOS_READ(7); | ||
| time.month = CMOS_READ(8); | ||
| time.year = CMOS_READ(9); | ||
| }while(time.second != CMOS_READ(0)); | ||
| BCD_TO_BIN(time.second); | ||
| BCD_TO_BIN(time.minute); | ||
| BCD_TO_BIN(time.hour); | ||
| BCD_TO_BIN(time.day); | ||
| BCD_TO_BIN(time.month); | ||
| BCD_TO_BIN(time.year); | ||
| time.month--; | ||
| startup_time = mktime(&time); | ||
| return &time; | ||
| } | ||
| void clock_init(void){ | ||
| put_irq_handler(0,(IrqHandler)clock_handler); | ||
| cmos_time(); | ||
| outb_p(0x36,0x43); | ||
| outb_p(LATCH&0xff,0x40); | ||
| outb_p(LATCH>>8,0x40); | ||
| enable_irq(0); | ||
| } | ||
| int clock_main(void){ | ||
| Message m; | ||
| Time *time; | ||
| time = cmos_time(); | ||
|
|
||
| printk("Clock Task runing!\n"); | ||
| clock_init(); | ||
| while(1){ | ||
| recvie(ANY,&m); | ||
| switch(m.type){ | ||
| case HARD_INT:pick_proc();break;//printk("\erHARD_INT\ew\n");break; | ||
| case GET_TIME:printk("second:%d ",startup_time);printk("%d/%d/%d %d:%d:%d\n", | ||
| time->year + 2000,time->month + 1,time->day,time->hour,time->minute,time->second);break; | ||
| } | ||
| } | ||
| unready(act_proc); | ||
| printk("\eW\eoError:clock is unready!\n\eO\ew"); | ||
| while(1); | ||
| return 0; | ||
| } |
| @@ -0,0 +1,196 @@ | ||
|
|
||
|
|
||
| #include "vga.h" | ||
|
|
||
| #define MAX_CONSOLES 1 | ||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
| static unsigned long video_mem_base; /* base of video memory */ | ||
| static unsigned long video_num_columns; /* Number of text columns */ | ||
| static unsigned long video_num_lines; /* NUmber of text lines */ | ||
| static unsigned long video_size_row; /* Byte per row */ | ||
| static int fg_cons; /* */ | ||
|
|
||
| struct { | ||
| unsigned char attr; /* char attrib */ | ||
| unsigned char def_attr; /* default attrib */ | ||
| unsigned short erase_char; /* erase char and attrib */ | ||
| unsigned long mem_start; /* memory start */ | ||
| unsigned long mem_end; /* memory end */ | ||
| unsigned long top; /* screen top */ | ||
| unsigned long bottom; /* screen bottom */ | ||
| unsigned long pos; /* cursor position */ | ||
| unsigned int state; | ||
| }vc_cons[MAX_CONSOLES]; | ||
|
|
||
|
|
||
| /* The maco consult Linus */ | ||
|
|
||
| #define attr vc_cons[cons].attr | ||
| #define def_attr vc_cons[cons].def_attr | ||
| #define erase_char vc_cons[cons].erase_char | ||
| #define mem_start vc_cons[cons].mem_start | ||
| #define mem_end vc_cons[cons].mem_end | ||
| #define top vc_cons[cons].top | ||
| #define bottom vc_cons[cons].bottom | ||
| #define pos vc_cons[cons].pos | ||
| #define state vc_cons[cons].state | ||
|
|
||
|
|
||
| static inline void set_top(int cons){ | ||
|
|
||
| //cli(); | ||
| if(cons != fg_cons) return; | ||
| mc6845_write((0xff&(top - video_mem_base)>>9),START_ADDR_H); | ||
| mc6845_write(0xff&((top - video_mem_base)>>1),START_ADDR_L); | ||
| //sti(); | ||
|
|
||
| } | ||
|
|
||
| static inline void set_cur(int cons){ | ||
|
|
||
| //cli(); | ||
| if(cons != fg_cons) return; | ||
| mc6845_write(0xff&((pos - video_mem_base)>>9),CURSOR_H); | ||
| mc6845_write(0xff&((pos - video_mem_base)>>1),CURSOR_L); | ||
| //sti(); | ||
|
|
||
| } | ||
|
|
||
|
|
||
| static inline void scrup(int cons){ | ||
|
|
||
| top += video_size_row; | ||
| bottom += video_size_row; | ||
| //pos += video_size_row; | ||
|
|
||
| if(bottom > mem_end){ | ||
| __asm__ __volatile__("rep movsl\n\t\t" | ||
| "movl video_num_columns,%%ecx\n\t\t" | ||
| "rep stosw\n\t\t" | ||
| ::"c"(((video_num_lines - 1)*(video_size_row))>>2), | ||
| "D"(mem_start),"S"(top),"a"(erase_char) | ||
| ); | ||
| bottom -= top - mem_start; | ||
| pos -=top - mem_start; | ||
| top = mem_start; | ||
| }else{ | ||
| __asm__ __volatile__("rep stosw\n\t\t" | ||
| ::"D"(bottom),"c"(video_num_columns),"a"(erase_char)); | ||
| } | ||
|
|
||
| set_top(cons); | ||
| //set_cur(cons); | ||
| } | ||
|
|
||
| static inline void scrdown(int cons){ | ||
| if(top - video_size_row <= mem_start) return; | ||
| top -= video_size_row; | ||
| bottom -= video_size_row; | ||
| pos -= video_size_row; | ||
|
|
||
| set_top(cons); | ||
| set_cur(cons); | ||
| } | ||
|
|
||
| static inline void lf(int cons){ | ||
|
|
||
| if(pos + video_size_row > bottom) scrup(cons); | ||
| pos += video_size_row; | ||
| set_cur(cons); | ||
| } | ||
|
|
||
| static inline void cr(int cons){ | ||
| pos -= (pos - mem_start) % video_size_row; | ||
| set_cur(cons); | ||
| } | ||
|
|
||
| static inline void ri(int cons){ | ||
| if(pos - video_size_row < top) scrdown(cons); | ||
| pos -= video_size_row; | ||
| set_cur(cons); | ||
| } | ||
|
|
||
| static inline void set_attr(int cons,unsigned char _attr){ | ||
| attr = _attr; | ||
| } | ||
|
|
||
| static inline void del(int cons){ | ||
| if((pos - mem_start)% video_size_row){ | ||
| pos -= 2; | ||
| *(unsigned short *)pos = erase_char; | ||
| } | ||
| } | ||
|
|
||
|
|
||
| static inline void insert(int cons,unsigned char ch){ | ||
|
|
||
| *(unsigned short *)pos = ch|(attr<<8); | ||
| if(pos + 2 > bottom){ | ||
| scrup(cons); | ||
| } | ||
| pos += 2; | ||
| set_cur(cons); | ||
| } | ||
|
|
||
| extern void cons_print(int cons,const char * buf){ | ||
|
|
||
| unsigned char ch; | ||
|
|
||
| while((ch = (*buf++))){ | ||
| if(state == 1){ | ||
| switch(ch){ | ||
| case 'o':attr = (attr & 0xf0) | 0x00;break; | ||
| case 'O':attr = (attr & 0x0f) | 0x00;break; | ||
| case 'b':attr = (attr & 0xf0) | 0x01;break; | ||
| case 'B':attr = (attr & 0x0f) | 0x10;break; | ||
| case 'g':attr = (attr & 0xf0) | 0x02;break; | ||
| case 'G':attr = (attr & 0x0f) | 0x20;break; | ||
| case 'y':attr = (attr & 0xf0) | 0x03;break; | ||
| case 'Y':attr = (attr & 0x0f) | 0x30;break; | ||
| case 'r':attr = (attr & 0xf0) | 0x04;break; | ||
| case 'R':attr = (attr & 0x0f) | 0x40;break; | ||
| case 'p':attr = (attr & 0xf0) | 0x05;break; | ||
| case 'P':attr = (attr & 0x0f) | 0x50;break; | ||
| case 'h':attr = (attr & 0xf0) | 0x06;break; | ||
| case 'H':attr = (attr & 0x0f) | 0x60;break; | ||
| case 'w':attr = (attr & 0xf0) | 0x07;break; | ||
| case 'W':attr = (attr & 0x0f) | 0x70;break; | ||
| } | ||
| state = 0; | ||
| } | ||
| else if(ch == '\e') state = 1; | ||
| else if(ch == '\n'){ | ||
| lf(cons); | ||
| cr(cons); | ||
| }else{ | ||
| insert(cons,ch); | ||
| } | ||
| } | ||
| } | ||
|
|
||
| extern void cons_init(void){ | ||
|
|
||
| int cons = 0; | ||
|
|
||
| fg_cons = 0; | ||
| video_mem_base = 0xb8000; | ||
| video_num_lines = 25; | ||
| video_num_columns = 80; | ||
| video_size_row = video_num_columns << 1; | ||
|
|
||
| attr = 0xf; | ||
| state = 0; | ||
| erase_char = ' ' | 0xf<<8; | ||
|
|
||
| mem_start = video_mem_base; | ||
| mem_end = mem_start + 80*25*2*3; | ||
| top = ((mc6845_read(START_ADDR_H)<<9)|(mc6845_read(START_ADDR_L)<<1)) + mem_start; | ||
| bottom = top + 80*25*2; | ||
| pos = ((mc6845_read(CURSOR_H)<<9)|(mc6845_read(CURSOR_L)<<1)) + mem_start; | ||
|
|
||
| } |
| @@ -0,0 +1,9 @@ | ||
| #ifndef __DRIVER_H__ | ||
| #define __DRIVER_H__ | ||
|
|
||
| typedef struct driver{ | ||
| int dev; | ||
| int | ||
| }; | ||
|
|
||
| #endif |
| @@ -0,0 +1,44 @@ | ||
| #include <const.h> | ||
| #include <types.h> | ||
| #include <x86/io.h> | ||
| #include <sys/inter.h> | ||
| #include <stdio.h> | ||
| #include <stdlib.h> | ||
| #include <string.h> | ||
|
|
||
| extern void trap_init(void); | ||
| extern void mm_init(void); | ||
|
|
||
| /* */ | ||
| extern void disable_irq(int irq); | ||
| extern void enable_irq(int irq); | ||
| extern void put_irq_handler(int irq,IrqHandler handler); | ||
|
|
||
| extern int interrupt(pid_t dest,Message *m_ptr); | ||
|
|
||
| extern void sched(void); | ||
|
|
||
| extern Proc *act_proc; | ||
| extern Proc *proc_ptr; | ||
| extern IrqHandler irq_table[NR_IRQ_VECTORS]; | ||
|
|
||
| #define proc_number(rp) ((rp)->pid) | ||
| #define proc_addr(pid) (task[pid]) | ||
|
|
||
| extern Tss *tss; | ||
|
|
||
| /* */ | ||
| #define getcr3() ({ \ | ||
| Pointer _cr3; \ | ||
| asm("movl %%cr3,%0\n\t\t":"=a"(_cr3)); \ | ||
| _cr3; \ | ||
| }) | ||
|
|
||
| #define ldcr3(cr3) ({\ | ||
| asm("movl %0,%%cr3\n\t\t"::"a"(cr3));\ | ||
| }) | ||
|
|
||
| /* Task List */ | ||
| int clock_main(void); | ||
|
|
||
|
|
| @@ -0,0 +1,16 @@ | ||
| #include "kernel.h" | ||
|
|
||
| extern void cons_init(); | ||
| extern int printk(const char *fmt,...); | ||
| extern void proc_init(void); | ||
| int main(void){ | ||
|
|
||
| cli(); | ||
| cons_init(); | ||
| printk("\erHello \ebWorld!\n"); | ||
| mm_init(); | ||
| trap_init(); | ||
| proc_init(); | ||
| sti(); | ||
| hlt(); | ||
| } |
| @@ -0,0 +1,94 @@ | ||
| #include "kernel.h" | ||
| #include <multiboot.h> | ||
|
|
||
|
|
||
| #define clear_page(p) \ | ||
| asm("rep stosl\n\t\t"::"a"(0),"c"(0x1000 >> 2),"D"(p)); | ||
|
|
||
|
|
||
| Pointer MEMORY_END = 0; | ||
| Pointer MEMORY_MAP_END = 0; | ||
|
|
||
| unsigned char *mmap = (unsigned char *)MMAP_BASE; | ||
| /* get a free page in kernel space */ | ||
| Pointer get_free_page(void){ | ||
| while(1){ | ||
| for(int i = CONST_MEM >> 12;i < KMEM >> 12;i++){ | ||
| if(mmap[i] == 0){ | ||
| mmap[i]++; | ||
| /* clear the page */ | ||
| clear_page((i << 12)); | ||
| return (i << 12); | ||
| } | ||
| } | ||
| } | ||
| return 0; | ||
| } | ||
|
|
||
| /* free a page in space */ | ||
| void free_page(Pointer page){ | ||
| if(page < CONST_MEM) panic("Free Kernel Memory!"); | ||
| if(mmap[page >>12] == 0) panic("Free free Memory!"); | ||
| mmap[page >>12] --; | ||
| } | ||
|
|
||
|
|
||
|
|
||
| void open_pagination(void){ | ||
| Pointer *dir = (Pointer *)DIE_DIR; | ||
| Pointer *table = (Pointer *)DIE_TABLE; | ||
| Pointer page = 0; | ||
|
|
||
| memset((void *)dir,0,0x1000); | ||
| dir[0] = (Pointer)table | 7; | ||
| for(int i = 0;i < 1024;i++) table[i] = (i << 12) | 7; | ||
| for(int i = PAGE_OFFSET >> 22;i < (KMEM >> 22);i++){ | ||
| table = (Pointer *)((Pointer)table + 0x1000); | ||
| dir[i] = (Pointer)table | 7; | ||
| for(int i = 0;i < 1024;i++) table[i] = ((page++) << 12) | 7; | ||
| } | ||
| table = (Pointer *)(dir[1023] & (~0xcff)); | ||
| for(int i = 0;i < 1024;i++) table[i] = (1023 << 22) | (i << 12) | 7; | ||
|
|
||
| /* bios */ | ||
| __asm__("mov %0,%%cr3\n\t\t" | ||
| "mov %%cr0,%%eax\n\t\t" "or $0x80010000,%%eax\n\t" | ||
| "mov %%eax,%%cr0\n\t\t" | ||
| ::"a"(dir)); | ||
|
|
||
| } | ||
|
|
||
|
|
||
|
|
||
|
|
||
| extern multiboot_info_t *envp; | ||
| void mm_init(void){ | ||
|
|
||
| #define alow map->base_addr_low | ||
| #define ahigh map->base_addr_high | ||
| #define llow map->length_low | ||
| #define lhigh map->length_high | ||
| memory_map_t *map = (memory_map_t *)envp->mmap_addr; | ||
| memory_map_t *end = (memory_map_t *)(envp->mmap_addr + envp->mmap_length); | ||
|
|
||
| unsigned char busy = 100; | ||
|
|
||
| for(int i = 0;mmap + i < (unsigned char *)MMAP_END;i++) mmap[i] = 100; | ||
| for(;map < end;map++){ | ||
| if(map->type == 1){ | ||
| busy = 0; | ||
| MEMORY_END = alow + llow; | ||
| } else busy = 100; | ||
| for(Pointer i = alow >> 12;i < (alow + llow) >> 12;i++) mmap[i] = busy; | ||
| } | ||
| for(int i = 0;i < (CONST_MEM >> 12); i++) mmap[i] = 100; | ||
| if(MEMORY_END > KMEM ) MEMORY_MAP_END = KMEM; | ||
| else MEMORY_MAP_END = MEMORY_END; | ||
|
|
||
| open_pagination(); | ||
| #undef alow | ||
| #undef ahigh | ||
| #undef llow | ||
| #undef lhigh | ||
| } | ||
|
|
| @@ -0,0 +1,8 @@ | ||
| #include "kernel.h" | ||
|
|
||
| extern void panic(const char *s){ | ||
| printk("panic: %s\n",s); | ||
| cli(); | ||
| while(1); | ||
| sti(); | ||
| } |
| @@ -0,0 +1,18 @@ | ||
| #include <stdarg.h> | ||
| #include <stddef.h> | ||
| #include "kernel.h" | ||
|
|
||
| extern void cons_print(int cons,const char *buf); | ||
|
|
||
| static char buf[1024]; | ||
|
|
||
| extern int printk(const char *fmt,...){ | ||
| va_list args; | ||
| int i; | ||
|
|
||
| va_start(args,fmt); | ||
| i=vsprintf(buf,fmt,args); | ||
| cons_print(0,buf); | ||
| return i; | ||
|
|
||
| } |
| @@ -0,0 +1,223 @@ | ||
| #include "kernel.h" | ||
|
|
||
| #define istaskp(p) ((p)->pri == PRI_TASK) | ||
| #define isservep(p) ((p)->pri == PRI_SERVER) | ||
| #define isuserp(p) ((p)->pri == PRI_USER) | ||
| #define isnull(p) ((p) == NULL) | ||
|
|
||
| Proc *task[NR_TASKS]; | ||
| Proc *act_proc; | ||
| Proc *proc_ptr; | ||
|
|
||
| Proc *rdy_head[NR_PRI]; | ||
| Proc *rdy_tail[NR_PRI]; | ||
|
|
||
| Tss *tss; | ||
|
|
||
| static int isrecv(pid_t src,pid_t dest){ | ||
| if(src == ANY) return 1; | ||
| else return (src == dest); | ||
| } | ||
|
|
||
| void pick_proc(void){ | ||
| //Proc *rp; | ||
| for(int i = 0;i < NR_PRI;i++){ | ||
| if(NULL != rdy_head[i]){ | ||
| proc_ptr = rdy_head[i]; | ||
| return; | ||
| } | ||
| } | ||
| proc_ptr = proc_addr(IDLE); | ||
| } | ||
|
|
||
| void ready(Proc *rp){ | ||
| if(isnull(rp)) panic("\erReady \eb[\erprocess is <null>\eb]"); | ||
| if(isnull(rdy_head[rp->pri])) | ||
| rdy_head[rp->pri] = rp; | ||
| else | ||
| rdy_tail[rp->pri]->next = rp; | ||
| rp->next = NULL; | ||
| rdy_tail[rp->pri] = rp; | ||
| pick_proc(); | ||
| } | ||
|
|
||
| void unready(Proc *rp){ | ||
| Proc *xp; | ||
| if(isnull(rp)) panic("\erUnready \eb[\erprocess is <null>\eb]"); | ||
| if(NULL == (xp = rdy_head[rp->pri])) return; | ||
| if(xp == rp){ | ||
| rdy_head[rp->pri] = rp->next; | ||
| /* | ||
| if(rdy_tail[rp->pri] == rp) | ||
| rdy_tail[rp->pri] = NULL; | ||
| */ | ||
| }else{ | ||
| while(xp->next != rp) | ||
| if(NULL == (xp = xp->next)) return; | ||
| xp->next = xp->next->next; | ||
| if(rdy_tail[rp->pri] == rp) | ||
| rdy_tail[rp->pri] = xp; | ||
| } | ||
| if(proc_ptr == rp) pick_proc(); | ||
| hlt(); | ||
| //while(act_proc == rp); | ||
| } | ||
|
|
||
| int proc_send(pid_t dest,Message *m_ptr){ | ||
| Proc *rp,*sp; | ||
| sp = act_proc; | ||
| m_ptr->src = proc_number(sp); | ||
| if((rp = proc_addr(dest)) == NULL) return -1; | ||
| if((rp->flags & RECVIEING) && (rp->getfrom == proc_number(sp) || rp->getfrom == ANY )){ | ||
| memcpy(&(rp->message),m_ptr,sizeof(Message)); | ||
| rp->wait = m_ptr->src; | ||
| rp->flags &= ~(RECVIEING); | ||
| ready(rp); | ||
| unready(sp); | ||
| return 0; | ||
| } | ||
| Proc **sl; | ||
| sl = &rp->sendlink; | ||
| sp->sendlink = NULL; | ||
| memcpy(&(sp->message),m_ptr,sizeof(Message)); | ||
| while(*sl != NULL) sl = &((*sl)->sendlink); | ||
| *sl = sp; | ||
| sp->flags |= SENDING; | ||
| unready(sp); | ||
| return 0; | ||
| } | ||
|
|
||
| int interrupt(pid_t dest,Message *m_ptr){ | ||
| Proc *rp; | ||
| Interrput *inte; | ||
| m_ptr->src = HARDWORE; | ||
| if(NULL == (rp = proc_addr(dest))) panic("\erInterrupt \eb[\ersystem tasks don't found\eb]"); | ||
| if((rp->flags & RECVIEING)){ | ||
| memcpy(&(rp->message),m_ptr,sizeof(Message)); | ||
| rp->wait = HARDWORE; | ||
| rp->flags &= ~(RECVIEING); | ||
| ready(rp); | ||
| return 0; | ||
| } | ||
| if(NULL == (inte = malloc(sizeof(Interrput)))) panic("\erInterrput \eb[\ermemory is out\eb]"); | ||
| memcpy(&(inte->message),m_ptr,sizeof(Message)); | ||
| inte->next = rp->interruptlink; | ||
| rp->interruptlink = inte; | ||
| return 0; | ||
| } | ||
|
|
||
| int proc_receive(pid_t src,Message *m_ptr){ | ||
| Proc *rp,*np,**sp; | ||
| Interrput *inte; | ||
| rp = act_proc; | ||
| sp = &((rp)->sendlink); | ||
| np = rp->sendlink; | ||
|
|
||
| if((inte = rp->interruptlink)){ | ||
| rp->interruptlink = inte->next; | ||
| memcpy(m_ptr,&(inte->message),sizeof(Message)); | ||
| free(inte); | ||
| return 0; | ||
| } | ||
| while(np != NULL){ | ||
| if(isrecv(src,proc_number(np))){ | ||
| if((np->flags & SENDING)){ | ||
| *sp = np->sendlink; | ||
| memcpy(m_ptr,&(np->message),sizeof(Message)); | ||
| np->flags &= ~(SENDING); | ||
| ready(np); | ||
| return 0; | ||
| } | ||
| } | ||
| sp = &((*sp)->sendlink); | ||
| np = np->sendlink; | ||
| } | ||
| rp->flags |= RECVIEING; | ||
| rp->getfrom = src; | ||
| unready(rp); | ||
| memcpy(m_ptr,&(rp->message),sizeof(Message)); | ||
| if(rp->wait != HARDWORE) ready(proc_addr(rp->wait)); | ||
| return 0; | ||
| } | ||
|
|
||
| void sched(void){ | ||
| if(rdy_head[PRI_USER] == NULL)return; | ||
|
|
||
| rdy_tail[PRI_USER]->next = rdy_head[PRI_USER]; | ||
| rdy_tail[PRI_USER] = rdy_head[PRI_USER]; | ||
| rdy_head[PRI_USER] = rdy_head[PRI_USER]->next; | ||
| rdy_tail[PRI_USER]->next = NULL; | ||
| pick_proc(); | ||
| } | ||
|
|
||
| int system_main(void){ | ||
| Message m; | ||
| m.type = GET_TIME; | ||
| send(CLOCK_PID,&m); | ||
| unready(act_proc); | ||
| while(1); | ||
| } | ||
|
|
||
| Proc *make_proc(pid_t pid,const char *pname,Pointer data,Pointer code,int pri,int (*pentry)()){ | ||
| Proc *p; | ||
| p = (Proc*)get_free_page(); | ||
| p->pid = pid; | ||
| p->pri = pri; | ||
| p->core = getcr3(); | ||
| p->esp0 = (Pointer)p + sizeof(Task); | ||
| strcpy(p->pname,pname); | ||
| p->sendlink = NULL; | ||
| p->registers = (Registers*)(p->esp0 - 0x100); | ||
| p->interruptlink = NULL; | ||
| memcpy(p->registers,&(Registers){ | ||
| .gs = data, | ||
| .fs = data, | ||
| .ds = data, | ||
| .es = data, | ||
| .edi = 0, | ||
| .esi = 0, | ||
| .ebp = 0, | ||
| .ebx = 0, | ||
| .edx = 0, | ||
| .ecx = 0, | ||
| .eax = 0, | ||
| .eip = (long)(pentry), | ||
| .cs = code, | ||
| .eflags = 0x200, | ||
| },sizeof(Registers)); | ||
| task[pid] = p; | ||
| ready(p); | ||
| return p; | ||
| } | ||
|
|
||
| void proc_init(){ | ||
|
|
||
| Pointer tr = TR_DESC; | ||
| Proc *idle; | ||
|
|
||
| for(int i = 0;i < NR_PRI;i++){ | ||
| rdy_head[i] = rdy_tail[i] = NULL; | ||
| } | ||
| idle = (Proc *)get_free_page(); | ||
| idle->pid = IDLE; | ||
| idle->core = getcr3(); | ||
| idle->esp0 = (Pointer)(idle) + sizeof(Task); | ||
| strcpy(idle->pname,"idle"); | ||
| idle->sendlink = NULL; | ||
| idle->interruptlink = NULL; | ||
| act_proc = idle; | ||
| task[IDLE] = idle; | ||
|
|
||
| make_proc(CLOCK_PID,"CLock",KERNEL_DATA,KERNEL_CODE,PRI_TASK,clock_main); | ||
| make_proc(SYSTEM_PID,"Sytem",KERNEL_DATA,KERNEL_CODE,PRI_TASK,system_main); | ||
|
|
||
| tss = (Tss*)(TSS_TABLE); | ||
| tss->ss0 = KERNEL_DATA; | ||
| tss->esp0 = idle->esp0; | ||
| //tss->gs = tss->fs = tss->es = tss->ds = USER_DATE; | ||
| tss->ldt = 0; | ||
| tss->io = 0xffff0000; | ||
| tss->eflags = 0x200; | ||
| asm("ltr %0"::"m"(tr)); | ||
| pick_proc(); | ||
| } |
| @@ -0,0 +1,167 @@ | ||
| /* | ||
| * (C) 2011-10 | ||
| * Email:LuoZhongYao@gmail.com | ||
| * 每天都对自己说:"Good luck!" | ||
| * 该程序负责初始化内核工作环境,是内核执行的第一个程序. | ||
| * 初始化内容包括,重新安排GDT(由multiboot规范知道,现在已经有一个GDT了),并且 | ||
| * 对8259进行初始化,本质上来说,该程序只是原gmL的setup去除进入保护模式和添加 | ||
| * multiboot支持而已. | ||
| * 使用multiboot的好处是可以使用现存的文件系统,而不用去研究它,可以被其 | ||
| * 引导器引导.内核大小没有限制.反正很多啦,所以我个人建议,有写内核的同学,必 | ||
| * 要参考multiboot,并遵守它. | ||
| */ | ||
| /* 汇编代码 */ | ||
| #define ASM | ||
| /* multiboot规范头文件,该文件直接拷贝于grub_0.98/docs/multiboot.h */ | ||
| #include <multiboot.h> | ||
| #include <const.h> | ||
|
|
||
| #define CreateSection(base,limit,attr) \ | ||
| .short limit&0xffff;\ | ||
| .short base&0xffff; \ | ||
| .byte (base>>16)&0xff;\ | ||
| .short (attr)|((limit>>8)&0x0f00);\ | ||
| .byte (base>>24)&0xff;\ | ||
| //代码段相关属性宏定义 | ||
| #define CODE_READ 0x009a //代码段可读 | ||
| #define CODE_C 0x009c //一致代码段 | ||
| #define CODE_G 0x8098 //使用4GB的界限 | ||
| #define CODE_D 0x4098 //默认使用32位地址 | ||
| //数据段属性 | ||
| #define DATA_WRITE 0x0092 //数据段可写 | ||
| #define DATA_E 0x0094 //向下扩展 | ||
| #define DATA_G 0x8090 //使用32界限 | ||
| #define DATA_B 0x4090 //堆栈段使用ESP等32位指针,向下扩展,指明栈上限4GB | ||
| //TSS描述符 | ||
| #define TSS_G 0x8089 //TSS使用4GB界限,通常这个是用不到的 | ||
| #define TSS 0x0089 //说明这是一个TSS段 | ||
| //权限 | ||
| #define R0 0x0000 //ring 0 | ||
| #define R1 0x0020 // | ||
| #define R2 0x0040 // | ||
| #define R3 0x0060 //ring 3 | ||
| #define _STACK 0x3ffff0 | ||
|
|
||
| GDT_LEN = gdt_end-gdt_start | ||
| /* | ||
| #define io_delay \ | ||
| jmp .+2 \ | ||
| jmp .+2 | ||
| */ | ||
| /* IO延时宏 */ | ||
| .macro io_delay | ||
| jmp .+2 | ||
| jmp .+2 | ||
| .endm | ||
| .text | ||
| .globl _start,envp,main | ||
| _start: | ||
| jmp start | ||
| /* multiboot 要求4字节对齐 */ | ||
| .align 4 | ||
| multiboot_header: | ||
| /* multiboot header magic 详情请查阅multiboot */ | ||
| .long MULTIBOOT_HEADER_MAGIC | ||
| /* multiboot header flags multiboot为你做什么服务,色情服务不在这个范围内*/ | ||
| /* 同时也告诉了multiboot你是什么款式的人,oh,程序 */ | ||
| .long MULTIBOOT_HEADER_FLAGS | ||
| /* multiboot header checksum ,详情请看multiboot */ | ||
| /* 我猜测引导器就是靠checksum和magic来识别multiboot header的. */ | ||
| .long -(MULTIBOOT_HEADER_MAGIC+MULTIBOOT_HEADER_FLAGS) | ||
| /* 如果不是ELF文件格式,下面的信息就是必须的,这个__ELF__不知道是在哪里定义的 */ | ||
| /* 不过我的二进制,就算下面这些提供了,grub还是不鸟我,所以我也不鸟二进制 */ | ||
| #ifndef __ELF__ | ||
| /* multiboot header addr,hi哥们,你在哪? */ | ||
| .long multiboot_header | ||
| /* Load addr .text在OSimage中的偏移 */ | ||
| .long _start | ||
| /* Load end addr 引导到OSimage中那个位置,如果为零,引导整个OS Image */ | ||
| .long _edata | ||
| /* bss段的结束地址.Boot loader将其清零,并且保证不被覆盖 */ | ||
| .long _end | ||
| /* Boot loader 引导完后将跳转到这里执行 */ | ||
| .long _start | ||
| #endif | ||
| start: | ||
| cli | ||
| /* | ||
| mov $0x3FFFF0,%esp | ||
| push %ebx | ||
| */ | ||
| /* 保存由Boot loader提供的信息地址 */ | ||
| mov %ebx,envp | ||
| /* 8259,写过很多次了,懒得在写,不懂的可以google,或者Email我 */ | ||
| /* 唯一说一点的就是外部中断0x20~0x30 */ | ||
| mov $0x11,%al | ||
| out %al,$0x20 | ||
| io_delay | ||
| out %al,$0xa0 | ||
| io_delay | ||
|
|
||
| mov $0x20,%al | ||
| out %al,$0x21 | ||
| io_delay | ||
| mov $0x28,%al | ||
| out %al,$0xa1 | ||
| io_delay | ||
|
|
||
| mov $0x04,%al | ||
| out %al,$0x21 | ||
| io_delay | ||
| mov $0x2,%al | ||
| out %al,$0xa1 | ||
| io_delay | ||
|
|
||
| mov $0x1,%al | ||
| out %al,$0x21 | ||
| io_delay | ||
| out %al,$0xa1 | ||
| io_delay | ||
|
|
||
| /* 屏蔽外部中断 */ | ||
| mov $0xFF,%al | ||
| out %al,$0x21 | ||
| io_delay | ||
| out %al,$0xa1 | ||
| io_delay | ||
| /* 重新设置GDT,GDT被放置到0x101000处 */ | ||
| mov $GDT_TABLE,%edi | ||
| mov $gdt_start,%esi | ||
| mov $GDT_LEN,%ecx | ||
| shr $2,%ecx | ||
| cld | ||
| rep movsl | ||
| lgdt gdt | ||
| lidt idt | ||
| /* 刷新环境 */ | ||
| ljmp $0x8,$new_env | ||
| new_env: | ||
| mov $0x10,%eax | ||
| mov %eax,%ds | ||
| mov %eax,%es | ||
| mov %eax,%ss | ||
| mov %eax,%fs | ||
| mov %eax,%gs | ||
| mov $_STACK,%esp | ||
| call main | ||
| 0: | ||
| hlt | ||
| jmp 0b | ||
|
|
||
| .data | ||
| envp: | ||
| .long 0x0 | ||
| gdt: | ||
| .word 0xFFFF | ||
| .long GDT_TABLE | ||
| idt: | ||
| .word 256*8-1 | ||
| .long IDT_TABLE | ||
| gdt_start: | ||
| CreateSection(0xAA,0,0XBB); | ||
| CreateSection(0x0,0xFFFFF,CODE_READ|CODE_D|CODE_G) | ||
| CreateSection(0x0,0xFFFFF,DATA_WRITE|DATA_G|R0|DATA_B); | ||
| CreateSection(0x0,0xFFFFF,CODE_READ|CODE_D|CODE_G|R3); | ||
| CreateSection(0x0,0xFFFFF,DATA_WRITE|DATA_G|R3|DATA_B); | ||
| CreateSection(TSS_TABLE,0x100,TSS|R3); | ||
| gdt_end: |
| @@ -0,0 +1,255 @@ | ||
| #include "kernel.h" | ||
| #include <sys/sys.h> | ||
|
|
||
| #define INT_GATE 0x8e00 | ||
| #define TRA_GATE 0x8f00 | ||
| #define TR_GATE 0x8500 | ||
| #define IDT_R0 0x0000 | ||
| #define IDT_R1 0x2000 | ||
| #define IDT_R2 0x4000 | ||
| #define IDT_R3 0x6000 | ||
|
|
||
|
|
||
| extern void divide_error(long,long *); | ||
| extern void single_step_exception(long,long *); | ||
| extern void nmi(long,long *); | ||
| extern void breakpoint_exception(long,long *); | ||
| extern void overflow(long,long *); | ||
| extern void bounds_check(long,long *); | ||
| extern void inval_opcode(long,long *); | ||
| extern void copr_not_available(long,long *); | ||
| extern void double_fault(long,long *); | ||
| extern void copr_seg_overrun(long,long *); | ||
| extern void inval_tss(long,long *); | ||
| extern void segment_not_present(long,long *); | ||
| extern void stack_exception(long,long *); | ||
| extern void general_protection(long,long *); | ||
| extern void page_fault(long,long *); | ||
| extern void copr_error(long,long *); | ||
| extern void none(long,long *); | ||
|
|
||
| extern void hwint00(void); | ||
| extern void hwint01(void); | ||
| extern void hwint02(void); | ||
| extern void hwint03(void); | ||
| extern void hwint04(void); | ||
| extern void hwint05(void); | ||
| extern void hwint06(void); | ||
| extern void hwint07(void); | ||
| extern void hwint08(void); | ||
| extern void hwint09(void); | ||
| extern void hwint10(void); | ||
| extern void hwint11(void); | ||
| extern void hwint12(void); | ||
| extern void hwint13(void); | ||
| extern void hwint14(void); | ||
| extern void hwint15(void); | ||
| extern int sys_call(int EAX,int EBX,int ECX,int EDX); | ||
|
|
||
|
|
||
| static unsigned long (* const idt)[2] = (unsigned long (*const)[2])(IDT_TABLE); | ||
|
|
||
| IrqHandler irq_table[NR_IRQ_VECTORS]; | ||
|
|
||
| #define set_int(nr,func,section,attr) {\ | ||
| idt[nr][0] = ((((unsigned int)func)&0xffff)|((unsigned short )(section)<<16));\ | ||
| idt[nr][1] = ((((unsigned int)func)&0xffff0000)|(unsigned short)(attr));\ | ||
| } | ||
|
|
||
|
|
||
| #define exit(n) panic("oop:-_-|\n"); | ||
| static inline void die(char *str,long *reg,long nr){ | ||
| printk("TRAP: %s %d.\nPROC:%d,%s\n",str,nr,act_proc->pid,act_proc->pname); | ||
| panic("^-^"); | ||
| } | ||
|
|
||
| extern void do_divide_error(long code,long *reg){ | ||
| die("divede error",reg,code); | ||
| } | ||
|
|
||
| extern void do_debug(long code,long *reg){ | ||
| die("debug traps",reg,code); | ||
| printk("This debug!,But the code no ready![TRAP]\n"); | ||
| } | ||
|
|
||
| extern void do_nmi(long code,long *reg){ | ||
| die("nmi error!",reg,code); | ||
| } | ||
|
|
||
| extern void do_breakpoint(long code,long *reg){ | ||
| die("breakpoint traps.",reg,code); | ||
| printk("code no ready![TRAP]\n"); | ||
| } | ||
| extern void do_overflow(long code,long *reg){ | ||
| die("overflow",reg,code); | ||
| } | ||
|
|
||
| extern void do_bounds_check(long code,long *reg){ | ||
| die("bounds",reg,code); | ||
| } | ||
|
|
||
| extern void do_inval_opcode(long code,long *reg){ | ||
| die("invalid operand",reg,code); | ||
| } | ||
|
|
||
| extern void do_copr_not_available(long code,long *reg){ | ||
| die("copr not available.",reg,code); | ||
| } | ||
|
|
||
| extern void do_double_fault(long code,long *reg){ | ||
| die("double fault",reg,code); | ||
| } | ||
|
|
||
| extern void do_copr_seg_overrun(long code,long *reg){ | ||
| die("copr segment overrun",reg,code); | ||
| } | ||
|
|
||
| extern void do_inval_tss(long code,long *reg){ | ||
| die("inval tss",reg,code); | ||
| } | ||
|
|
||
| extern void do_segment_not_present(long code,long *reg){ | ||
| die("segment not present",reg,code); | ||
| } | ||
|
|
||
| extern void do_stack_exception(long code,long *reg){ | ||
| die("stack segment",reg,code); | ||
| } | ||
|
|
||
| extern void do_general_protection(long code,long *reg){ | ||
| die("general protection",reg,code); | ||
| } | ||
|
|
||
| extern void do_page_fault(long code,long *reg){ | ||
| Message m = {}; | ||
|
|
||
| __asm__("movl %%cr2,%0":"=r"(m.cr2)); | ||
|
|
||
| } | ||
|
|
||
| extern void do_copr_error(long code,long *reg){ | ||
| die("copr error",reg,code); | ||
| } | ||
|
|
||
| extern void do_none(long code,long *reg){ | ||
| die("what the fuck!",reg,code); | ||
| } | ||
|
|
||
| extern void _null(void){ | ||
| // die("-_-!",1); | ||
| ; | ||
| } | ||
|
|
||
| extern void do_keyboard(void){ | ||
| int _ch; | ||
| const char key[]=" `1234567890-=\15\tqwertyuiop[] asdfghjkl;' \r zxcvbnm,./ "; | ||
| _ch = inb(0x60); | ||
| if(_ch<sizeof(key)); | ||
| //printk("%c",key[_ch]); | ||
| } | ||
|
|
||
| extern void disable_irq(int irq){ | ||
| unsigned char mask; | ||
| unsigned char ctl; | ||
| if(NR_IRQ_VECTORS < irq || 0 > irq) | ||
| panic("invalid irq disable_irq"); | ||
|
|
||
| if(irq > 7){ | ||
| mask = 1 << (irq - 7); | ||
| ctl = INT2_CTLMASK; | ||
| }else{ | ||
| mask = 1 << irq; | ||
| ctl = INT_CTLMASK; | ||
| } | ||
| cli(); | ||
| mask |= inb(ctl); | ||
| outb(ctl,mask); | ||
| sti(); | ||
| } | ||
|
|
||
| extern void enable_irq(int irq){ | ||
| unsigned char mask; | ||
| unsigned char ctl; | ||
| if(NR_IRQ_VECTORS < irq || 0 > irq) | ||
| panic("invalid irq disable_irq"); | ||
|
|
||
| if(irq > 7){ | ||
| mask = ~(1 << (irq - 7)); | ||
| ctl = INT2_CTLMASK; | ||
| }else{ | ||
| mask = ~(1 << irq); | ||
| ctl = INT_CTLMASK; | ||
| } | ||
| cli(); | ||
| mask &= inb(ctl); | ||
| outb(ctl,mask); | ||
| sti(); | ||
| } | ||
|
|
||
| static int spurious_irq(int irq){ | ||
| if(irq < 0 || irq >= NR_IRQ_VECTORS) | ||
| panic("invalid call to spurious_irq"); | ||
| printk("spurious irq %d \n",irq); | ||
| return 1; | ||
| } | ||
|
|
||
| extern void put_irq_handler(int irq,IrqHandler handler){ | ||
| if(irq < 0 || irq >= NR_IRQ_VECTORS) | ||
| panic("invalid call to put_irq_handler"); | ||
| if(irq_table[irq] == handler) | ||
| return; | ||
| if(irq_table[irq] != spurious_irq) | ||
| panic("attempt to register second irq handler for irq"); | ||
| disable_irq(irq); | ||
| irq_table[irq] = handler; | ||
| enable_irq(irq); | ||
| } | ||
|
|
||
| extern void trap_init(void){ | ||
|
|
||
| /* install defualt int */ | ||
| for(int i = 0;i<256;i++) set_int(i,none,KERNEL_CODE,(INT_GATE|IDT_R0)); | ||
| set_int(0,divide_error,KERNEL_CODE,((TRA_GATE|IDT_R0))); | ||
| set_int(1,single_step_exception,KERNEL_CODE,(TRA_GATE|IDT_R0)); | ||
| set_int(2,nmi,KERNEL_CODE,(INT_GATE|IDT_R0)); | ||
| set_int(3,breakpoint_exception,KERNEL_CODE,(TRA_GATE|IDT_R0)); | ||
| set_int(4,overflow,KERNEL_CODE,(TRA_GATE|IDT_R0)); | ||
| set_int(5,bounds_check,KERNEL_CODE,(TRA_GATE|IDT_R0)); | ||
| set_int(6,inval_opcode,KERNEL_CODE,(TRA_GATE|IDT_R0)); | ||
| set_int(7,copr_not_available,KERNEL_CODE,(TRA_GATE|IDT_R0)); | ||
| set_int(8,double_fault,KERNEL_CODE,(TRA_GATE|IDT_R0)); | ||
| set_int(9,copr_seg_overrun,KERNEL_CODE,(TRA_GATE|IDT_R0)); | ||
| set_int(10,inval_tss,KERNEL_CODE,(TRA_GATE|IDT_R0)); | ||
| set_int(11,segment_not_present,KERNEL_CODE,(TRA_GATE|IDT_R0)); | ||
| set_int(12,stack_exception,KERNEL_CODE,(TRA_GATE|IDT_R0)); | ||
| set_int(13,general_protection,KERNEL_CODE,(TRA_GATE|IDT_R0)); | ||
| set_int(14,page_fault,KERNEL_CODE,(TRA_GATE|IDT_R0)); | ||
| set_int(16,copr_error,KERNEL_CODE,(TRA_GATE|IDT_R0)); | ||
|
|
||
|
|
||
| set_int(0x20,hwint00,KERNEL_CODE,(TRA_GATE|IDT_R0)); | ||
| set_int(0x21,hwint01,KERNEL_CODE,(TRA_GATE|IDT_R0)); | ||
| set_int(0x22,hwint02,KERNEL_CODE,(TRA_GATE|IDT_R0)); | ||
| set_int(0x23,hwint03,KERNEL_CODE,(TRA_GATE|IDT_R0)); | ||
| set_int(0x24,hwint04,KERNEL_CODE,(TRA_GATE|IDT_R0)); | ||
| set_int(0x25,hwint05,KERNEL_CODE,(TRA_GATE|IDT_R0)); | ||
| set_int(0x26,hwint06,KERNEL_CODE,(TRA_GATE|IDT_R0)); | ||
| set_int(0x27,hwint07,KERNEL_CODE,(TRA_GATE|IDT_R0)); | ||
| set_int(0x28,hwint08,KERNEL_CODE,(TRA_GATE|IDT_R0)); | ||
| set_int(0x29,hwint09,KERNEL_CODE,(TRA_GATE|IDT_R0)); | ||
| set_int(0x2a,hwint10,KERNEL_CODE,(TRA_GATE|IDT_R0)); | ||
| set_int(0x2b,hwint11,KERNEL_CODE,(TRA_GATE|IDT_R0)); | ||
| set_int(0x2c,hwint12,KERNEL_CODE,(TRA_GATE|IDT_R0)); | ||
| set_int(0x2d,hwint13,KERNEL_CODE,(TRA_GATE|IDT_R0)); | ||
| set_int(0x2e,hwint14,KERNEL_CODE,(TRA_GATE|IDT_R0)); | ||
| set_int(0x2f,hwint15,KERNEL_CODE,(TRA_GATE|IDT_R0)); | ||
|
|
||
| set_int(0x80,sys_call,KERNEL_CODE,(TRA_GATE|IDT_R3)); | ||
|
|
||
| for(int i = 0;i < NR_IRQ_VECTORS;i++) irq_table[i] = spurious_irq; | ||
| Registers *clock_handler(Registers *); | ||
| irq_table[0] = (IrqHandler)clock_handler; | ||
|
|
||
| outb_p(~(0x1),INT_CTLMASK); | ||
| //outb_p(0x0,INT2_CTLMASK); | ||
| } |
| @@ -0,0 +1,40 @@ | ||
| #ifndef __VGA_H__ | ||
| #define __VGA_H__ | ||
| #include <x86/io.h> | ||
|
|
||
| /* VGA register port */ | ||
|
|
||
| #define VGA_ADDR 0x03d4 /* vga address port */ | ||
| #define VGA_DATA 0x03d5 /* vga data port */ | ||
| #define VGA_MODE 0x03d8 /* select vga model */ | ||
| #define VGA_PALLET 0x03d9 /* vga pallet */ | ||
| #define VGA_STATE 0x03da /* vga display state register */ | ||
| #define VGA_RESET_LP 0x03db /* reset light pen */ | ||
| #define VGA_SET_LP 0x03dc /* */ | ||
|
|
||
| #define START_ADDR_H 0x0c /* reg index of video memory start addr High*/ | ||
| #define START_ADDR_L 0x0d /* reg index of video memory start addr Low */ | ||
| #define CURSOR_H 0x0e /* reg index of cursor position Hight */ | ||
| #define CURSOR_L 0x0f /* reg index of cursor position Low */ | ||
|
|
||
| /* CGA model console register*/ | ||
|
|
||
|
|
||
| /* mc6845 data register */ | ||
|
|
||
| /* write\read mc6845 register */ | ||
|
|
||
| #define mc6845_read(port) ({\ | ||
| unsigned char _d = 0; \ | ||
| outb_p((port),VGA_ADDR); \ | ||
| _d = inb_p(VGA_DATA); \ | ||
| _d; \ | ||
| }) | ||
|
|
||
| #define mc6845_write(data,port) ({\ | ||
| outb_p((port),VGA_ADDR); \ | ||
| outb_p((data),VGA_DATA); \ | ||
| }) | ||
|
|
||
|
|
||
| #endif |
| @@ -0,0 +1,325 @@ | ||
|
|
||
|
|
||
| # | ||
| # | ||
| # X86硬件相关处理包括x86中断,时钟中断,硬件中断等入口,系统调用入口也在该文件处理 | ||
| # | ||
| # | ||
| #include <const.h> | ||
|
|
||
| .globl divide_error # 除法出错 | ||
| .globl single_step_exception # 单步异常 | ||
| .globl nmi # nmi | ||
| .globl breakpoint_exception # 断点 | ||
| .globl overflow # 溢出 | ||
| .globl bounds_check # 边界检测 | ||
| .globl inval_opcode # 无效操作码 | ||
| .globl copr_not_available # 协处理器无效 | ||
| .globl double_fault # 双重错误 | ||
| .globl copr_seg_overrun # 协处理器段越界 | ||
| .globl inval_tss # 无效的任务段 | ||
| .globl segment_not_present # 段不存在 | ||
| .globl stack_exception # 栈异常 | ||
| .globl general_protection # 常规错误 | ||
| .globl page_fault # 页异常 | ||
| .globl copr_error # 协处理器错误 | ||
| .globl none | ||
| .globl sys_call | ||
| .globl switch_proc | ||
|
|
||
| .globl _null | ||
| .globl do_keybord | ||
| .globl do_call | ||
|
|
||
| .globl hwint00 | ||
| .globl hwint01 | ||
| .globl hwint02 | ||
| .globl hwint03 | ||
| .globl hwint04 | ||
| .globl hwint05 | ||
| .globl hwint06 | ||
| .globl hwint07 | ||
| .globl hwint08 | ||
| .globl hwint09 | ||
| .globl hwint10 | ||
| .globl hwint11 | ||
| .globl hwint12 | ||
| .globl hwint13 | ||
| .globl hwint14 | ||
| .globl hwint15 | ||
|
|
||
| .globl jiffies | ||
|
|
||
| .globl NR_syscalls,sys_call_table | ||
| .globl irq_table,act_registers,act_core | ||
|
|
||
|
|
||
|
|
||
| .macro save | ||
|
|
||
| pushal | ||
| pushl %es | ||
| pushl %ds | ||
| pushl %fs | ||
| pushl %gs | ||
| movl $0x10,%eax | ||
| movl %eax,%ds | ||
| movl %eax,%es | ||
| movl %eax,%fs | ||
| movl %eax,%gs | ||
| .endm | ||
|
|
||
| .macro recov | ||
| popl %gs | ||
| popl %fs | ||
| popl %ds | ||
| popl %es | ||
| popal | ||
| .endm | ||
|
|
||
| .text | ||
| # 除法出错处理 | ||
| divide_error: | ||
| push $0 #人工设置错误号 | ||
| pushl $do_divide_error | ||
| error_code: | ||
| xchgl %eax,4(%esp) #保存%eax,并将错误号放入%eax | ||
| pushl %ecx | ||
| pushl %edx | ||
| xchgl %ebx,8(%esp) #保存%ebx,并将处理函数指针放入%ebx | ||
| pushl %ebp | ||
| pushl %esi | ||
| pushl %edi | ||
| pushl %es | ||
| pushl %ds | ||
| pushl %fs | ||
| pushl %gs | ||
| pushl %esp | ||
| pushl %eax | ||
| movl $0x10,%eax | ||
| movw %ax,%ds | ||
| movw %ax,%es | ||
| movw %ax,%fs | ||
| call *%ebx | ||
| addl $8,%esp | ||
| popl %gs | ||
| popl %fs | ||
| popl %ds | ||
| popl %es | ||
| popl %edi | ||
| popl %esi | ||
| popl %ebp | ||
| popl %ebx | ||
| popl %edx | ||
| popl %ecx | ||
| popl %eax | ||
| iret | ||
|
|
||
| # 调试中断 | ||
| single_step_exception: | ||
| pushl $0 | ||
| pushl $do_debug | ||
| jmp error_code | ||
|
|
||
| #_nmi | ||
| nmi: | ||
| pushl $0 | ||
| pushl $do_nmi | ||
| jmp error_code | ||
|
|
||
| breakpoint_exception: | ||
| pushl $0 | ||
| pushl $do_breakpoint | ||
| jmp error_code | ||
|
|
||
| overflow: | ||
| pushl $0 | ||
| pushl $do_overflow | ||
| jmp error_code | ||
|
|
||
| bounds_check: | ||
| pushl $0 | ||
| push $do_bounds_check | ||
| jmp error_code | ||
|
|
||
| inval_opcode: | ||
| pushl $0 | ||
| pushl $do_inval_opcode | ||
| jmp error_code | ||
|
|
||
| copr_not_available: | ||
| pushl $0 | ||
| pushl $do_copr_not_available | ||
| jmp error_code | ||
|
|
||
| double_fault: | ||
| pushl $do_double_fault | ||
| jmp error_code | ||
|
|
||
| copr_seg_overrun: | ||
| pushl $0 | ||
| pushl $do_copr_seg_overrun | ||
| jmp error_code | ||
|
|
||
| inval_tss: | ||
| pushl $do_inval_tss | ||
| jmp error_code | ||
|
|
||
| segment_not_present: | ||
| pushl $do_segment_not_present | ||
| jmp error_code | ||
|
|
||
| stack_exception: | ||
| pushl $do_stack_exception | ||
| jmp error_code | ||
|
|
||
| general_protection: | ||
| pushl $do_general_protection | ||
| jmp error_code | ||
|
|
||
| page_fault: | ||
| pushl $do_page_fault | ||
| jmp error_code | ||
|
|
||
| copr_error: | ||
| pushl $0 | ||
| pushl $do_copr_error | ||
| jmp error_code | ||
|
|
||
| none: | ||
| pushl $0 | ||
| pushl $do_none | ||
| jmp error_code | ||
|
|
||
| # hwint01-07 | ||
| # | ||
| #define hwint_master(irq) \ | ||
| save; \ | ||
| inb $INT2_CTLMASK,%al; \ | ||
| orb $(1<<(irq)),%al; \ | ||
| outb %al,$INT_CTLMASK; \ | ||
| movb $0x20,%al; \ | ||
| outb %al,$INT_CTL; \ | ||
| movl $irq,%eax;\ | ||
| sti; \ | ||
| push $irq; \ | ||
| call *irq_table(,%eax,4); \ | ||
| addl $4,%esp; \ | ||
| cli; \ | ||
| inb $INT_CTLMASK,%al; \ | ||
| andb $(~(1<<(irq))),%al; \ | ||
| outb %al,$INT_CTLMASK; \ | ||
| recov; \ | ||
| iret; | ||
|
|
||
| hwint00: | ||
| save; | ||
| inb $INT2_CTLMASK,%al; | ||
| orb 1,%al; | ||
| outb %al,$INT_CTLMASK; | ||
| movb $0x20,%al; | ||
| outb %al,$INT_CTL; | ||
|
|
||
| incl jiffies | ||
|
|
||
| #sti; | ||
| pushl %esp | ||
| movl $0,%eax | ||
| call *irq_table(,%eax,4) //不用恢复ESP | ||
| movl %eax,%esp | ||
| 0: | ||
| inb $INT_CTLMASK,%al; | ||
| andb $(~1),%al; | ||
| outb %al,$INT_CTLMASK; | ||
| recov; | ||
| iret; | ||
|
|
||
| hwint01: | ||
| hwint_master(1); | ||
| hwint02: | ||
| hwint_master(2); | ||
| hwint03: | ||
| hwint_master(3); | ||
| hwint04: | ||
| hwint_master(4); | ||
| hwint05: | ||
| hwint_master(5); | ||
| hwint06: | ||
| hwint_master(6); | ||
| hwint07: | ||
| hwint_master(7); | ||
| # hwinnt09-15 | ||
| #define hwint_slave( irq) \ | ||
| save; \ | ||
| inb $INT2_CTLMASK,%al; \ | ||
| orb $(1<<(irq-8)),%al; \ | ||
| outb %al,$INT2_CTLMASK; \ | ||
| movb $0x20,%al; \ | ||
| outb %al,$INT_CTL; \ | ||
| jmp .+2; \ | ||
| outb %al,$INT2_CTL; \ | ||
| movl $irq,%eax;\ | ||
| sti; \ | ||
| pushl $irq; \ | ||
| call *irq_table(,%eax,4); \ | ||
| addl $4,%esp;\ | ||
| cli; \ | ||
| inb $INT2_CTLMASK,%al; \ | ||
| andb $(~(1<<(irq-8))),%al; \ | ||
| outb %al,$INT2_CTLMASK; \ | ||
| recov; \ | ||
| iret; | ||
| hwint08: | ||
| hwint_slave(8); | ||
| hwint09: | ||
| hwint_slave(9); | ||
| hwint10: | ||
| hwint_slave(10); | ||
| hwint11: | ||
| hwint_slave(11); | ||
| hwint12: | ||
| hwint_slave(12); | ||
| hwint13: | ||
| hwint_slave(13); | ||
| hwint14: | ||
| hwint_slave(14); | ||
| hwint15: | ||
| hwint_slave(15); | ||
|
|
||
| bad_sys_call: | ||
| movl $-1,%eax | ||
| jmp ret_from_sys_call | ||
| # eax = function args = {ebx ,ecx,edx} | ||
| sys_call: | ||
| cli | ||
| pushl %ds | ||
| pushl %es | ||
| pushl %fs | ||
| pushl %esi | ||
| pushl %edi | ||
| pushl %edx | ||
| pushl %ecx | ||
| pushl %ebx | ||
|
|
||
| cmpl NR_syscalls,%eax | ||
| jae bad_sys_call | ||
|
|
||
| movl $KERNEL_DATA,%edx | ||
| movl %edx,%ds | ||
| movl %edx,%es | ||
| movl %edx,%fs | ||
|
|
||
| sti | ||
| call *sys_call_table(,%eax,4) | ||
|
|
||
| ret_from_sys_call: | ||
| popl %ebx | ||
| popl %ecx | ||
| popl %edx | ||
| popl %edi | ||
| popl %esi | ||
| popl %fs | ||
| popl %es | ||
| popl %ds | ||
| sti | ||
| iret |
| @@ -0,0 +1,37 @@ | ||
| # Makefile for all | ||
| # | ||
| .PHONY:clear install make | ||
|
|
||
| # Directories | ||
| i = $r/include | ||
| l = libc.a | ||
| vpath %.h $r/include/ | ||
|
|
||
| # Programs, flags, etc. | ||
| AS = as | ||
| CC = gcc | ||
| LD = ld | ||
|
|
||
| ASFLAGS = --32 | ||
| CFLAGS = -I $i -m32 -c -std=gnu99 -fno-stack-protector -Wall -nostdinc | ||
| LDFLAGS = -m elf_i386 -Ttext 0x300000 | ||
|
|
||
| OBJS = vsprintf.o string.o malloc.o | ||
| # What to make. | ||
| # | ||
|
|
||
| $l:$(OBJS) | ||
| $(AR) -r $@ $^ | ||
|
|
||
| %.o:%.S | ||
| $(CC) $< -o $@ $(CFLAGS) | ||
|
|
||
| %.o:%.c | ||
| $(CC) $< -o $@ $(CFLAGS) | ||
|
|
||
| %.o:%.s | ||
| $(AS) $< -o $@ $(ASFLAGS) | ||
|
|
||
|
|
||
| clear: | ||
| -rm *.o -rf |
| @@ -0,0 +1,129 @@ | ||
| /* | ||
| * Copy form linux 0.12 . | ||
| * | ||
| */ | ||
| #include <const.h> | ||
| #include <stdio.h> | ||
| #include <types.h> | ||
| #include <sys/inter.h> | ||
|
|
||
| #define isnull(p) (!(p)) | ||
| /* get page pointer */ | ||
| #define get_pointer(p) ((p) & 0xfffff000) | ||
|
|
||
| typedef struct _bucket{ | ||
| void *page; | ||
| struct _bucket *next; | ||
| void *freeptr; | ||
| unsigned short refcnt; | ||
| unsigned short bucket_size; | ||
| }Bucket; | ||
|
|
||
| struct _bucket_dir{ | ||
| int size; | ||
| Bucket *bucket; | ||
| }; | ||
|
|
||
| struct _bucket_dir bucket_dir[] = { | ||
| {16,NULL}, | ||
| {32,NULL}, | ||
| {64,NULL}, | ||
| {128,NULL}, | ||
| {256,NULL}, | ||
| {512,NULL}, | ||
| {1024,NULL}, | ||
| {2048,NULL}, | ||
| {4096,NULL}, | ||
| {0,NULL}, | ||
| }; | ||
|
|
||
| Bucket *free_bucket = NULL; | ||
|
|
||
| static inline void bucket_init(void){ | ||
| Bucket *first,*bdesc; | ||
|
|
||
| first = bdesc = (Bucket *)(get_free_page()); | ||
| if(isnull(bdesc)) panic("Out of memory in init bucket_init!\n"); | ||
| for(int i = PAGE_SIZE / sizeof(Bucket);i > 1;i--){ | ||
| bdesc->next = bdesc + 1; | ||
| bdesc++; | ||
| } | ||
| bdesc->next = free_bucket; | ||
| free_bucket = first; | ||
| } | ||
|
|
||
| void *malloc(unsigned int len){ | ||
| Bucket *bdesc; | ||
| struct _bucket_dir *bdir; | ||
| void *retval = NULL; | ||
| for(bdir = bucket_dir;bdir->size;bdir++) | ||
| if(bdir->size > len) | ||
| break; | ||
| if(!bdir->size) panic("Don't alloc the memory!\n"); | ||
| lock(); | ||
| for(bdesc = bdir->bucket;bdesc;bdesc = bdesc->next) | ||
| if(bdesc->freeptr) | ||
| break; | ||
| if(isnull(bdesc)){ | ||
| char *cp = NULL; | ||
| if(isnull(free_bucket)) bucket_init(); | ||
| bdesc = free_bucket; | ||
| free_bucket = free_bucket->next; | ||
| bdesc->refcnt = 0; | ||
| bdesc->bucket_size = bdir->size; | ||
| bdesc->page = bdesc->freeptr = cp = (void *)(get_free_page()); | ||
| if(isnull(cp)) panic("Out of memory in kernel malloc()\n"); | ||
| for(int i = PAGE_SIZE / bdir->size;i > 1;i--){ | ||
| *((char **)cp) = cp + bdir->size; | ||
| cp += bdir->size; | ||
| } | ||
| *((char **)cp) = NULL; | ||
| bdesc->next = bdir->bucket; | ||
| bdir->bucket = bdesc; | ||
| } | ||
| retval = bdesc->freeptr; | ||
| bdesc->freeptr = *((void **) retval); | ||
| bdesc->refcnt++; | ||
| unlock(); | ||
| return retval; | ||
| } | ||
|
|
||
| void free_s(void *obj,int size){ | ||
| void *page; | ||
| struct _bucket_dir *bdir; | ||
| Bucket *bdesc,*prev; | ||
|
|
||
| page = (void *)(get_pointer((Pointer)obj)); | ||
|
|
||
| for(bdir = bucket_dir;bdir->size;bdir++){ | ||
| prev = NULL; | ||
| if(bdir->size < size) continue; | ||
| for(bdesc = bdir->bucket;bdesc;bdesc = bdesc->next){ | ||
| if(bdesc->page == page) | ||
| goto found; | ||
| prev = bdesc; | ||
| } | ||
| } | ||
| panic("Bad address passed to kernel free_s()"); | ||
| found: | ||
| lock(); | ||
| *((void **)obj) = bdesc->freeptr; | ||
| bdesc->refcnt--; | ||
| if(bdesc->refcnt == 0){ | ||
| if((prev && (prev->next != bdesc)) || (!prev && (bdir->bucket != bdesc))) | ||
| for(prev = bdir->bucket;prev;prev = prev->next) | ||
| if(prev->next == bdesc) | ||
| break; | ||
| if(prev) | ||
| prev->next = bdesc->next; | ||
| else{ | ||
| if(bdir->bucket != bdesc) | ||
| panic("malloc bucket corrupted\n"); | ||
| bdir->bucket = bdesc->next; | ||
| } | ||
| free_page((Pointer)bdesc->page); | ||
| bdesc->next = free_bucket; | ||
| free_bucket = bdesc; | ||
| } | ||
| unlock(); | ||
| } |
| @@ -0,0 +1,32 @@ | ||
| #include <string.h> | ||
| #include <stddef.h> | ||
| void *memcpy(void *dest,const void *src,int n){ | ||
| asm("cld\n\t" | ||
| "rep\n\t" | ||
| "movsb\n\t" | ||
| : | ||
| :"c"(n),"S"(src),"D"(dest) | ||
| : | ||
| ); | ||
| return dest; | ||
| } | ||
| void *memset(void *dest,int ch,int n){ | ||
| asm("0:movb %%al,(%1)\n\t" | ||
| "inc %1\n\t" | ||
| "loop 0b\n\t" | ||
| : | ||
| :"a"(ch),"D"(dest),"c"(n) | ||
| :); | ||
| return dest; | ||
| } | ||
|
|
||
| char *strcpy(char *dest,const char *src){ | ||
| asm("0:lodsb\n\t\t" | ||
| "stosb\n\t\t" | ||
| "test %%al,%%al\n\t\t" | ||
| "jne 0b\n\t\t" | ||
| : | ||
| :"D"(dest),"S"(src) | ||
| :); | ||
| return dest; | ||
| } |
| @@ -0,0 +1,211 @@ | ||
| /* | ||
| */ | ||
| #include <stdarg.h> | ||
| /* 数值转换成以base为基数的字符串,保存在str中 */ | ||
| typedef enum _HexBase{ | ||
| OCTAL = 8, | ||
| DECIMAL = 10, | ||
| HEX = 16 | ||
| }HexBase; | ||
|
|
||
| typedef enum{ | ||
| _false = 0, | ||
| _true = 1, | ||
| }_bool; | ||
| //输出样式 | ||
| // <space>|<sign>|<special>|<zero>|num|<space> | ||
| #define STYLE_LEFT 1 //左对齐 | ||
| #define STYLE_SIGN ((STYLE_LEFT)<<1) //负数时显示'-'号,正数时显示'+' | ||
| #define STYLE_SPECIAL ((STYLE_LEFT)<<2) //显示进制前缀 | ||
| #define STYLE_ZEROPAD ((STYLE_LEFT)<<3) //用零填充不足的位宽 | ||
| #define STYLE_LARGE ((STYLE_LEFT)<<4) //使用大写字母 | ||
|
|
||
| //数字字符表 | ||
| static const char * const _lowerDigits = "0123456789abcdefx"; | ||
| static const char * const _upperDigits = "0123456789ABCDEFX"; | ||
|
|
||
| #define isDigit(c) ((c) >= '0' && (c) <= '9') | ||
| // | ||
| static inline int _atoi(const char **s){ | ||
| int i = 0; | ||
| while(isDigit(**s)) i = i * 10 + *((*s)++) - '0'; | ||
| return i; | ||
| } | ||
| //进制转换 | ||
| static inline int _octal(int *str,unsigned long value){ | ||
| int i = 0; | ||
| do{ | ||
| *str++ = value & 7; | ||
| value >>= 3; | ||
| i++; | ||
| }while(value); | ||
| return i; | ||
| } | ||
| static inline int _decimal(int *str,unsigned long value){ | ||
| int i = 0; | ||
| do{ | ||
| *str ++ = value % 10; | ||
| value /= 10; | ||
| i++; | ||
| }while(value); | ||
| return i; | ||
| } | ||
| static inline int _hex(int *str,unsigned long value){ | ||
| int i = 0; | ||
| do{ | ||
| *str++ = value & 0xf; | ||
| value >>= 4; | ||
| i++; | ||
| }while(value); | ||
| return i; | ||
| } | ||
|
|
||
| static inline char *_toNumber(char *str,long value,_bool sign, | ||
| HexBase base,int size,int style){ | ||
| char signString = '+'; | ||
| const char *dig = _lowerDigits; | ||
| int tmp[64]; //缓存转换后的值.还不是ASCII | ||
| int length = 0; | ||
|
|
||
| if(style & STYLE_LARGE) dig = _upperDigits; | ||
| if(style & STYLE_LEFT) style &= (~STYLE_ZEROPAD); //左对齐就不能使用0填充 | ||
| //如果不是10进制,则都按无符号处理 ,并且无正负符号显示 | ||
| //如果是10进制,则去除前缀属性 | ||
| if(DECIMAL != base){ | ||
| sign = _false; | ||
| style &= ~STYLE_SIGN; | ||
| } else style &= ~STYLE_SPECIAL; | ||
|
|
||
| if(style & STYLE_SPECIAL){ | ||
| if(HEX == base) size -= 2; | ||
| else if(OCTAL == base) size -= 1; | ||
| } | ||
|
|
||
| //如果是有符号数,却小于0,则取其补码,并设置符号标志,非16进制在前面已经去除 | ||
| //符号,所以不会受影响 | ||
| if((_true == sign) && (value < 0)){ | ||
| style |= STYLE_SIGN; | ||
| value = ~value + 1; | ||
| signString = '-'; | ||
| } | ||
|
|
||
| if(style & STYLE_SIGN) size --; | ||
|
|
||
| switch(base){ | ||
| case OCTAL:length = _octal(tmp,(unsigned long)value);break; | ||
| case DECIMAL:length = _decimal(tmp,(unsigned long)value);break; | ||
| case HEX:length = _hex(tmp,(unsigned long)value);break; | ||
| } | ||
| size -= length; | ||
|
|
||
| if(!(style & (STYLE_ZEROPAD|STYLE_LEFT))) while(size-- > 0) *str++ = ' '; | ||
| if(style & STYLE_SIGN) *str++ = signString; | ||
| if(style & STYLE_SPECIAL){ | ||
| *str++ = '0'; | ||
| if(HEX == base) *str++ = dig[0x10]; | ||
| } | ||
| if(style & STYLE_ZEROPAD) while(size-- > 0) *str++ = '0'; | ||
| while(length-- > 0) *str++ = dig[tmp[length]]; | ||
| if(style & STYLE_LEFT) while(size-- > 0) *str++ = ' '; | ||
|
|
||
| return str; | ||
| } | ||
|
|
||
| extern int vsprintf(char *buf,const char *fmt,va_list args){ | ||
| int style = 0; | ||
| int width = 0; | ||
| unsigned long num = 0; | ||
| _bool sign = _true; | ||
| HexBase base = DECIMAL; | ||
| char *str,*s; | ||
|
|
||
| enum type{ _long = 'L', _int = 'l' , _short = 'h' }_type = _int; //数据类型,long,int,short | ||
|
|
||
| for( str = buf; *fmt; fmt++){ | ||
| if(*fmt == '%'){ | ||
| style = 0; | ||
| repeat: | ||
| fmt++; | ||
| switch(* fmt){ | ||
| case '-': style |= STYLE_LEFT;goto repeat; | ||
| case '+': style |= STYLE_SIGN;goto repeat; | ||
| case ' ': style |= STYLE_SIGN;goto repeat; | ||
| case '0': style |= STYLE_ZEROPAD;goto repeat; | ||
| case '#': style |= STYLE_SPECIAL;goto repeat; | ||
| } | ||
| width = 0; | ||
| if(isDigit(*fmt)) | ||
| width = _atoi(&fmt); | ||
| else if(* fmt == '*'){ | ||
| fmt++; | ||
| width = va_arg(args,int); | ||
| } | ||
| _type = _int; | ||
| if(*fmt == 'h' || *fmt == 'l' || *fmt == 'L'){ | ||
| _type = (enum type)(*fmt); | ||
| fmt++; | ||
| } | ||
| base = DECIMAL; | ||
| sign = _false; | ||
|
|
||
| switch(*fmt){ | ||
| case 'c':*str++ = (unsigned char)va_arg(args,int);continue; | ||
| case 's': | ||
| s = va_arg(args,char *); | ||
| if(!s) s = "<NULL>"; | ||
| while(*s) *str++ = *s++; | ||
| continue; | ||
| case 'p': | ||
| style |= STYLE_SPECIAL; | ||
| str = _toNumber(str,(unsigned long)va_arg(args,void *), | ||
| _false,HEX,width,style); | ||
| continue; | ||
| case 'o':base = OCTAL;break; | ||
| case 'X':style |= STYLE_LARGE; | ||
| case 'x':base = HEX;style |= STYLE_SPECIAL;break; | ||
| case 'd': | ||
| case 'i': sign = _true; | ||
| case 'u': break; | ||
| default: if(*fmt) *str++ = *fmt; continue; | ||
| } | ||
| if ( _long == _type ) | ||
| num = va_arg( args, unsigned long ); | ||
| else if ( _short == _type ){ | ||
| if ( _true == sign ) | ||
| num = va_arg( args, int ); | ||
| else | ||
| num = va_arg( args, unsigned int ); | ||
| } | ||
| else if ( _true == sign ) | ||
| num = va_arg( args, int ); | ||
| else | ||
| num = va_arg( args, unsigned int ); | ||
|
|
||
| str = _toNumber(str,num, | ||
| _false,base,width,style); | ||
| } | ||
| else | ||
| *str++ = *fmt; | ||
| } | ||
| *str = 0; | ||
|
|
||
| return (buf - str); | ||
| } | ||
|
|
||
| extern int sprintf(char *buf,const char * fmt,...){ | ||
| va_list args; | ||
| int n; | ||
| va_start(args,fmt); | ||
| n = vsprintf(buf,fmt,args); | ||
| va_end(args); | ||
| return n; | ||
| } | ||
| /* | ||
| int main(void){ | ||
| #include <string.h> | ||
| char buf[1200]={0}; | ||
| sprintf(buf,"|Hello %c %-d %u %#08x %#o %s\n",'a',30,40,0xaa,010,"ni hao!"); | ||
| #include <stdio.h> | ||
| puts(buf); | ||
| } | ||
| */ |
| @@ -0,0 +1,163 @@ | ||
| /* | ||
| * (C) 2011-10 | ||
| * Email:LuoZhongYao@gmail.com | ||
| * 每天都对自己说:"Good luck!" | ||
| * 该程序负责初始化内核工作环境,是内核执行的第一个程序. | ||
| * 初始化内容包括,重新安排GDT(由multiboot规范知道,现在已经有一个GDT了),并且 | ||
| * 对8259进行初始化,本质上来说,该程序只是原gmL的setup去除进入保护模式和添加 | ||
| * multiboot支持而已. | ||
| * 使用multiboot的好处是可以使用现存的文件系统,而不用去研究它,可以被其 | ||
| * 引导器引导.内核大小没有限制.反正很多啦,所以我个人建议,有写内核的同学,必 | ||
| * 要参考multiboot,并遵守它. | ||
| */ | ||
| /* 汇编代码 */ | ||
| #define ASM | ||
| /* multiboot规范头文件,该文件直接拷贝于grub_0.98/docs/multiboot.h */ | ||
| #include <multiboot.h> | ||
|
|
||
| #define CreateSection(base,limit,attr) \ | ||
| .short limit&0xffff;\ | ||
| .short base&0xffff; \ | ||
| .byte (base>>16)&0xff;\ | ||
| .short (attr)|((limit>>8)&0x0f00);\ | ||
| .byte (base>>24)&0xff;\ | ||
| //代码段相关属性宏定义 | ||
| #define CODE_READ 0x009a //代码段可读 | ||
| #define CODE_C 0x009c //一致代码段 | ||
| #define CODE_G 0x8098 //使用4GB的界限 | ||
| #define CODE_D 0x4098 //默认使用32位地址 | ||
| //数据段属性 | ||
| #define DATA_WRITE 0x0092 //数据段可写 | ||
| #define DATA_E 0x0094 //向下扩展 | ||
| #define DATA_G 0x8090 //使用32界限 | ||
| #define DATA_B 0x4090 //堆栈段使用ESP等32位指针,向下扩展,指明栈上限4GB | ||
| //TSS描述符 | ||
| #define TSS_G 0x8089 //TSS使用4GB界限,通常这个是用不到的 | ||
| #define TSS 0x0089 //说明这是一个TSS段 | ||
| //权限 | ||
| #define R0 0x0000 //ring 0 | ||
| #define R1 0x0020 // | ||
| #define R2 0x0040 // | ||
| #define R3 0x0060 //ring 3 | ||
|
|
||
| GDT_LEN = gdt_end-gdt_start | ||
| /* | ||
| #define io_delay \ | ||
| jmp .+2 \ | ||
| jmp .+2 | ||
| */ | ||
| /* IO延时宏 */ | ||
| .macro io_delay | ||
| jmp .+2 | ||
| jmp .+2 | ||
| .endm | ||
| .text | ||
| .globl _start,envp,main | ||
| _start: | ||
| jmp start | ||
| /* multiboot 要求4字节对齐 */ | ||
| .align 4 | ||
| multiboot_header: | ||
| /* multiboot header magic 详情请查阅multiboot */ | ||
| .long MULTIBOOT_HEADER_MAGIC | ||
| /* multiboot header flags multiboot为你做什么服务,色情服务不在这个范围内*/ | ||
| /* 同时也告诉了multiboot你是什么款式的人,oh,程序 */ | ||
| .long MULTIBOOT_HEADER_FLAGS | ||
| /* multiboot header checksum ,详情请看multiboot */ | ||
| /* 我猜测引导器就是靠checksum和magic来识别multiboot header的. */ | ||
| .long -(MULTIBOOT_HEADER_MAGIC+MULTIBOOT_HEADER_FLAGS) | ||
| /* 如果不是ELF文件格式,下面的信息就是必须的,这个__ELF__不知道是在哪里定义的 */ | ||
| /* 不过我的二进制,就算下面这些提供了,grub还是不鸟我,所以我也不鸟二进制 */ | ||
| #ifndef __ELF__ | ||
| /* multiboot header addr,hi哥们,你在哪? */ | ||
| .long multiboot_header | ||
| /* Load addr .text在OSimage中的偏移 */ | ||
| .long _start | ||
| /* Load end addr 引导到OSimage中那个位置,如果为零,引导整个OS Image */ | ||
| .long _edata | ||
| /* bss段的结束地址.Boot loader将其清零,并且保证不被覆盖 */ | ||
| .long _end | ||
| /* Boot loader 引导完后将跳转到这里执行 */ | ||
| .long _start | ||
| #endif | ||
| start: | ||
| cli | ||
| /* | ||
| mov $0x3FFFF0,%esp | ||
| push %ebx | ||
| */ | ||
| /* 保存由Boot loader提供的信息地址 */ | ||
| mov %ebx,envp | ||
| /* 8259,写过很多次了,懒得在写,不懂的可以google,或者Email我 */ | ||
| /* 唯一说一点的就是外部中断0x20~0x30 */ | ||
| mov $0x11,%al | ||
| out %al,$0x20 | ||
| io_delay | ||
| out %al,$0xa0 | ||
| io_delay | ||
|
|
||
| mov $0x20,%al | ||
| out %al,$0x21 | ||
| io_delay | ||
| mov $0x28,%al | ||
| out %al,$0xa1 | ||
| io_delay | ||
|
|
||
| mov $0x04,%al | ||
| out %al,$0x21 | ||
| io_delay | ||
| mov $0x2,%al | ||
| out %al,$0xa1 | ||
| io_delay | ||
|
|
||
| mov $0x1,%al | ||
| out %al,$0x21 | ||
| io_delay | ||
| out %al,$0xa1 | ||
| io_delay | ||
|
|
||
| /* 屏蔽外部中断 */ | ||
| mov $0xFF,%al | ||
| out %al,$0x21 | ||
| io_delay | ||
| out %al,$0xa1 | ||
| io_delay | ||
| /* 重新设置GDT,GDT被放置到0x101000处 */ | ||
| mov $GDT_TABLE,%edi | ||
| mov $gdt_start,%esi | ||
| mov $GDT_LEN,%ecx | ||
| shr $2,%ecx | ||
| cld | ||
| rep movsl | ||
| lgdt gdt | ||
| lidt idt | ||
| /* 刷新环境 */ | ||
| ljmp $KERNEL_CODE,$new_env | ||
| new_env: | ||
| mov $KERNEL_DATA,%eax | ||
| mov %eax,%ds | ||
| mov %eax,%es | ||
| mov %eax,%ss | ||
| mov %eax,%fs | ||
| mov %eax,%gs | ||
| mov $DIE_STACK,%esp | ||
| call main | ||
| jmp . | ||
|
|
||
| .data | ||
| envp: | ||
| .long 0x0 | ||
| gdt: | ||
| .word 0xFFFF | ||
| .long GDT_TABLE | ||
| idt: | ||
| .word 256*8-1 | ||
| .long IDT_TABLE | ||
| gdt_start: | ||
| CreateSection(0xAA,0,0XBB); | ||
| CreateSection(0x0,0xFFFFF,CODE_READ|CODE_D|CODE_G) | ||
| CreateSection(0x0,0xFFFFF,DATA_WRITE|DATA_G|R0|DATA_B); | ||
| CreateSection(0x0,0xFFFFF,CODE_READ|CODE_D|CODE_G|R3); | ||
| CreateSection(0x0,0xFFFFF,DATA_WRITE|DATA_G|R3|DATA_B); | ||
| CreateSection(TSS_TABLE,0x100,TSS|R3); | ||
| gdt_end: |