From b42d36ff4606577a99ec9b956ab34734af76c818 Mon Sep 17 00:00:00 2001 From: sharixos Date: Wed, 18 Oct 2017 12:43:00 +0800 Subject: [PATCH] window --- Makefile | 6 +- kern/component/component.c | 35 +++ kern/component/component.h | 36 +++ kern/component/editbox.c | 30 ++- kern/component/editbox.h | 8 +- kern/debug/monitor.c | 18 +- kern/font/font.c | 4 +- kern/graphic/bitmap.c | 38 --- kern/graphic/bitmap.h | 5 +- kern/graphic/graphic.c | 259 +++++++++--------- kern/graphic/graphic.h | 75 ++++-- kern/graphic/window.c | 90 +++++++ kern/graphic/window.h | 40 +++ kern/init/init.c | 27 +- kern/libs/asm_tool.S | 4 - kern/libs/asm_tool.h | 2 +- kern/libs/rb_tree.c | 527 +++++++++++++++++++++++++++++++++++++ kern/libs/rb_tree.h | 31 +++ kern/mm/buddy_pmm.c | 10 +- kern/mm/memlayout.h | 13 +- kern/mm/mmu.h | 7 +- kern/mm/pmm.c | 15 +- kern/mm/pmm.h | 17 ++ kern/mm/slab.c | 455 ++++++++++++++++++++++++++++++++ kern/mm/slab.h | 15 ++ kern/sync/sync.h | 24 ++ libs/cpp.c | 1 + libs/cpp.h | 12 + libs/rand.c | 25 ++ libs/stdlib.h | 16 ++ libs/stringbuffer.c | 7 +- libs/types.h | 29 +- 32 files changed, 1586 insertions(+), 295 deletions(-) create mode 100644 kern/component/component.c create mode 100644 kern/component/component.h delete mode 100644 kern/graphic/bitmap.c create mode 100644 kern/graphic/window.c create mode 100644 kern/graphic/window.h create mode 100644 kern/libs/rb_tree.c create mode 100644 kern/libs/rb_tree.h create mode 100644 kern/mm/slab.c create mode 100644 kern/mm/slab.h create mode 100644 kern/sync/sync.h create mode 100644 libs/cpp.c create mode 100644 libs/cpp.h create mode 100644 libs/rand.c create mode 100644 libs/stdlib.h diff --git a/Makefile b/Makefile index 2c8587e..4edd2cf 100755 --- a/Makefile +++ b/Makefile @@ -121,7 +121,8 @@ KINCLUDE += kern/debug/ \ kern/font \ kern/component \ kern/mm \ - kern/init + kern/init \ + kern/sync KSRCDIR += kern/init \ kern/libs \ @@ -144,7 +145,7 @@ kernel = $(call totarget,kernel) $(kernel): tools/kernel.ld -$(kernel): $(KOBJS) +$(kernel): $(KOBJS) @echo + ld $@ $(V)$(LD) $(LDFLAGS) -T tools/kernel.ld -o $@ $(KOBJS) @$(OBJDUMP) -S $@ > $(call asmfile,kernel) @@ -285,4 +286,3 @@ handin: packall packall: clean @$(RM) -f $(HANDIN) @tar -czf $(HANDIN) `find . -type f -o -type d | grep -v '^\.*$$' | grep -vF '$(HANDIN)'` - diff --git a/kern/component/component.c b/kern/component/component.c new file mode 100644 index 0000000..c302bc2 --- /dev/null +++ b/kern/component/component.c @@ -0,0 +1,35 @@ +#include + +void draw_frame(graphic_t *g, context_t *contex, frame_t *frame) +{ + int x = contex->rect.p.x; + int y = contex->rect.p.y; + rect_t frect = frame->rect; + rect_t realrect = RECT(x+frect.p.x, y+frect.p.y, frect.width, frect.height); + g->fill_rect(realrect, frame->bgc); + g->draw_rect(realrect, frame->frc); +} + +void draw_button(graphic_t *g, context_t *contex, button_t *button) +{ + draw_frame(g, contex, &button->frame); + rect_t frect = button->frame.rect; + int x1 = contex->rect.p.x + frect.p.x; + int y1 = contex->rect.p.y + frect.p.y; + int x2 = x1 + frect.width-1; + int y2 = y1 + frect.height-1; + g->draw_line(POINT(x1, y1),POINT(x2, y2), button->btc); + g->draw_line(POINT(x1, y2),POINT(x2, y1), button->btc); +} + +void draw_list(graphic_t *g, context_t *contex, list_t *list) +{ + draw_frame(g, contex, &list->frame); + rect_t frect = list->frame.rect; + int x1 = contex->rect.p.x + frect.p.x; + int y1 = contex->rect.p.y + frect.p.y; + for (size_t i = 0; i < list->n; i++) { + g->draw_line(POINT(x1, y1), POINT(x1+frect.width, y1), list->sepc); + y1 += LIST_H; + } +} diff --git a/kern/component/component.h b/kern/component/component.h new file mode 100644 index 0000000..ebb4e30 --- /dev/null +++ b/kern/component/component.h @@ -0,0 +1,36 @@ +#pragma once + +#include +#include +#include + +/* + point or rect of the component are all relative + for example: + if the point of window is (xw, yw) and the point of frame is (xf, yf) + then the real position of frame is (xw+xf, yw+yf) +*/ + + +typedef struct frame_s +{ + rect_t rect; // relative rect + rgb_t bgc; // background color + rgb_t frc; // frame color +} frame_t; +void draw_frame(graphic_t *g, context_t *contex, frame_t *frame); + +typedef struct button_s +{ + frame_t frame; // button frame + rgb_t btc; // button color +} button_t; +void draw_button(graphic_t *g, context_t *contex, button_t *button); + +typedef struct list_s +{ + frame_t frame; // list frame + rgb_t sepc; // separator color + uint32_t n; // n list item +} list_t; +void draw_list(graphic_t *g, context_t *contex, list_t *list); diff --git a/kern/component/editbox.c b/kern/component/editbox.c index 79312e8..9f2405e 100644 --- a/kern/component/editbox.c +++ b/kern/component/editbox.c @@ -4,19 +4,20 @@ #include #include #include +#include keybuf_t kb; -void getcontent(editbox_t *peb) +void getcontent(editbox_t *peb) { keybuf_init(&kb); - while(1) { - edit_readline(peb); - edit_runcmd(peb); - } + while(1) { + edit_readline(peb); + edit_runcmd(peb); + } } -void edit_putchar(char ch, editbox_t *peb) +void edit_putchar(char ch, editbox_t *peb) { if(ch == '\n' || ch == '\t') { peb->cur_y ++; @@ -24,17 +25,17 @@ void edit_putchar(char ch, editbox_t *peb) if(peb->cur_y >= peb->ch_y) peb->cur_y = 0; return; - } + } int x = peb->point.x + peb->cur_x*ASC16_WIDTH; int y = peb->point.y + peb->cur_y*ASC16_HEIGHT; - + draw_asc16(ch, (point_t){x, y}, peb->text_c); peb->cur_x ++; if(peb->cur_x >= peb->ch_x) { peb->cur_x = 0; peb->cur_y ++; } - if(peb->cur_y >= peb->ch_y) + if(peb->cur_y >= peb->ch_y) peb->cur_y = 0; } void edit_putstr(char *str, editbox_t *peb) @@ -45,12 +46,13 @@ void edit_putstr(char *str, editbox_t *peb) } } -void edit_readline(editbox_t *peb) +void edit_readline(editbox_t *peb) { int i = 0 , c; memset(peb->ch,'\0',peb->ch_size); while (1) { while((c=keybuf_pop(&kb)) == 0); + cprintf("c:%c\n", c); if (c < 0) { return; } @@ -62,7 +64,7 @@ void edit_readline(editbox_t *peb) i --; } else if (c == '\n' || c == '\r') { - peb->ch[i] = '\0'; + peb->ch[i] = '\0'; peb->cur_x = 0; peb->cur_y ++; if(peb->cur_y >= peb->ch_y-1) peb->ch_y = 0; @@ -72,14 +74,14 @@ void edit_readline(editbox_t *peb) } void edit_runcmd(editbox_t *peb) -{ +{ if(strcmp(peb->ch, "hello") == 0) edit_putstr("great\n", peb); else if(strcmp(peb->ch, "system") == 0) - draw_bmp_test(); + print_kerninfo(); else if(strcmp(peb->ch, "who are you") == 0) edit_putstr("I am joker\n", peb); else if(strcmp(peb->ch, "kerninfo") == 0) print_kerninfo(); else; -} \ No newline at end of file +} diff --git a/kern/component/editbox.h b/kern/component/editbox.h index 46e13bb..0428589 100644 --- a/kern/component/editbox.h +++ b/kern/component/editbox.h @@ -1,8 +1,8 @@ -#ifndef _KERN_EDITBOX_H -#define _KERN_EDITBOX_H +#pragma once #include #include +#include extern keybuf_t kb; @@ -12,7 +12,7 @@ typedef struct editbox_s int ch_x; //num of width int ch_y; // num of height rgb_t bg_c; - rgb_t text_c; + rgb_t text_c; int cur_x, cur_y; char * ch; int ch_size; @@ -21,5 +21,3 @@ typedef struct editbox_s void getcontent(editbox_t * peb); void edit_readline(editbox_t *peb); void edit_runcmd(editbox_t *peb); - -#endif \ No newline at end of file diff --git a/kern/debug/monitor.c b/kern/debug/monitor.c index fd74f8d..20a9287 100644 --- a/kern/debug/monitor.c +++ b/kern/debug/monitor.c @@ -97,9 +97,9 @@ monitor(struct trapframe *tf) { if (runcmd(buf, tf) < 0) { break; } - } + } } - + } } @@ -112,7 +112,7 @@ mon_help(int argc, char **argv, struct trapframe *tf) { draw_str16((char*)commands[i].name, (point_t){20, 40+i*16}, (rgb_t){43,43,43}); } cputchar('*'); - _gfillrect2(MediumBlue, (rect_t){200,200,500,500}); + // _gfillrect2(MediumBlue, (rect_t){200,200,500,500}); return 0; } @@ -132,12 +132,11 @@ mon_kerninfo(int argc, char **argv, struct trapframe *tf) { * */ int mon_bootinfo(int argc, char **argv, struct trapframe *tf) { - struct BOOTINFO* pboot = get_bootinfo(); - cprintf("uint8_t: cyls=%d leds=%x ", pboot->cyls, pboot->leds); - cprintf("vmode=%x reserve=%x\n", pboot->vmode, pboot->reserve); - cprintf("uint16_t: scrnx=%d scrny=%d\n", pboot->scrnx, pboot->scrny); - cprintf("uint8_t: bitspixel=%d mem_model=%d\n", pboot->bitspixel, pboot->mem_model); - cprintf("uint8_t: vram=%x\n", pboot->vram); + cprintf("uint8_t: cyls=%d leds=%x ", binfo->cyls, binfo->leds); + cprintf("vmode=%x reserve=%x\n", binfo->vmode, binfo->reserve); + cprintf("uint16_t: scrnx=%d scrny=%d\n", binfo->scrnx, binfo->scrny); + cprintf("uint8_t: bitspixel=%d mem_model=%d\n", binfo->bitspixel, binfo->mem_model); + cprintf("uint8_t: vram=%x\n", binfo->vram); return 0; } @@ -151,4 +150,3 @@ mon_backtrace(int argc, char **argv, struct trapframe *tf) { print_stackframe(); return 0; } - diff --git a/kern/font/font.c b/kern/font/font.c index 010b9b3..8bc789f 100644 --- a/kern/font/font.c +++ b/kern/font/font.c @@ -7,13 +7,13 @@ static uint8_t* p_font_asc16_b = (uint8_t*)(FONT_ASC16_ADDR+KERNBASE); BOOL draw_asc16(char ch, point_t point, rgb_t c) { uint8_t * p_asc = p_font_asc16_b + (uint8_t)ch * 16; - + graphic_t * g = get_graphic(); for(int y=0; yset_pixel(point.x+x, point.y+y, c); testbit >>= 1; } p_asc ++; diff --git a/kern/graphic/bitmap.c b/kern/graphic/bitmap.c deleted file mode 100644 index a566653..0000000 --- a/kern/graphic/bitmap.c +++ /dev/null @@ -1,38 +0,0 @@ -#include -#include -#include -#include -#include - -static bitmap_t* p_bmp_icon = (bitmap_t*)(BMP_ICON_ADDR+KERNBASE); - -BOOL draw_bitmap(bitmap_t* p_bmp, int x0, int y0) -{ - uint8_t* p_bmp_data_addr = (uint8_t*)p_bmp + p_bmp->file_head.bf_offset_bits; - uint8_t* p_data; - - /* 不是24位位图 */ - if (p_bmp->info_head.bi_bit_count != 24) - return FALSE; - - /* 图像的宽、髙 */ - int bmp_cx = abs(p_bmp->info_head.bi_width); - int bmp_cy = abs(p_bmp->info_head.bi_height); - - int nBpline = (((bmp_cx*p_bmp->info_head.bi_bit_count + 31) >> 5) << 2); - - for(int j=0; j @@ -34,5 +33,3 @@ typedef struct bitmap24_t } bitmap_t; void draw_bmp_test(); - -#endif \ No newline at end of file diff --git a/kern/graphic/graphic.c b/kern/graphic/graphic.c index 6f35506..32b0ca1 100644 --- a/kern/graphic/graphic.c +++ b/kern/graphic/graphic.c @@ -9,193 +9,172 @@ #include #include #include +#include +#include -struct BOOTINFO * get_bootinfo() -{ - return binfo; -} +/*********** global value ************/ +graphic_t *g = NULL; -void draw_editbox(editbox_t eb); -inline BOOL is_pixel_valid(int32_t x, int32_t y) + +/********* graphic library *******************/ +static inline BOOL is_pixel_valid(int32_t x, int32_t y) { if(x<0 || y<0 || (uint32_t)x >= binfo->scrnx || (uint32_t)y >= binfo->scrny) return FALSE; return TRUE; } -inline BOOL setpixel(int32_t x, int32_t y, rgb_t c) +static void set_pixel(int x, int y, rgb_t c) { - // cprintf("vram:%x scrnx:%d scrny:%d\n", binfo->vram, binfo->scrnx, binfo->scrny); -// if(!is_pixel_valid(x, y)) -// return FALSE; - + if(!is_pixel_valid(x,y)) + return; int nBppixel = binfo->bitspixel>>3; uint8_t * pvram = (uint8_t*)(binfo->vram + nBppixel*binfo->scrnx*y + nBppixel*x); - *pvram = c.r; + *pvram = c.b; *(pvram+1) = c.g; - *(pvram+2) = c.b; - return TRUE; + *(pvram+2) = c.r; } -rgb_t _gGetPixel(int32_t x, int32_t y) +static rgb_t get_pixel(int32_t x, int32_t y) { if(!is_pixel_valid(x,y)) return (rgb_t){0,0,0}; - //uint8_t * pvram = binfo->vram + y*binfo->scrnx + x; - //return *pvram; - return (rgb_t){0,0,0}; -} - -rect_t _gGetScrnRect() -{ - rect_t rect; - rect.left = 0; - rect.top = 0; - rect.width = binfo->scrnx; - rect.height = binfo->scrny; - return rect; -} - - -void graphic_init() -{ - cprintf("graphic_init\n"); - init_screen8(); - - draw_asc16('>', (point_t){22, 2}, MediumBlue); - draw_str16("Chill out!", (point_t){30, 2}, (rgb_t){32,33,22}); - - rgb_t buff[16*16]; - init_mouse_cursor8(buff); - draw_mouse(buff); - - char buf[100]; - memset(buf,'\0',100); - - editbox_t eb; - eb.point = (point_t){100,100}; - eb.ch_x = 60; - eb.ch_y = 30; - eb.bg_c = Pink; - eb.text_c = Black; - eb.ch = buf; - eb.ch_size = 100; - eb.cur_x = eb.cur_y = 0; - - draw_editbox(eb); - getcontent(&eb); - + uint8_t * pvram = binfo->vram + y*binfo->scrnx + x; + return (rgb_t){*pvram,*(pvram+1),*(pvram+2)}; } -void init_screen8() +static void draw_line(point_t p1, point_t p2, rgb_t c) { - _gfillrect2((rgb_t){20,40,100}, (rect_t){0,0,binfo->scrnx,binfo->scrny}); - - _gdrawrect((rgb_t){100,100,100}, (rect_t){0, 0, 64, 700}); - - for(int i=0; i<10; i++) - { - _gfillrect2((rgb_t){200,220,10}, (rect_t){2, 2+70*i, 60, 60}); - _gdrawrect((rgb_t){32,33,44}, (rect_t){2, 2+70*i, 60, 60}); + if(p2.x (p2.y-p1.y); if(type) { float yt1 = p1.y, dy = (float)(p2.y-p1.y)/(p2.x-p1.x); int xt1=p1.x; for(;yt1<=p2.y && xt1<=p2.x; yt1+=dy, xt1++) - setpixel(xt1,yt1,c); + set_pixel(xt1,yt1,c); } else{ float xt2 = p1.x, dx = (float)(p2.x-p1.x)/(p2.y-p1.y); int yt2 = p1.y; for(;xt2<=p2.x && yt2<=p2.y; xt2+=dx, yt2++) - setpixel(xt2, yt2,c); + set_pixel(xt2, yt2,c); } - - } -void _gdrawrect(rgb_t c, rect_t rect) +static void draw_rect(rect_t rect, rgb_t c) { - int x1 = rect.left, x2 = rect.left+rect.width-1; - int y1 = rect.top, y2 = rect.top+rect.height-1; - _gdrawline(c, (point_t){x1, y1}, (point_t){x2, y1}); - _gdrawline(c, (point_t){x1, y1}, (point_t){x1, y2}); - _gdrawline(c, (point_t){x2, y1}, (point_t){x2, y2}); - _gdrawline(c, (point_t){x1, y2}, (point_t){x2, y2}); + point_t p1 = rect.p; + point_t p2 = (point_t){p1.x, p1.y+rect.height-1}; + point_t p3 = (point_t){p1.x+rect.width-1, p1.y}; + point_t p4 = (point_t){p1.x+rect.width-1, p1.y+rect.height-1}; + draw_line(p1, p2, c); + draw_line(p2, p4, c); + draw_line(p4, p3, c); + draw_line(p3, p1, c); } -void _gfillrect(rgb_t *buf, rect_t rect) +static void fill_rect(rect_t rect, rgb_t c) { - for(int x=rect.left; xbitspixel>>3; + int scrnx = binfo->scrnx; + int scrny = binfo->scrny; + int left = rect.p.x, right = rect.p.x+rect.width-1; + int top = rect.p.y, bottom = rect.p.y+rect.height-1; + + if(left>right || top>bottom || left>scrnx-1 || top>scrny-1) return; + if(left < 0) left = 0; + if(top < 0) top = 0; + if(right > scrnx-1) right = scrnx-1; + if(bottom > scrny-1) bottom = scrny-1; + + uint8_t * vram = (uint8_t*)binfo->vram; + uint8_t *pvram = vram; + + for (size_t i = top; i <= bottom; i++) { + for (size_t j = left; j <= right; j++) { + pvram = (uint8_t*)(vram + nBppixel*(scrnx*i+j)); + *pvram = c.b; + *(pvram+1) = c.g; + *(pvram+2) = c.r; + } + } } -void _gfillrect2(rgb_t c, rect_t rect) +static void draw_bitmap(rect_t rect, bitmap_t * pbmp) { - for(int x=rect.left; xfile_head.bf_offset_bits; + uint32_t nbit = pbmp->info_head.bi_bit_count; + if(nbit != 24) return; + uint32_t width = abs(pbmp->info_head.bi_width); + uint32_t height = abs(pbmp->info_head.bi_height); - } + size_t nBpline = ((width*nbit + 31) >> 5) << 2; + + size_t x0 = rect.p.x, y0 = rect.p.y; + if(width > rect.width) width = rect.width; + if(height > rect.height) height = rect.height; + int nBppixel = binfo->bitspixel>>3; + int scrnx = binfo->scrnx; + int scrny = binfo->scrny; + + if(x0+width > scrnx) width = scrnx-x0-1; + if(y0+height > scrny) height = scrny-y0-1; + + uint8_t * vram = (uint8_t*)binfo->vram; + uint8_t *pvram = vram; + uint8_t *pdata = pbmp_addr; + for (size_t i = 0; i < width; i++) { + for (size_t j = 0; j < height; j++) { + pvram = (uint8_t*)(vram + nBppixel*(scrnx*(y0+j)+x0+i)); + pdata = (uint8_t*)(pbmp_addr + nBpline*j + i*3); + *pvram = *pdata; + *(pvram+1) = *(pdata+1); + *(pvram+2) = *(pdata+2); + } + } } -void init_mouse_cursor8(rgb_t *mouse) +static void fill_bitmap(rect_t rect, bitmap_t * pbmp) { - static char cursor[16][16] = { - "**************..", - "*OOOOOOOOOOO*...", - "*OOOOOOOOOO*....", - "*OOOOOOOOO*.....", - "*OOOOOOOO*......", - "*OOOOOOO*.......", - "*OOOOOOO*.......", - "*OOOOOOOO*......", - "*OOOO**OOO*.....", - "*OOO*..*OOO*....", - "*OO*....*OOO*...", - "*O*......*OOO*..", - "**........*OOO*.", - "*..........*OOO*", - "............*OO*", - ".............***" - }; - int x, y; - - for (y = 0; y < 16; y++) { - for (x = 0; x < 16; x++) { - if (cursor[y][x] == '*') { - mouse[y * 16 + x] = LightPink; - } - if (cursor[y][x] == 'O') { - mouse[y * 16 + x] = Navy; - } - if (cursor[y][x] == '.') { - mouse[y * 16 + x] = BlueViolet; - } + uint32_t width = abs(pbmp->info_head.bi_width); + uint32_t height = abs(pbmp->info_head.bi_height); + + size_t x = rect.p.x, y = rect.p.y; + while (xset_pixel = set_pixel; + g->get_pixel = get_pixel; + g->draw_line = draw_line; + g->draw_rect = draw_rect; + g->fill_rect = fill_rect; + g->draw_bitmap = draw_bitmap; + g->fill_bitmap = fill_bitmap; } - return; + return g; +} + +rect_t get_scrn_rect() +{ + rect_t rect = RECT(0, 0, binfo->scrnx, binfo->scrny); + return rect; } diff --git a/kern/graphic/graphic.h b/kern/graphic/graphic.h index 4bc9ee1..5b7f5fd 100644 --- a/kern/graphic/graphic.h +++ b/kern/graphic/graphic.h @@ -1,27 +1,58 @@ -#ifndef _KERN_GRAPHIC_H -#define _KERN_GRAPHIC_H - +#pragma once #include #include - - - -void graphic_init() ; -void init_mouse_cursor8(rgb_t *mouse); - +#include + +typedef struct point_s +{ + int32_t x; + int32_t y; +} point_t; + +#define POINT(x,y) (point_t){x,y} + +typedef struct rect_s +{ + point_t p; + uint32_t width; + uint32_t height; +} rect_t; + +#define RECTP(p,w,h) ((rect_t){p,w,h}) +#define RECT(x,y,w,h) RECTP(POINT(x,y),w,h) + +typedef struct rgb_s +{ + uint8_t r; + uint8_t g; + uint8_t b; +} rgb_t; + +typedef struct painter_s +{ + rgb_t color; +} painter_t; + +typedef struct graphic_s +{ + void (*init)(void); + void (*set_pixel)(int x, int y, rgb_t c); + rgb_t (*get_pixel)(int x, int y); + + void (*draw_line)(point_t p1, point_t p2, rgb_t c); + void (*draw_circle)(point_t p, uint32_t r); + void (*draw_rect)(rect_t rect, rgb_t c); + + void (*fill_rect)(rect_t rect, rgb_t c); + void (*fill_circle)(point_t p, uint32_t r); + + void (*draw_bitmap)(rect_t rect, bitmap_t * pbmp); + void (*fill_bitmap)(rect_t rect, bitmap_t * pbmp); +} graphic_t; + +graphic_t * get_graphic(); +rect_t get_scrn_rect(); BOOL setpixel(int32_t x, int32_t y, rgb_t c); -rgb_t _gGetPixel(int32_t x, int32_t y); -rect_t _gGetScrnRect(); -void init_screen8(); -void draw_mouse(rgb_t *mouse); - -void _gdrawline(rgb_t c, point_t p1, point_t p2); -void _gdrawrect(rgb_t c, rect_t rect); -void _gfillrect(rgb_t *buf, rect_t rect); -void _gfillrect2(rgb_t c, rect_t rect); -BOOL is_pixel_valid(int32_t x, int32_t y); -struct BOOTINFO* get_bootinfo(); - -#endif +void init_screen8(); diff --git a/kern/graphic/window.c b/kern/graphic/window.c new file mode 100644 index 0000000..4ad86ca --- /dev/null +++ b/kern/graphic/window.c @@ -0,0 +1,90 @@ +#include +#include +#include +#include +#include +#include +#include + +Define_Method(window_t) + +/*********** global value ************/ +window_t * parent = NULL; +static bitmap_t* p_bmp_icon2 = (bitmap_t*)(BMP_ICON_ADDR+KERNBASE); + +/********* member function *******************/ +void show() +{ + MethodOf(window_t); + + graphic_t * g = get_graphic(); + + if(this->bgbmp) { + g->fill_bitmap(get_scrn_rect(), this->bgbmp); + } + else { + g->fill_rect(this->contex.rect, this->contex.bgc); + } + + g->draw_rect(this->contex.rect, SkyBlue); + g->fill_rect(RECTP(this->contex.rect.p, this->contex.rect.width, TITLE_H), TITLE_C); + + + // editbox_t * peb = this->edit; + // if(peb) { + // g->fill_rect(RECTP(peb->point, peb->ch_x*ASC16_WIDTH, peb->ch_y*ASC16_HEIGHT), peb->bg_c); + // } +} + +void destroy() +{ + MethodOf(window_t); + + if(this->edit) { + //TODO: there should be destroy_editbox + kfree(this->edit); + } + kfree(this); +} + + + + + +/********* create *******************/ +window_t* get_parent_window() +{ + if(!parent) { + window_t * win = (window_t*) kmalloc(sizeof(window_t)); + win->contex.rect = get_scrn_rect(); + win->contex.bgc = DarkOliveGreen; + win->bgbmp = p_bmp_icon2; + win->edit = NULL; + Register_Method(win, window_t) + win->show = show; + win->destroy = destroy; + return win; + } + return parent; +} + +window_t * create_window(int width, int height) +{ + window_t * parent = get_parent_window(); + window_t * win = (window_t*) kmalloc(sizeof(window_t)); + int randx = rand()%(parent->contex.rect.width-width); + int randy = TITLE_H + rand()%(parent->contex.rect.height-height-TITLE_H); + win->contex.rect = RECT(randx, randy, width, height); + win->contex.bgc = Khaki; + Register_Method(win, window_t) + win->show = show; + win->destroy = destroy; + return win; +} + +void draw_mouse(uint32_t x, uint32_t y) +{ + graphic_t *g = get_graphic(); + g->fill_rect(RECT(x,y,6,6), Navy); + g->fill_rect(RECT(x+3,y+3,10,10), CornflowerBlue); +} diff --git a/kern/graphic/window.h b/kern/graphic/window.h new file mode 100644 index 0000000..1c35fa5 --- /dev/null +++ b/kern/graphic/window.h @@ -0,0 +1,40 @@ +#pragma once + +#include +#include +#include +#include +#include + +#define TITLE_H 30 +#define TITLE_C DarkGray + +#define LIST_H 30 + +typedef struct contex_s +{ + rect_t rect; // window rect + rgb_t bgc; // window background color +} context_t; + +typedef struct window_s +{ + Define_Member(window_s) + + char *name; + context_t contex; + + bitmap_t *bgbmp; + + editbox_t *edit; // editbox + + void (*show)(); + void (*destroy)(); +} window_t; + +window_t* get_parent_window(); + +window_t * create_window(int width, int height); +void destroy_window(window_t * win); + +void draw_mouse(uint32_t x, uint32_t y); diff --git a/kern/init/init.c b/kern/init/init.c index f136040..ebcff77 100644 --- a/kern/init/init.c +++ b/kern/init/init.c @@ -12,33 +12,42 @@ #include #include #include +#include +#include +#include +#include struct BOOTINFO *binfo = (struct BOOTINFO *) (ADR_BOOTINFO+KERNBASE); int kern_init(void) __attribute__((noreturn)); -int -kern_init(void) { +int kern_init(void) { extern char edata[], end[]; memset(edata, 0, end - edata); cons_init(); - - const char *message = "Sharix is loading ..."; - cprintf("%s\n\n", message); - cprintf("scrnx:%d scrny:%d vram:%x\n", binfo->scrnx, binfo->scrny, binfo->vram); print_kerninfo(); pmm_init(); pic_init(); - idt_init(); clock_init(); - intr_enable(); - graphic_init(); + window_t *win = get_parent_window(); + m(win)->show(); + + window_t * terminal = create_window(500,600); + m(terminal)->show(); + + window_t * terminal2 = create_window(400,400); + m(terminal2)->show(); + + draw_mouse(400,400); + + draw_str16("Author: Xingang Wang", (point_t){800,40}, White); + draw_str16("Visit: www.sharix.site", (point_t){800,60}, White); while (1) { // monitor(NULL); diff --git a/kern/libs/asm_tool.S b/kern/libs/asm_tool.S index 789c5ba..f93114d 100644 --- a/kern/libs/asm_tool.S +++ b/kern/libs/asm_tool.S @@ -36,7 +36,3 @@ io_out8: # void io_out8(int port, int data) movb 8(%esp), %al outb %al, %dx ret - -set_pixel: # int set_pixel() - movl $0xaaaaaaaa, %eax - ret diff --git a/kern/libs/asm_tool.h b/kern/libs/asm_tool.h index ab4d96c..e0e851f 100644 --- a/kern/libs/asm_tool.h +++ b/kern/libs/asm_tool.h @@ -5,4 +5,4 @@ void io_out8(int port, int data); void io_cli(void); void io_sti(void); -int set_pixel(void); +// int set_pixel(void); diff --git a/kern/libs/rb_tree.c b/kern/libs/rb_tree.c new file mode 100644 index 0000000..6b86d5a --- /dev/null +++ b/kern/libs/rb_tree.c @@ -0,0 +1,527 @@ +#include +#include +#include +#include +#include +#include + +/* rb_node_create - create a new rb_node */ +static inline rb_node * +rb_node_create(void) { + return kmalloc(sizeof(rb_node)); +} + +/* rb_tree_empty - tests if tree is empty */ +static inline bool +rb_tree_empty(rb_tree *tree) { + rb_node *nil = tree->nil, *root = tree->root; + return root->left == nil; +} + +/* * + * rb_tree_create - creates a new red-black tree, the 'compare' function + * is required and returns 'NULL' if failed. + * + * Note that, root->left should always point to the node that is the root + * of the tree. And nil points to a 'NULL' node which should always be + * black and may have arbitrary children and parent node. + * */ +rb_tree * +rb_tree_create(int (*compare)(rb_node *node1, rb_node *node2)) { + assert(compare != NULL); + + rb_tree *tree; + rb_node *nil, *root; + + if ((tree = kmalloc(sizeof(rb_tree))) == NULL) { + goto bad_tree; + } + + tree->compare = compare; + + if ((nil = rb_node_create()) == NULL) { + goto bad_node_cleanup_tree; + } + + nil->parent = nil->left = nil->right = nil; + nil->red = 0; + tree->nil = nil; + + if ((root = rb_node_create()) == NULL) { + goto bad_node_cleanup_nil; + } + + root->parent = root->left = root->right = nil; + root->red = 0; + tree->root = root; + return tree; + +bad_node_cleanup_nil: + kfree(nil); +bad_node_cleanup_tree: + kfree(tree); +bad_tree: + return NULL; +} + +/* * + * FUNC_ROTATE - rotates as described in "Introduction to Algorithm". + * + * For example, FUNC_ROTATE(rb_left_rotate, left, right) can be expaned to a + * left-rotate function, which requires an red-black 'tree' and a node 'x' + * to be rotated on. Basically, this function, named rb_left_rotate, makes the + * parent of 'x' be the left child of 'x', 'x' the parent of its parent before + * rotation and finally fixes other nodes accordingly. + * + * FUNC_ROTATE(xx, left, right) means left-rotate, + * and FUNC_ROTATE(xx, right, left) means right-rotate. + * */ +#define FUNC_ROTATE(func_name, _left, _right) \ +static void \ + func_name(rb_tree *tree, rb_node *x) { \ + rb_node *nil = tree->nil, *y = x->_right; \ + assert(x != tree->root && x != nil && y != nil); \ + x->_right = y->_left; \ + if (y->_left != nil) { \ + y->_left->parent = x; \ + } \ + y->parent = x->parent; \ + if (x == x->parent->_left) { \ + x->parent->_left = y; \ + } \ + else { \ + x->parent->_right = y; \ + } \ + y->_left = x; \ + x->parent = y; \ + assert(!(nil->red)); \ +} + +FUNC_ROTATE(rb_left_rotate, left, right); +FUNC_ROTATE(rb_right_rotate, right, left); + +#undef FUNC_ROTATE + +#define COMPARE(tree, node1, node2) \ +((tree))->compare((node1), (node2)) + +/* * + * rb_insert_binary - insert @node to red-black @tree as if it were + * a regular binary tree. This function is only intended to be called + * by function rb_insert. + * */ +static inline void +rb_insert_binary(rb_tree *tree, rb_node *node) { + rb_node *x, *y, *z = node, *nil = tree->nil, *root = tree->root; + + z->left = z->right = nil; + y = root, x = y->left; + while (x != nil) { + y = x; + x = (COMPARE(tree, x, node) > 0) ? x->left : x->right; + } + z->parent = y; + if (y == root || COMPARE(tree, y, z) > 0) { + y->left = z; + } + else { + y->right = z; + } +} + +/* rb_insert - insert a node to red-black tree */ +void +rb_insert(rb_tree *tree, rb_node *node) { + rb_insert_binary(tree, node); + node->red = 1; + + rb_node *x = node, *y; + +#define RB_INSERT_SUB(_left, _right) \ + do { \ + y = x->parent->parent->_right; \ + if (y->red) { \ + x->parent->red = 0; \ + y->red = 0; \ + x->parent->parent->red = 1; \ + x = x->parent->parent; \ + } \ + else { \ + if (x == x->parent->_right) { \ + x = x->parent; \ + rb_##_left##_rotate(tree, x); \ + } \ + x->parent->red = 0; \ + x->parent->parent->red = 1; \ + rb_##_right##_rotate(tree, x->parent->parent); \ + } \ + } while (0) + + while (x->parent->red) { + if (x->parent == x->parent->parent->left) { + RB_INSERT_SUB(left, right); + } + else { + RB_INSERT_SUB(right, left); + } + } + tree->root->left->red = 0; + assert(!(tree->nil->red) && !(tree->root->red)); + +#undef RB_INSERT_SUB +} + +/* * + * rb_tree_successor - returns the successor of @node, or nil + * if no successor exists. Make sure that @node must belong to @tree, + * and this function should only be called by rb_node_prev. + * */ +static inline rb_node * +rb_tree_successor(rb_tree *tree, rb_node *node) { + rb_node *x = node, *y, *nil = tree->nil; + + if ((y = x->right) != nil) { + while (y->left != nil) { + y = y->left; + } + return y; + } + else { + y = x->parent; + while (x == y->right) { + x = y, y = y->parent; + } + if (y == tree->root) { + return nil; + } + return y; + } +} + +/* * + * rb_tree_predecessor - returns the predecessor of @node, or nil + * if no predecessor exists, likes rb_tree_successor. + * */ +static inline rb_node * +rb_tree_predecessor(rb_tree *tree, rb_node *node) { + rb_node *x = node, *y, *nil = tree->nil; + + if ((y = x->left) != nil) { + while (y->right != nil) { + y = y->right; + } + return y; + } + else { + y = x->parent; + while (x == y->left) { + if (y == tree->root) { + return nil; + } + x = y, y = y->parent; + } + return y; + } +} + +/* * + * rb_search - returns a node with value 'equal' to @key (according to + * function @compare). If there're multiple nodes with value 'equal' to @key, + * the functions returns the one highest in the tree. + * */ +rb_node * +rb_search(rb_tree *tree, int (*compare)(rb_node *node, void *key), void *key) { + rb_node *nil = tree->nil, *node = tree->root->left; + int r; + while (node != nil && (r = compare(node, key)) != 0) { + node = (r > 0) ? node->left : node->right; + } + return (node != nil) ? node : NULL; +} + +/* * + * rb_delete_fixup - performs rotations and changes colors to restore + * red-black properties after a node is deleted. + * */ +static void +rb_delete_fixup(rb_tree *tree, rb_node *node) { + rb_node *x = node, *w, *root = tree->root->left; + +#define RB_DELETE_FIXUP_SUB(_left, _right) \ + do { \ + w = x->parent->_right; \ + if (w->red) { \ + w->red = 0; \ + x->parent->red = 1; \ + rb_##_left##_rotate(tree, x->parent); \ + w = x->parent->_right; \ + } \ + if (!w->_left->red && !w->_right->red) { \ + w->red = 1; \ + x = x->parent; \ + } \ + else { \ + if (!w->_right->red) { \ + w->_left->red = 0; \ + w->red = 1; \ + rb_##_right##_rotate(tree, w); \ + w = x->parent->_right; \ + } \ + w->red = x->parent->red; \ + x->parent->red = 0; \ + w->_right->red = 0; \ + rb_##_left##_rotate(tree, x->parent); \ + x = root; \ + } \ + } while (0) + + while (x != root && !x->red) { + if (x == x->parent->left) { + RB_DELETE_FIXUP_SUB(left, right); + } + else { + RB_DELETE_FIXUP_SUB(right, left); + } + } + x->red = 0; + +#undef RB_DELETE_FIXUP_SUB +} + +/* * + * rb_delete - deletes @node from @tree, and calls rb_delete_fixup to + * restore red-black properties. + * */ +void +rb_delete(rb_tree *tree, rb_node *node) { + rb_node *x, *y, *z = node; + rb_node *nil = tree->nil, *root = tree->root; + + y = (z->left == nil || z->right == nil) ? z : rb_tree_successor(tree, z); + x = (y->left != nil) ? y->left : y->right; + + assert(y != root && y != nil); + + x->parent = y->parent; + if (y == y->parent->left) { + y->parent->left = x; + } + else { + y->parent->right = x; + } + + bool need_fixup = !(y->red); + + if (y != z) { + if (z == z->parent->left) { + z->parent->left = y; + } + else { + z->parent->right = y; + } + z->left->parent = z->right->parent = y; + *y = *z; + } + if (need_fixup) { + rb_delete_fixup(tree, x); + } +} + +/* rb_tree_destroy - destroy a tree and free memory */ +void +rb_tree_destroy(rb_tree *tree) { + kfree(tree->root); + kfree(tree->nil); + kfree(tree); +} + +/* * + * rb_node_prev - returns the predecessor node of @node in @tree, + * or 'NULL' if no predecessor exists. + * */ +rb_node * +rb_node_prev(rb_tree *tree, rb_node *node) { + rb_node *prev = rb_tree_predecessor(tree, node); + return (prev != tree->nil) ? prev : NULL; +} + +/* * + * rb_node_next - returns the successor node of @node in @tree, + * or 'NULL' if no successor exists. + * */ +rb_node * +rb_node_next(rb_tree *tree, rb_node *node) { + rb_node *next = rb_tree_successor(tree, node); + return (next != tree->nil) ? next : NULL; +} + +/* rb_node_root - returns the root node of a @tree, or 'NULL' if tree is empty */ +rb_node * +rb_node_root(rb_tree *tree) { + rb_node *node = tree->root->left; + return (node != tree->nil) ? node : NULL; +} + +/* rb_node_left - gets the left child of @node, or 'NULL' if no such node */ +rb_node * +rb_node_left(rb_tree *tree, rb_node *node) { + rb_node *left = node->left; + return (left != tree->nil) ? left : NULL; +} + +/* rb_node_right - gets the right child of @node, or 'NULL' if no such node */ +rb_node * +rb_node_right(rb_tree *tree, rb_node *node) { + rb_node *right = node->right; + return (right != tree->nil) ? right : NULL; +} + +int +check_tree(rb_tree *tree, rb_node *node) { + rb_node *nil = tree->nil; + if (node == nil) { + assert(!node->red); + return 1; + } + if (node->left != nil) { + assert(COMPARE(tree, node, node->left) >= 0); + assert(node->left->parent == node); + } + if (node->right != nil) { + assert(COMPARE(tree, node, node->right) <= 0); + assert(node->right->parent == node); + } + if (node->red) { + assert(!node->left->red && !node->right->red); + } + int hb_left = check_tree(tree, node->left); + int hb_right = check_tree(tree, node->right); + assert(hb_left == hb_right); + int hb = hb_left; + if (!node->red) { + hb ++; + } + return hb; +} + +static void * +check_safe_kmalloc(size_t size) { + void *ret = kmalloc(size); + assert(ret != NULL); + return ret; +} + +struct check_data { + long data; + rb_node rb_link; +}; + +#define rbn2data(node) \ +(to_struct(node, struct check_data, rb_link)) + +static inline int +check_compare1(rb_node *node1, rb_node *node2) { + return rbn2data(node1)->data - rbn2data(node2)->data; +} + +static inline int +check_compare2(rb_node *node, void *key) { + return rbn2data(node)->data - (long)key; +} + +void +check_rb_tree(void) { + rb_tree *tree = rb_tree_create(check_compare1); + assert(tree != NULL); + + rb_node *nil = tree->nil, *root = tree->root; + assert(!nil->red && root->left == nil); + + int total = 1000; + struct check_data **all = check_safe_kmalloc(sizeof(struct check_data *) * total); + + long i; + for (i = 0; i < total; i ++) { + all[i] = check_safe_kmalloc(sizeof(struct check_data)); + all[i]->data = i; + } + + int *mark = check_safe_kmalloc(sizeof(int) * total); + memset(mark, 0, sizeof(int) * total); + + for (i = 0; i < total; i ++) { + mark[all[i]->data] = 1; + } + for (i = 0; i < total; i ++) { + assert(mark[i] == 1); + } + + for (i = 0; i < total; i ++) { + int j = (rand() % (total - i)) + i; + struct check_data *z = all[i]; + all[i] = all[j]; + all[j] = z; + } + + memset(mark, 0, sizeof(int) * total); + for (i = 0; i < total; i ++) { + mark[all[i]->data] = 1; + } + for (i = 0; i < total; i ++) { + assert(mark[i] == 1); + } + + for (i = 0; i < total; i ++) { + rb_insert(tree, &(all[i]->rb_link)); + check_tree(tree, root->left); + } + + rb_node *node; + for (i = 0; i < total; i ++) { + node = rb_search(tree, check_compare2, (void *)(all[i]->data)); + assert(node != NULL && node == &(all[i]->rb_link)); + } + + for (i = 0; i < total; i ++) { + node = rb_search(tree, check_compare2, (void *)i); + assert(node != NULL && rbn2data(node)->data == i); + rb_delete(tree, node); + check_tree(tree, root->left); + } + + assert(!nil->red && root->left == nil); + + long max = 32; + if (max > total) { + max = total; + } + + for (i = 0; i < max; i ++) { + all[i]->data = max; + rb_insert(tree, &(all[i]->rb_link)); + check_tree(tree, root->left); + } + + for (i = 0; i < max; i ++) { + node = rb_search(tree, check_compare2, (void *)max); + assert(node != NULL && rbn2data(node)->data == max); + rb_delete(tree, node); + check_tree(tree, root->left); + } + + assert(rb_tree_empty(tree)); + + for (i = 0; i < total; i ++) { + rb_insert(tree, &(all[i]->rb_link)); + check_tree(tree, root->left); + } + + rb_tree_destroy(tree); + + for (i = 0; i < total; i ++) { + kfree(all[i]); + } + + kfree(mark); + kfree(all); +} diff --git a/kern/libs/rb_tree.h b/kern/libs/rb_tree.h new file mode 100644 index 0000000..728e15f --- /dev/null +++ b/kern/libs/rb_tree.h @@ -0,0 +1,31 @@ +#ifndef __KERN_LIBS_RB_TREE_H__ +#define __KERN_LIBS_RB_TREE_H__ + +#include + +typedef struct rb_node { + bool red; // if red = 0, it's a black node + struct rb_node *parent; + struct rb_node *left, *right; +} rb_node; + +typedef struct rb_tree { + // compare function should return -1 if *node1 < *node2, 1 if *node1 > *node2, and 0 otherwise + int (*compare)(rb_node *node1, rb_node *node2); + struct rb_node *nil, *root; +} rb_tree; + +rb_tree *rb_tree_create(int (*compare)(rb_node *node1, rb_node *node2)); +void rb_tree_destroy(rb_tree *tree); +void rb_insert(rb_tree *tree, rb_node *node); +void rb_delete(rb_tree *tree, rb_node *node); +rb_node *rb_search(rb_tree *tree, int (*compare)(rb_node *node, void *key), void *key); +rb_node *rb_node_prev(rb_tree *tree, rb_node *node); +rb_node *rb_node_next(rb_tree *tree, rb_node *node); +rb_node *rb_node_root(rb_tree *tree); +rb_node *rb_node_left(rb_tree *tree, rb_node *node); +rb_node *rb_node_right(rb_tree *tree, rb_node *node); + +void check_rb_tree(void); + +#endif /* !__KERN_LIBS_RBTREE_H__ */ diff --git a/kern/mm/buddy_pmm.c b/kern/mm/buddy_pmm.c index dcfcae7..3ec017b 100755 --- a/kern/mm/buddy_pmm.c +++ b/kern/mm/buddy_pmm.c @@ -35,7 +35,7 @@ static void buddy_init_memmap(struct Page *base, size_t n) cprintf("list order=%d ++\n", order); } - --order; + --order; order_size >>= 1; } } @@ -46,7 +46,7 @@ static inline struct Page* buddy_alloc_pages_sub(size_t order) for(size_t i=order; i<=MAX_ORDER; i++) { if(!list_empty(&free_list(i))) { list_entry_t *le = list_next(&free_list(i)); - struct Page *page = tostruct(le, struct Page, page_link); + struct Page *page = to_struct(le, struct Page, page_link); nr_free(i) --; list_del(le); size_t size = 1 << i; @@ -86,7 +86,7 @@ static void buddy_free_pages_sub(struct Page *base, size_t order) flag = 1; break; } - struct Page * buddy = tostruct(le, struct Page, page_link); + struct Page * buddy = to_struct(le, struct Page, page_link); le = list_next(le); size_t p_size = 1<order, buddy_size = 1<order; if(p == buddy+buddy_size) { @@ -172,7 +172,7 @@ const struct pmm_manager buddy_pmm_manager = { .init = buddy_init, .init_memmap = buddy_init_memmap, .alloc_pages = buddy_alloc_pages, - .free_pages = buddy_free_pages, + .free_pages = buddy_free_pages, .check = buddy_check, .pageinfo = buddy_pageinfo, -}; \ No newline at end of file +}; diff --git a/kern/mm/memlayout.h b/kern/mm/memlayout.h index 44479c1..4f110e6 100644 --- a/kern/mm/memlayout.h +++ b/kern/mm/memlayout.h @@ -81,14 +81,14 @@ #include #include -#define E820MAX 20 +#define E820MAX 20 #define E820_ARM 1 // memory #define E820_ARR 2 // reserved struct e820map { int nr_map; - struct + struct { uint64_t addr; uint64_t size; @@ -105,19 +105,24 @@ struct Page #define PG_reserved 0 #define PG_property 1 // if =1 means is valid +#define PG_slab 2 // page frame is included in a slab #define SetPageReserved(page) set_bit(PG_reserved, &((page)->flags)) #define ClearPageReserved(page) clear_bit(PG_reserved, &((page)->flags)) #define PageReserved(page) test_bit(PG_reserved, &((page)->flags)) +#define SetPageSlab(page) set_bit(PG_slab, &((page)->flags)) +#define ClearPageSlab(page) clear_bit(PG_slab, &((page)->flags)) +#define PageSlab(page) test_bit(PG_slab, &((page)->flags)) + #define SetPageProperty(page) set_bit(PG_reserved, &((page)->flags)) #define ClearPageProperty(page) clear_bit(PG_property, &((page)->flags)) #define PageProperty(page) test_bit(PG_property, &((page)->flags)) -typedef struct +typedef struct { list_entry_t free_list; - unsigned int nr_free; // # of free pages + unsigned int nr_free; // # of free pages } free_area_t; #endif diff --git a/kern/mm/mmu.h b/kern/mm/mmu.h index e6095b5..4aaf70c 100644 --- a/kern/mm/mmu.h +++ b/kern/mm/mmu.h @@ -1,5 +1,9 @@ #pragma once +/* Eflags register */ +#define FL_IF 0x00000200 // Interrupt Flag + + /* Application segment type bits */ #define STA_X 0x8 // Executable segment #define STA_E 0x4 // Expand down (non-executable segments) @@ -135,6 +139,8 @@ struct taskstate { #define PDX(la) ((((uintptr_t)(la)) >> 22) & 0x3FF) #define PTX(la) ((((uintptr_t)(la)) >> 12) & 0x3FF) +// page number field of address +#define PPN(la) (((uintptr_t)(la)) >> 12) #define PTE_ADDR(pte) ((uintptr_t)(pte) & ~0xFFF) #define PDE_ADDR(pde) PTE_ADDR(pde) @@ -174,4 +180,3 @@ struct taskstate { #define CR0_NW 0x20000000 // Not Writethrough #define CR0_CD 0x40000000 // Cache Disable #define CR0_PG 0x80000000 // Paging - diff --git a/kern/mm/pmm.c b/kern/mm/pmm.c index ffc504c..9571e75 100755 --- a/kern/mm/pmm.c +++ b/kern/mm/pmm.c @@ -7,6 +7,7 @@ #include #include #include +#include static struct taskstate ts = {0}; @@ -77,7 +78,7 @@ static void page_init(void) extern char end[]; cprintf("end:%x", end); npage = maxpa / PGSIZE; - pages = (struct Page *)ROUND_UP((void*)end, PGSIZE); + pages = (struct Page *)ROUNDUP((void*)end, PGSIZE); // for(int i=0; i KMEMSIZE) free_end = KMEMSIZE; if(begin < free_end) { - begin = ROUND_UP(begin, PGSIZE); - free_end = ROUND_DOWN(free_end, PGSIZE); + begin = ROUNDUP(begin, PGSIZE); + free_end = ROUNDDOWN(free_end, PGSIZE); if(begin < free_end) { cprintf("------- begin:%8llx free_end:%8llx\n", begin, free_end); init_memmap(pa2page(begin), (free_end-begin)/PGSIZE); @@ -149,9 +150,9 @@ gdt_init(void) { static void map_physical_memory(uintptr_t *pgdir, uintptr_t la, size_t size, uintptr_t pa, uint32_t perm) { - size_t n = ROUND_UP(size + PG_OFF(la), PGSIZE) /PGSIZE; - la = ROUND_DOWN(la, PGSIZE); - pa = ROUND_DOWN(pa, PGSIZE); + size_t n = ROUNDUP(size + PG_OFF(la), PGSIZE) /PGSIZE; + la = ROUNDDOWN(la, PGSIZE); + pa = ROUNDDOWN(pa, PGSIZE); for(; n>0; n--,la+=PGSIZE,pa+=PGSIZE) { uintptr_t *pte_p = get_pte(pgdir, la); @@ -207,6 +208,8 @@ void pmm_init(void) print_pgdir(); print_stackframe(); + + slab_init(); } struct Page *alloc_pages(size_t n) diff --git a/kern/mm/pmm.h b/kern/mm/pmm.h index fc02216..58b4444 100755 --- a/kern/mm/pmm.h +++ b/kern/mm/pmm.h @@ -37,6 +37,13 @@ void print_pgdir(void); #define VADDR(kpa) ({uintptr_t __m_kpa = (uintptr_t)(kpa); \ __m_kpa + KERNBASE;}) +/* * + * KADDR - takes a physical address and returns the corresponding kernel virtual address. It panics if you pass an invalid physical address. + * */ +#define KADDR(pa) ({ \ + uintptr_t __m_pa = (pa); \ + (void *) (__m_pa + KERNBASE); \ +}) static inline struct Page* n2page(int n) { @@ -73,3 +80,13 @@ static inline struct Page * pde2page(uintptr_t pde) { return pa2page(PDE_ADDR(pde)); } + +static inline void * +page2kva(struct Page *page) { + return KADDR(page2pa(page)); +} + +static inline struct Page * +kva2page(void *kva) { + return pa2page(PADDR(kva)); +} diff --git a/kern/mm/slab.c b/kern/mm/slab.c new file mode 100644 index 0000000..dd9dc54 --- /dev/null +++ b/kern/mm/slab.c @@ -0,0 +1,455 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* The slab allocator used in ucore is based on an algorithm first introduced by + Jeff Bonwick for the SunOS operating system. The paper can be download from + http://citeseer.ist.psu.edu/bonwick94slab.html + An implementation of the Slab Allocator as described in outline in; + UNIX Internals: The New Frontiers by Uresh Vahalia + Pub: Prentice Hall ISBN 0-13-101908-2 + Within a kernel, a considerable amount of memory is allocated for a finite set + of objects such as file descriptors and other common structures. Jeff found that + the amount of time required to initialize a regular object in the kernel exceeded + the amount of time required to allocate and deallocate it. His conclusion was + that instead of freeing the memory back to a global pool, he would have the memory + remain initialized for its intended purpose. + In our simple slab implementation, the the high-level organization of the slab + structures is simplied. At the highest level is an array slab_cache[SLAB_CACHE_NUM], + and each array element is a slab_cache which has slab chains. Each slab_cache has + two list, one list chains the full allocated slab, and another list chains the notfull + allocated(maybe empty) slab. And each slab has fixed number(2^n) of pages. In each + slab, there are a lot of objects (such as ) with same fixed size(32B ~ 128KB). + + +----------------------------------+ + | slab_cache[0] for 0~32B obj | + +----------------------------------+ + | slab_cache[1] for 33B~64B obj |-->lists for slabs + +----------------------------------+ | + | slab_cache[2] for 65B~128B obj | | + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | + +----------------------------------+ | + | slab_cache[12]for 64KB~128KB obj | | + +----------------------------------+ | + | + slabs_full/slabs_not +---------------------+ + -<-----------<----------<-+ + | | | + slab1 slab2 slab3... + | + |-------|-------| + pages1 pages2 pages3... + | + | + | + slab_t+n*bufctl_t+obj1-obj2-obj3...objn (the size of obj is small) + | + OR + | + obj1-obj2-obj3...objn WITH slab_t+n*bufctl_t in another slab (the size of obj is BIG) + + The important functions are: + kmem_cache_grow(kmem_cache_t *cachep) + kmem_slab_destroy(kmem_cache_t *cachep, slab_t *slabp) + kmalloc(size_t size): used by outside functions need dynamicly get memory + kfree(void *objp): used by outside functions need dynamicly release memory +*/ + +#define BUFCTL_END 0xFFFFFFFFL // the signature of the last bufctl +#define SLAB_LIMIT 0xFFFFFFFEL // the max value of obj number + +typedef size_t kmem_bufctl_t; //the index of obj in slab + +typedef struct slab_s { + list_entry_t slab_link; // the list entry linked to kmem_cache list + void *s_mem; // the kernel virtual address of the first obj in slab + size_t inuse; // the number of allocated objs + size_t offset; // the first obj's offset value in slab + kmem_bufctl_t free; // the first free obj's index in slab +} slab_t; + +// get the slab address according to the link element (see list.h) +#define le2slab(le, member) \ +to_struct((le), slab_t, member) + +typedef struct kmem_cache_s kmem_cache_t; + + +struct kmem_cache_s { + list_entry_t slabs_full; // list for fully allocated slabs + list_entry_t slabs_notfull; // list for not-fully allocated slabs + + size_t objsize; // the fixed size of obj + size_t num; // number of objs per slab + size_t offset; // this first obj's offset in slab + bool off_slab; // the control part of slab in slab or not. + + /* order of pages per slab (2^n) */ + size_t page_order; + + kmem_cache_t *slab_cachep; +}; + +#define MIN_SIZE_ORDER 5 // 32 +#define MAX_SIZE_ORDER 17 // 128k +#define SLAB_CACHE_NUM (MAX_SIZE_ORDER - MIN_SIZE_ORDER + 1) + +static kmem_cache_t slab_cache[SLAB_CACHE_NUM]; + +static void init_kmem_cache(kmem_cache_t *cachep, size_t objsize, size_t align); + +//slab_init - call init_kmem_cache function to reset the slab_cache array +void +slab_init(void) { + size_t i; + //the align bit for obj in slab. 2^n could be better for performance + size_t align = 16; + for (i = 0; i < SLAB_CACHE_NUM; i ++) { + init_kmem_cache(slab_cache + i, 1 << (i + MIN_SIZE_ORDER), align); + } +} + +//slab_allocated - summary the total size of allocated objs +size_t +slab_allocated(void) { + size_t total = 0; + int i; + bool intr_flag; + local_intr_save(intr_flag); + { + for (i = 0; i < SLAB_CACHE_NUM; i ++) { + kmem_cache_t *cachep = slab_cache + i; + list_entry_t *list, *le; + list = le = &(cachep->slabs_full); + while ((le = list_next(le)) != list) { + total += cachep->num * cachep->objsize; + } + list = le = &(cachep->slabs_notfull); + while ((le = list_next(le)) != list) { + slab_t *slabp = le2slab(le, slab_link); + total += slabp->inuse * cachep->objsize; + } + } + } + local_intr_restore(intr_flag); + return total; +} + +// slab_mgmt_size - get the size of slab control area (slab_t+num*kmem_bufctl_t) +static size_t +slab_mgmt_size(size_t num, size_t align) { + return ROUNDUP(sizeof(slab_t) + num * sizeof(kmem_bufctl_t), align); +} + +// cacahe_estimate - estimate the number of objs in a slab +static void +cache_estimate(size_t order, size_t objsize, size_t align, bool off_slab, size_t *remainder, size_t *num) { + size_t nr_objs, mgmt_size; + size_t slab_size = (PGSIZE << order); + + if (off_slab) { + mgmt_size = 0; + nr_objs = slab_size / objsize; + if (nr_objs > SLAB_LIMIT) { + nr_objs = SLAB_LIMIT; + } + } + else { + nr_objs = (slab_size - sizeof(slab_t)) / (objsize + sizeof(kmem_bufctl_t)); + while (slab_mgmt_size(nr_objs, align) + nr_objs * objsize > slab_size) { + nr_objs --; + } + if (nr_objs > SLAB_LIMIT) { + nr_objs = SLAB_LIMIT; + } + mgmt_size = slab_mgmt_size(nr_objs, align); + } + *num = nr_objs; + *remainder = slab_size - nr_objs * objsize - mgmt_size; +} + +// calculate_slab_order - estimate the size(4K~4M) of slab +// paramemters: +// cachep: the slab_cache +// objsize: the size of obj +// align: align bit for objs +// off_slab: the control part of slab in slab or not +// left_over: the size of can not be used area in slab +static void +calculate_slab_order(kmem_cache_t *cachep, size_t objsize, size_t align, bool off_slab, size_t *left_over) { + size_t order; + for (order = 0; order <= KMALLOC_MAX_ORDER; order ++) { + size_t num, remainder; + cache_estimate(order, objsize, align, off_slab, &remainder, &num); + if (num != 0) { + if (off_slab) { + size_t off_slab_limit = objsize - sizeof(slab_t); + off_slab_limit /= sizeof(kmem_bufctl_t); + if (num > off_slab_limit) { + panic("off_slab: objsize = %d, num = %d.", objsize, num); + } + } + if (remainder * 8 <= (PGSIZE << order)) { + cachep->num = num; + cachep->page_order = order; + if (left_over != NULL) { + *left_over = remainder; + } + return ; + } + } + } + panic("calculate_slab_over: failed."); +} + +// getorder - find order, should satisfy n <= minest 2^order +static inline size_t +getorder(size_t n) { + size_t order = MIN_SIZE_ORDER, order_size = (1 << order); + for (; order <= MAX_SIZE_ORDER; order ++, order_size <<= 1) { + if (n <= order_size) { + return order; + } + } + panic("getorder failed. %d\n", n); +} + +// init_kmem_cache - initial a slab_cache cachep according to the obj with the size = objsize +static void +init_kmem_cache(kmem_cache_t *cachep, size_t objsize, size_t align) { + list_init(&(cachep->slabs_full)); + list_init(&(cachep->slabs_notfull)); + + objsize = ROUNDUP(objsize, align); + cachep->objsize = objsize; + cachep->off_slab = (objsize >= (PGSIZE >> 3)); + + size_t left_over; + calculate_slab_order(cachep, objsize, align, cachep->off_slab, &left_over); + + assert(cachep->num > 0); + + size_t mgmt_size = slab_mgmt_size(cachep->num, align); + + if (cachep->off_slab && left_over >= mgmt_size) { + cachep->off_slab = 0; + } + + if (cachep->off_slab) { + cachep->offset = 0; + cachep->slab_cachep = slab_cache + (getorder(mgmt_size) - MIN_SIZE_ORDER); + } + else { + cachep->offset = mgmt_size; + } +} + +static void *kmem_cache_alloc(kmem_cache_t *cachep); + +#define slab_bufctl(slabp) \ +((kmem_bufctl_t*)(((slab_t *)(slabp)) + 1)) + +// kmem_cache_slabmgmt - get the address of a slab according to page +// - and initialize the slab according to cachep +static slab_t * +kmem_cache_slabmgmt(kmem_cache_t *cachep, struct Page *page) { + void *objp = page2kva(page); + slab_t *slabp; + if (cachep->off_slab) { + if ((slabp = kmem_cache_alloc(cachep->slab_cachep)) == NULL) { + return NULL; + } + } + else { + slabp = page2kva(page); + } + slabp->inuse = 0; + slabp->offset = cachep->offset; + slabp->s_mem = objp + cachep->offset; + return slabp; +} + +#define SET_PAGE_CACHE(page, cachep) \ + do { \ + struct Page *__page = (struct Page *)(page); \ + kmem_cache_t **__cachepp = (kmem_cache_t **)&(__page->page_link.next); \ + *__cachepp = (kmem_cache_t *)(cachep); \ +} while (0) + +#define SET_PAGE_SLAB(page, slabp) \ + do { \ + struct Page *__page = (struct Page *)(page); \ + slab_t **__cachepp = (slab_t **)&(__page->page_link.prev); \ + *__cachepp = (slab_t *)(slabp); \ + } while (0) + +// kmem_cache_grow - allocate a new slab by calling alloc_pages +// - set control area in the new slab +static bool +kmem_cache_grow(kmem_cache_t *cachep) { + struct Page *page = alloc_pages(1 << cachep->page_order); + if (page == NULL) goto failed; + + slab_t *slabp; + if ((slabp = kmem_cache_slabmgmt(cachep, page)) == NULL) { + goto oops; + } + + size_t order_size = (1 << cachep->page_order); + do { + //setup this page in the free list (see memlayout.h: struct page)??? + SET_PAGE_CACHE(page, cachep); + SET_PAGE_SLAB(page, slabp); + //this page is used for slab + SetPageSlab(page); + page ++; + } while (-- order_size); + + int i; + for (i = 0; i < cachep->num; i ++) { + slab_bufctl(slabp)[i] = i + 1; + } + slab_bufctl(slabp)[cachep->num - 1] = BUFCTL_END; + slabp->free = 0; + + bool intr_flag; + local_intr_save(intr_flag); + { + list_add(&(cachep->slabs_notfull), &(slabp->slab_link)); + } + local_intr_restore(intr_flag); + return 1; + + oops: + free_pages(page, 1 << cachep->page_order); + failed: + return 0; +} + +// kmem_cache_alloc_one - allocate a obj in a slab +static void * +kmem_cache_alloc_one(kmem_cache_t *cachep, slab_t *slabp) { + slabp->inuse ++; + void *objp = slabp->s_mem + slabp->free * cachep->objsize; + slabp->free = slab_bufctl(slabp)[slabp->free]; + + if (slabp->free == BUFCTL_END) { + list_del(&(slabp->slab_link)); + list_add(&(cachep->slabs_full), &(slabp->slab_link)); + } + return objp; +} + +// kmem_cache_alloc - call kmem_cache_alloc_one function to allocate a obj +// - if no free obj, try to allocate a slab +static void * +kmem_cache_alloc(kmem_cache_t *cachep) { + void *objp; + bool intr_flag; + +try_again: + local_intr_save(intr_flag); + if (list_empty(&(cachep->slabs_notfull))) { + goto alloc_new_slab; + } + slab_t *slabp = le2slab(list_next(&(cachep->slabs_notfull)), slab_link); + objp = kmem_cache_alloc_one(cachep, slabp); + local_intr_restore(intr_flag); + return objp; + +alloc_new_slab: + local_intr_restore(intr_flag); + + if (kmem_cache_grow(cachep)) { + goto try_again; + } + return NULL; +} + +// kmalloc - simple interface used by outside functions +// - to allocate a free memory using kmem_cache_alloc function +void * +kmalloc(size_t size) { + assert(size > 0); + size_t order = getorder(size); + if (order > MAX_SIZE_ORDER) return NULL; + + return kmem_cache_alloc(slab_cache + (order - MIN_SIZE_ORDER)); +} + +static void kmem_cache_free(kmem_cache_t *cachep, void *obj); + +// kmem_slab_destroy - call free_pages & kmem_cache_free to free a slab +static void +kmem_slab_destroy(kmem_cache_t *cachep, slab_t *slabp) { + struct Page *page = kva2page(slabp->s_mem - slabp->offset); + + struct Page *p = page; + size_t order_size = (1 << cachep->page_order); + do { + assert(PageSlab(p)); + ClearPageSlab(p); + p ++; + } while (-- order_size); + + free_pages(page, 1 << cachep->page_order); + + if (cachep->off_slab) { + kmem_cache_free(cachep->slab_cachep, slabp); + } +} + +// kmem_cache_free_one - free an obj in a slab +// - if slab->inuse==0, then free the slab +static void +kmem_cache_free_one(kmem_cache_t *cachep, slab_t *slabp, void *objp) { + //should not use divide operator ??? + size_t objnr = (objp - slabp->s_mem) / cachep->objsize; + slab_bufctl(slabp)[objnr] = slabp->free; + slabp->free = objnr; + + slabp->inuse --; + + if (slabp->inuse == 0) { + list_del(&(slabp->slab_link)); + kmem_slab_destroy(cachep, slabp); + } + else if (slabp->inuse == cachep->num -1 ) { + list_del(&(slabp->slab_link)); + list_add(&(cachep->slabs_notfull), &(slabp->slab_link)); + } +} + +#define GET_PAGE_CACHE(page) \ +(kmem_cache_t *)((page)->page_link.next) + +#define GET_PAGE_SLAB(page) \ +(slab_t *)((page)->page_link.prev) + +// kmem_cache_free - call kmem_cache_free_one function to free an obj +static void +kmem_cache_free(kmem_cache_t *cachep, void *objp) { + bool intr_flag; + struct Page *page = kva2page(objp); + + if (!PageSlab(page)) { + panic("not a slab page %08x\n", objp); + } + local_intr_save(intr_flag); + { + kmem_cache_free_one(cachep, GET_PAGE_SLAB(page), objp); + } + local_intr_restore(intr_flag); +} + +// kfree - simple interface used by ooutside functions to free an obj +void +kfree(void *objp) { + kmem_cache_free(GET_PAGE_CACHE(kva2page(objp)), objp); +} diff --git a/kern/mm/slab.h b/kern/mm/slab.h new file mode 100644 index 0000000..9c674b3 --- /dev/null +++ b/kern/mm/slab.h @@ -0,0 +1,15 @@ +#ifndef __KERN_MM_SLAB_H__ +#define __KERN_MM_SLAB_H__ + +#include + +#define KMALLOC_MAX_ORDER 10 + +void slab_init(void); + +void *kmalloc(size_t n); +void kfree(void *objp); + +size_t slab_allocated(void); + +#endif /* !__KERN_MM_SLAB_H__ */ diff --git a/kern/sync/sync.h b/kern/sync/sync.h new file mode 100644 index 0000000..38f9a96 --- /dev/null +++ b/kern/sync/sync.h @@ -0,0 +1,24 @@ +#pragma once + +#include +#include +#include + +static inline bool +__intr_save(void) { + if (read_eflags() & FL_IF) { + intr_disable(); + return 1; + } + return 0; +} + +static inline void +__intr_restore(bool flag) { + if (flag) { + intr_enable(); + } +} + +#define local_intr_save(x) do { x = __intr_save(); } while (0) +#define local_intr_restore(x) __intr_restore(x); diff --git a/libs/cpp.c b/libs/cpp.c new file mode 100644 index 0000000..7e85342 --- /dev/null +++ b/libs/cpp.c @@ -0,0 +1 @@ +void * _obj_arg_; diff --git a/libs/cpp.h b/libs/cpp.h new file mode 100644 index 0000000..a2819a6 --- /dev/null +++ b/libs/cpp.h @@ -0,0 +1,12 @@ +#pragma once + +#define this m(self) +#define m(pInst) ((pInst)->_method_(pInst)) + +#define Define_Method(T) T * T##$Method(T *ps){_obj_arg_ = ps;return ps;} +#define Define_Member(T) struct T * (* _method_)(struct T * ps); +#define Declare_Method(T) T * T##$Method(T * ps); +#define Register_Method(pInst,T) pInst->_method_ = T##$Method; +#define MethodOf(T) T * self = (T *)_obj_arg_; + +extern void *_obj_arg_; diff --git a/libs/rand.c b/libs/rand.c new file mode 100644 index 0000000..1250c32 --- /dev/null +++ b/libs/rand.c @@ -0,0 +1,25 @@ +#include +#include + +static unsigned long long next = 1; + +/* * + * rand - returns a pseudo-random integer + * + * The rand() function return a value in the range [0, RAND_MAX]. + * */ +int +rand(void) { + next = (next * 0x5DEECE66DLL + 0xBLL) & ((1LL << 48) - 1); + unsigned long long result = (next >> 12); + return (int)do_div(result, RAND_MAX + 1); +} + +/* * + * srand - seed the random number generator with the given number + * @seed: the required seed number + * */ +void +srand(unsigned int seed) { + next = seed; +} diff --git a/libs/stdlib.h b/libs/stdlib.h new file mode 100644 index 0000000..07de5c6 --- /dev/null +++ b/libs/stdlib.h @@ -0,0 +1,16 @@ +#ifndef __LIBS_STDLIB_H__ +#define __LIBS_STDLIB_H__ + +#include + +/* the largest number rand will return */ +#define RAND_MAX 2147483647UL + +/* libs/rand.c */ +int rand(void); +void srand(unsigned int seed); + +/* libs/hash.c */ +uint32_t hash32(uint32_t val, unsigned int bits); + +#endif /* !__LIBS_RAND_H__ */ diff --git a/libs/stringbuffer.c b/libs/stringbuffer.c index 805010e..c5648c3 100644 --- a/libs/stringbuffer.c +++ b/libs/stringbuffer.c @@ -1,5 +1,6 @@ #include #include +#include void buffer_init(StringBuffer *sb, char *buf, int size) @@ -21,7 +22,7 @@ void buffer_push(StringBuffer *sb, char ch) *(sb->top++) = ch; } -char buffer_pop(StringBuffer *sb) +char buffer_pop(StringBuffer *sb) { if(sb->top == sb->base) return 0; return *(--sb->top); @@ -36,6 +37,7 @@ void keybuf_init(keybuf_t *pkb) bool keybuf_push(keybuf_t *pkb, char ch) { + cprintf("keybuf: %x ch:%c\n", pkb, ch); if(pkb->front-pkb->rear == 1) return 0; if((pkb->front==0 && pkb->rear==31)) @@ -43,6 +45,7 @@ bool keybuf_push(keybuf_t *pkb, char ch) pkb->data[pkb->rear] = ch; if(++pkb->rear == 32) pkb->rear = 0; + cprintf("hello\n"); return 1; } @@ -55,4 +58,4 @@ char keybuf_pop(keybuf_t *pkb) pkb->front = 0; return c; -} \ No newline at end of file +} diff --git a/libs/types.h b/libs/types.h index 2e5dd5a..4cc4b6f 100644 --- a/libs/types.h +++ b/libs/types.h @@ -33,36 +33,15 @@ typedef uint32_t uintptr_t; /* size_t is used for memory object sizes */ typedef uintptr_t size_t; -typedef struct rgb_s -{ - uint8_t r; - uint8_t g; - uint8_t b; -} rgb_t; -typedef struct point_s -{ - int32_t x; - int32_t y; -} point_t; -typedef struct rect_s -{ - int32_t left; - int32_t top; - uint32_t width; - uint32_t height; -// struct rect_s(int32_t l=0, int32_t t=0, uint32_t w=0, uint32_t h=0):left(l), top(t), width(w), height(h) {} -} rect_t; - -#define ROUND_DOWN(a, n) ({size_t __a = (size_t)(a); \ +#define ROUNDDOWN(a, n) ({size_t __a = (size_t)(a); \ (typeof(a))(__a - __a%(n));}) -#define ROUND_UP(a, n) ({size_t __n = (size_t)n; \ - (typeof(a))(ROUND_DOWN((size_t)(a) + __n-1, __n));}) +#define ROUNDUP(a, n) ({size_t __n = (size_t)n; \ + (typeof(a))(ROUNDDOWN((size_t)(a) + __n-1, __n));}) #define offsetof(type, member) ((size_t)(&((type*)0)->member)) -#define tostruct(ptr, type, member) ((type*)((char*)(ptr) - offsetof(type, member))) +#define to_struct(ptr, type, member) ((type*)((char*)(ptr) - offsetof(type, member))) #endif /* !__LIBS_TYPES_H__ */ -