├── AUTHORS ├── COPYING ├── COPYINGv3 ├── INSTALL ├── Makefile ├── README.md ├── aclocal.m4 ├── config.guess ├── config.mk.in ├── config.sub ├── configure.in ├── docs ├── asm_ex.asm ├── code_flow.txt ├── longmode_ex.asm ├── memory_map.txt ├── mp_spec.txt ├── paging.txt ├── qemu.txt ├── slab.txt ├── spinlock_test │ ├── Makefile │ ├── a.out │ ├── ddd │ └── lock.c ├── symbols.txt └── x86_64-asm.txt ├── install-sh ├── run.bat ├── run.sh ├── src ├── Makefile ├── a20.inc ├── apic.c ├── bootsect.asm ├── except_entry.asm ├── except_handler.c ├── gdt.c ├── idt.c ├── include │ ├── apic.h │ ├── atomic.h │ ├── bitops.h │ ├── cdev.h │ ├── char_device.h │ ├── except_entry.h │ ├── except_handler.h │ ├── gdt.h │ ├── idt.h │ ├── init.h │ ├── io.h │ ├── io_apic.h │ ├── irq_entry.h │ ├── irq_handler.h │ ├── irq_vector.h │ ├── keyboard.h │ ├── list.h │ ├── memory.h │ ├── mp_spec.h │ ├── msr.h │ ├── oops.h │ ├── page-flags.h │ ├── page.h │ ├── page_alloc.h │ ├── percpu.h │ ├── pgtable.h │ ├── pic8259.h │ ├── platform.h.in │ ├── printf.h │ ├── process.h │ ├── processor.h │ ├── sched.h │ ├── screen.h │ ├── setup.h │ ├── slab.h │ ├── smp.h │ ├── spinlock.h │ ├── stamp-h1 │ ├── string.h │ ├── syscall.h │ ├── types.h │ ├── user_syscall.h │ └── user_tasks.h ├── io_apic.c ├── irq_entry.asm ├── irq_handler.c ├── keyboard.c ├── ld-script.ld ├── main.c ├── memory.c ├── mp_spec.c ├── page.c ├── page_alloc.c ├── percpu.c ├── pic8259.c ├── printf.c ├── process.c ├── screen.c ├── setup.asm ├── setup.c ├── slab.c ├── smp.c ├── spinlock.c └── string.c ├── unittest ├── Makefile └── test_atomic.c └── utils ├── Makefile ├── gen_section.c └── test_utils.c /AUTHORS: -------------------------------------------------------------------------------- 1 | Authors of CaOS64 2 | 3 | written by 4 | Gi-Oh Kim gurugio@hanmail.net 5 | 6 | special thanks to 7 | In-Hyuk Kim @SungKyunKwan Univ. 8 | 9 | 10 | 11 | ======================================================================== 12 | 13 | Local Variables: 14 | mode: text 15 | coding: utf-8 16 | End: 17 | 18 | Copyright (C) 1996, 2000, 2001, 2005, 2007 Free Software Foundation, Inc. 19 | 20 | This program is free software: you can redistribute it and/or modify 21 | it under the terms of the GNU General Public License as published by 22 | the Free Software Foundation, either version 3 of the License, or 23 | (at your option) any later version. 24 | 25 | This program is distributed in the hope that it will be useful, 26 | but WITHOUT ANY WARRANTY; without even the implied warranty of 27 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 28 | GNU General Public License for more details. 29 | 30 | You should have received a copy of the GNU General Public License 31 | along with this program. If not, see . 32 | -------------------------------------------------------------------------------- /INSTALL: -------------------------------------------------------------------------------- 1 | How to build kernel image 2 | 1. install 64bit gcc/ld/objcopy 3 | eg) x86_64-pc-elf-gcc, x86_64-pc-linux-ld, x86_64-pc-linux-objcopy 4 | 2. install nasm v2.0 or more recent version 5 | 3. necessary utilities: gtags, nm, objdump 6 | 4. $ autoconf 7 | 4.1 configure is generated 8 | 5. $ ./configure 9 | 5.1 config.mk is generated 10 | 6. $ make 11 | 7. check floppy.img, disasm.txt system.map in image directory 12 | 8. $ bash run.sh (on Linux) or run.bat (on Windows) 13 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # 64bit compiler tool commands 2 | include config.mk 3 | 4 | # utils directory must be build first 5 | all: 6 | mkdir ./image 7 | make -C utils 8 | make -C src 9 | 10 | clean: 11 | make -C utils clean 12 | make -C src clean 13 | rm -rf ./image 14 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | CaOS64 (Calcium OS for 64bit x86_64) 3 | ==================================== 4 | 5 | CaOS64 is a study-kernel for x86_64 multiprocessor platform. 6 | 7 | I hope that CaOS64 may provide the energy like calcium nutrition for system-programmers 8 | 9 | More calcium, better health and better programming 10 | 11 | features 12 | ======== 13 | * 32bit protected mode/64bit long mode 14 | * segmentation and paging 15 | * context switching of three user-mode processes 16 | * keyboard and timer interrupt handler 17 | * support dual-core processor and up to 512MB physical memory 18 | * dynamic memory allocation with slab memory manager 19 | * Keyboard IRQ handler 20 | * Local timer IRQ handler for each processor 21 | 22 | 23 | License 24 | ========= 25 | CaOS64 is released under the General Public License (GPL). 26 | For more licensing information, see 27 | . 28 | 29 | ----- 30 | 31 | Copyright (C) 1992, 1993, 1994, 1998, 2000, 2001, 2002, 2003, 2004, 32 | 2005, 2006, 2007, 2008 Free Software Foundation, Inc. 33 | 34 | This program is free software: you can redistribute it and/or modify 35 | it under the terms of the GNU General Public License as published by 36 | the Free Software Foundation, either version 3 of the License, or 37 | (at your option) any later version. 38 | 39 | This program is distributed in the hope that it will be useful, 40 | but WITHOUT ANY WARRANTY; without even the implied warranty of 41 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 42 | GNU General Public License for more details. 43 | 44 | You should have received a copy of the GNU General Public License 45 | along with this program. If not, see . 46 | -------------------------------------------------------------------------------- /config.mk.in: -------------------------------------------------------------------------------- 1 | HOST=@host@ 2 | CPU=@CAOS_CFG_CPU@ 3 | NASM=@NASM@ 4 | GCC64=@CC@ 5 | LD64=@LD@ 6 | OBJCOPY64=@OBJCOPY@ 7 | DD=@DD@ 8 | NM=@NM@ 9 | -------------------------------------------------------------------------------- /configure.in: -------------------------------------------------------------------------------- 1 | dnl # Initialize configure 2 | 3 | AC_INIT([./configure]) 4 | AM_INIT_AUTOMAKE(CaOS, 1.0) 5 | 6 | dnl # Check required autoconf version 7 | 8 | AC_PREREQ([2.13]) 9 | 10 | dnl # platform output file 11 | AC_CONFIG_HEADER([./src/include/platform.h]) 12 | 13 | 14 | dnl # tools 15 | 16 | 17 | dnl # gawk 18 | AC_PROG_AWK 19 | 20 | 21 | dnl # nasm install check 22 | AC_PATH_PROG([NASM], [nasm]) 23 | 24 | if test -z "$NASM"; then 25 | AC_MSG_ERROR([Cannot find Netwide Assembler]) 26 | fi 27 | 28 | AC_SUBST(NASM) 29 | 30 | dnl # nasm version check 31 | ${NASM} -v | grep version > nasm_version.tmp 32 | 33 | AC_MSG_CHECKING([whether NASM version >= 2.0 for 64bit assembly]) 34 | 35 | result=`cat nasm_version.tmp | awk '{print $3}'` 36 | nasm_major=`echo $result | awk -F . '{print $1}'` 37 | rm -f nasm_version.tmp 38 | 39 | if test "$nasm_major" -lt 2; then 40 | AC_MSG_ERROR([nasm version is below than 2.0]) 41 | else 42 | AC_MSG_RESULT([yes]) 43 | fi 44 | 45 | 46 | dnl # gcc install 47 | 48 | if test -z "$CC"; then 49 | CC=gcc 50 | fi 51 | 52 | dnl # gcc version >= 4.3 for -mcmodel=large option 53 | AC_MSG_CHECKING([whether GCC version >= 4.3.2 for -mcmodel=large option]) 54 | 55 | ${CC} -v 2> gcc_version.tmp 56 | 57 | result=`grep "gcc version" gcc_version.tmp | awk '{print $3}'` 58 | rm -f gcc_version.tmp 59 | echo "result=${result}" 60 | gcc_major=`echo $result | awk -F . '{print $1}'` 61 | gcc_minor=`echo $result | awk -F . '{print $2}'` 62 | gcc_minor_minor=`echo $result | awk -F . '{print $3}'` 63 | 64 | if test "$gcc_major" -ge 4 && test "$gcc_minor" = 3 && test "$gcc_minor_minor" -ge 2 65 | then 66 | AC_MSG_RESULT([yes]) 67 | elif test "$gcc_major" -ge 4 && test "$gcc_minor" -ge 4 68 | then 69 | AC_MSG_RESULT([yes]) 70 | else 71 | echo "current gcc is \"${CC}\"-${gcc_major}.${gcc_minor}.${gcc_minor_minor}" 72 | echo "you can define gcc as \"CC=your-gcc ./configure\"" 73 | AC_MSG_ERROR([current gcc version cannot process 64bit address]) 74 | fi 75 | 76 | AC_SUBST(CC) 77 | 78 | dnl # ld support x86_64 79 | AC_MSG_CHECKING([whether ld supports elf_x86_64]) 80 | 81 | if test -z "${LD}" ; then 82 | LD=ld 83 | fi 84 | 85 | result=`${LD} -V | grep elf_x86_64` 86 | 87 | if test -z "$result" ; then 88 | echo "current ld is \"${LD}\"" 89 | echo "you can define ld as \"LD=your-ld ./configure\"" 90 | AC_MSG_ERROR([current ld do not support elf_x86_64, please install 64bit ld]) 91 | else 92 | AC_MSG_RESULT([yes]) 93 | fi 94 | 95 | AC_SUBST(LD) 96 | 97 | dnl # objcopy support x86_64 98 | AC_MSG_CHECKING([whether objcopy supports elf64-x86-64]) 99 | 100 | if test -z "$OBJCOPY" ; then 101 | OBJCOPY=objcopy 102 | fi 103 | 104 | result=`${OBJCOPY} -h | grep elf64-x86-64` 105 | 106 | if test -z "$result" ; then 107 | echo "current objcopy is \"${OBJCOPY}\"" 108 | echo "you can define objcopy as \"OBJCOPY=your-objcopy ./configure\"" 109 | AC_MSG_ERROR([current objcopy do not support elf-x86-64, please install 110 | 64bit objcopy]) 111 | else 112 | AC_MSG_RESULT([yes]) 113 | fi 114 | 115 | AC_SUBST(OBJCOPY) 116 | 117 | dnl # extra tools 118 | AC_PATH_PROG([DD], [dd]) 119 | AC_PATH_PROG([NM], [nm]) 120 | 121 | AC_SUBST(DD) 122 | AC_SUBST(NM) 123 | 124 | 125 | dnl # host 126 | 127 | AC_CANONICAL_HOST() 128 | 129 | CAOS_CFG_CPU=UNKNOWN 130 | CAOS_CFG_CPU_BIT=0 131 | CAOS_CFG_MAJOR_VER=0 132 | CAOS_CFG_MINOR_VER=0 133 | 134 | echo "" 135 | echo "HOST PLATFORM: ${host}" 136 | echo "" 137 | 138 | case "${host}" in 139 | i[3456]86-* ) 140 | CAOS_CFG_CPU=i386 141 | CAOS_CFG_CPU_BIT=32 142 | ;; 143 | amd64-*-* ) 144 | CAOS_CFG_CPU=AMD64 145 | CAOS_CFG_CPU_BIT=64 146 | ;; 147 | x86_64-* ) 148 | CAOS_CFG_CPU=X86_64 149 | CAOS_CFG_CPU_BIT=64 150 | ;; 151 | esac 152 | 153 | 154 | 155 | AC_DEFINE_UNQUOTED(CAOS_CFG_CPU_$CAOS_CFG_CPU, 1) 156 | AC_DEFINE_UNQUOTED(CAOS_CFG_CPU, "$CAOS_CFG_CPU") 157 | AC_DEFINE_UNQUOTED(CAOS_CFG_CPU_BIT_$CAOS_CFG_CPU_BIT, 1) 158 | AC_DEFINE_UNQUOTED(CAOS_CFG_CPU_BIT, "$CAOS_CFG_CPU_BIT") 159 | 160 | 161 | AC_SUBST(CAOS_CFG_CPU) 162 | AC_SUBST(CAOS_CFG_CPU_BIT) 163 | 164 | AC_OUTPUT([config.mk]) 165 | 166 | 167 | dnl # remove temporary files 168 | rm -f ./config.cache ./config.log ./config.status 169 | -------------------------------------------------------------------------------- /docs/asm_ex.asm: -------------------------------------------------------------------------------- 1 | ; 2009.1.20 gurugio 2 | 3 | 4 | [bits 64] 5 | 6 | ; for x86_64 processor assembly 7 | [CPU X64] 8 | 9 | 10 | ; only RIP-relative addressing is active for x86_64 processor 11 | [DEFAULT REL] 12 | 13 | extern caos_putchar 14 | 15 | 16 | ; caos_printf cannot be invoked...WHT??? 17 | ;extern caos_printf 18 | 19 | section .text 20 | global _start 21 | 22 | _start: 23 | 24 | ; According to the AMD64 ABI Draft 0.99, 25 | ; rbx, rbp, r12-r15 registers must be preserved across function calls 26 | push rbx 27 | push rbp 28 | 29 | push r12 30 | push r13 31 | push r14 32 | push r15 33 | 34 | 35 | 36 | ; only "MOV reg64, imm64" intruction can take a full 64bit immediate value. 37 | mov r15, 0x12345678abcdef 38 | 39 | ; data is accessed with RIP-relative addressing 40 | ; function parameter is passed in rdi, rsi, rdx, rcx, r8, r9, stack~ 41 | mov rdi, [byte msg] 42 | call _test_asm 43 | 44 | 45 | ; data is accessed with RIP-relative addressing 46 | mov rdx, [byte msg] 47 | add dl, 1 48 | mov byte [byte msg], dl 49 | 50 | 51 | pop r15 52 | pop r14 53 | pop r13 54 | pop r12 55 | 56 | pop rbp 57 | pop rbx 58 | 59 | ret 60 | 61 | global _test_asm 62 | _test_asm: 63 | ; According to the AMD64 ABI Draft 0.99, 64 | ; rbx, rbp, r12-r15 registers must be preserved across function calls 65 | push rbx 66 | push rbp 67 | 68 | push r12 69 | push r13 70 | push r14 71 | push r15 72 | 73 | 74 | push rdi 75 | 76 | mov rdi, 'T' 77 | call caos_putchar 78 | mov rdi, 'e' 79 | call caos_putchar 80 | mov rdi, 's' 81 | call caos_putchar 82 | mov rdi, 't' 83 | call caos_putchar 84 | 85 | ; function argument is in rdi 86 | pop rdi 87 | call caos_putchar 88 | 89 | 90 | pop r15 91 | pop r14 92 | pop r13 93 | pop r12 94 | 95 | pop rbp 96 | pop rbx 97 | 98 | 99 | 100 | ret 101 | 102 | 103 | section .data 104 | msg db '0' 105 | 106 | -------------------------------------------------------------------------------- /docs/code_flow.txt: -------------------------------------------------------------------------------- 1 | [ Code Flow ] 2 | 3 | 4 | 2009.1.20 gurugio 5 | 6 | 7 | 1. bootsec.asm 8 | 9 | - Loads setup.asm and kernel image into physical memory. 10 | - Print 'C' on screen. 11 | 12 | 2. setup.asm 13 | + [16bit mode] 14 | - int 0x15, EAX=0xEC00, EBX=2 : tell BIOS that operating mode will be Long Mode 15 | - Print 'a' on screen 16 | - Set setup_msg variable zero 17 | - Build GDT at 0x8000 which is used only assembly language booting stage 18 | - Load GDT address into GDTR 19 | - Set PE bit in CR0 20 | 21 | + [32bit mode] 22 | - Set booting-stack at 0xA0000 (At least 0x98000~0xA0000 area should be free) 23 | - Set PAE bit in CR4 24 | - Build PML4 table at 0x90000, PML4[0] = PML[128] = PDP address 25 | - Build PDP table at 0x91000, PDP[0] = PDE address 26 | - Build PDE table at 0x92000, PDE[0] = PTE0, PDE[1] = PTE1, PDE[2] = PTE2, PDE[3] = PTE3 27 | - Build PTE0~3 tables at 0x93000, 0x94000, 0x95000, 0x96000 28 | + Now physical memory address 0~8MB is mapped to linear address 0~8MB and also 0xFFFF800000000000~0xFFFF800000800000 29 | - Load PML4 address into CR3 30 | - Set EFER.LME bit in MSR 0xC0000080 to activate long-mode 31 | - Set PG bit in CR0 to enable paging 32 | 33 | + [64bit mode] 34 | - Check that LMA bit in EFER is been setted. 35 | - Set PAE, PGE bit in CR4 in order to flush TLB 36 | - Set SCE bit in EFER 37 | - Copy kernel image from 0xA000 to 0x100000 38 | - Set kernel stack at KERNEL_STACK_START (0xFFFF800000000000 + 2MB) 39 | - Print 'L' on screen 40 | - Jump to start_kernel function with processor index as parameter 41 | 42 | 3. main.c 43 | - Initialize screen output and printf is available, init_screen() 44 | + Architecture-dependent setup, setup_arch() 45 | - Init booting-memory manager, bootmem_init() 46 | - Build GDT, IDT again, gdt_init(), idt_init(), irq_init() 47 | - Build pageing-tables again, paging_init() 48 | - Build mem_map and memory zones, mem_map_init(), memory_init() 49 | + Page-allocation and byte-size allocation are available 50 | - Read data-tables to init SMP, smp_init() 51 | - Setup PIC8259, pic8259_init() 52 | - Init local APIC of BSP and setup local timer, init_local_apic(), init_bsp_timer() 53 | - Wake up the second processor 54 | - Setup keyboard input with IRQ 0x1 through PIC8259, keyboard_init() 55 | - Accept IRQs, sti() 56 | - End of kernel booting 57 | -------------------------------------------------------------------------------- /docs/longmode_ex.asm: -------------------------------------------------------------------------------- 1 | ; 2009.1.20 gurugio 2 | 3 | ;==================================================== 4 | ; FILE NAME: bootsect.asm 5 | ; nasm -o boot.img bootsect.asm 6 | ;==================================================== 7 | 8 | 9 | [bits 16] 10 | 11 | [org 0x0] 12 | 13 | BOOT_SEG equ 0x7c0 14 | 15 | jmp BOOT_SEG:start 16 | 17 | 18 | start: 19 | mov ax, cs 20 | mov ss, ax 21 | mov sp, 0x0 22 | 23 | 24 | ; STEP 1. check CPUID is available 25 | 26 | ; eflag 의 21번 비트가 CPUID 명령어를 지원하는지를 나타내는 비트가 27 | ; 이 비트의 값을 소프트웨어가 소프트웨어가 반전할 수 있으면 CPUID 명령을 지원함 28 | pushf 29 | pop eax 30 | mov ebx, eax 31 | xor eax, 0x200000 ; 반전 32 | push eax 33 | popf 34 | pushf 35 | pop eax 36 | 37 | mov edx, 0x11111111 38 | jz no_longmode 39 | 40 | mov ax, 0xb800 41 | mov es, ax 42 | mov bx, 0x0 43 | mov al, '1' 44 | mov byte [es:bx], al 45 | 46 | ;----------------------------- 47 | ; STEP 2. Dual Processor 48 | 49 | mov eax, 0x1 50 | cpuid 51 | mov ecx, eax 52 | 53 | ; eax[13:12] : Processor Type 54 | ; 10 = Dual Processor 55 | and eax, 0x3000 56 | xor eax, 0x200000 57 | 58 | mov edx, 0x22222222 59 | jz no_longmode 60 | 61 | 62 | ; edx[3]: Page size Extension 63 | ; edx[5]: Model Specific Registers 64 | ; edx[6]: Physical Address Extension 65 | ; edx[13]: Page Global Enable 66 | and edx, (0x1<<3 | 0x1<<5 | 0x1<<6 | 0x1<<13) 67 | 68 | mov edx, 0x33333333 69 | jz no_longmode 70 | 71 | mov ax, 0xb800 72 | mov es, ax 73 | mov bx, 0x2 74 | mov al, '2' 75 | mov byte [es:bx], al 76 | 77 | ;------------------------------ 78 | ; STEP 3. Extended CPUID functions is available 79 | 80 | mov eax, 0x80000000 81 | cpuid 82 | 83 | ; eax: the largest extended function number 84 | ; 최소한 0x80000001 은 지원되야 함 85 | cmp eax, 0x80000001 86 | mov edx, 0x33333333 87 | jb no_longmode 88 | 89 | 90 | mov ax, 0xb800 91 | mov es, ax 92 | mov bx, 0x4 93 | mov al, '3' 94 | mov byte [es:bx], al 95 | 96 | 97 | ;-------------------------------- 98 | ; STEP 4. INTEL 64 instruction setup 99 | 100 | mov eax, 0x80000001 101 | cpuid 102 | and edx, (0x1<<29) 103 | 104 | mov edx, 0x44444444 105 | jz no_longmode 106 | 107 | 108 | mov ax, 0xb800 109 | mov es, ax 110 | mov bx, 0x6 111 | mov al, '4' 112 | mov byte [es:bx], al 113 | 114 | 115 | ;; 화면 첫줄에 1234가 출력되야 함 116 | ;; 117 | 118 | jmp $ 119 | 120 | 121 | no_longmode: 122 | 123 | mov ax, 0xb800 124 | mov es, ax 125 | mov bx, 0x0 126 | mov al, 'X' 127 | mov byte [es:bx], al 128 | 129 | jmp $ 130 | 131 | 132 | 133 | times 510-($-$$) db 0 134 | dw 0xaa55 135 | 136 | 137 | 138 | -------------------------------------------------------------------------------- /docs/memory_map.txt: -------------------------------------------------------------------------------- 1 | 2 | [ Memory Map ] 3 | 4 | 5 | 2009.1.20 gurugio 6 | 7 | 8 | 9 | 1. booting step, physical memory map 10 | 11 | First, bootsect.asm loads setup.asm and kernel.img and executes setup.asm. 12 | Second setup.asm copies kernel.img at 0x100000 (1MB) and build GDT to activate protected mode. The setup.asm activates protected mode and immediatly long mode. 13 | 14 | The setup.asm must build paging tables (PML4,PDP,PDE,PTEs) to turn into long mode so that the linear address is considered than physical address. 15 | 16 | 17 | 18 | 0x0 ~ 0x1000 BIOS reserved 19 | ~~~~~~~~~~~ free 20 | 21 | 0x8000 ~ 0x9000 GDT 22 | ~~~~~~~~~~~ free 23 | 24 | 0x9000 ~ 0xA000 setup.asm 25 | 0xA000 ~~~~~~ first-loaded kernel 26 | ~~~~~~~~~~~ free 27 | 28 | 0x90000 ~ 0x91000 PML4 29 | 0x91000 ~ 0x92000 PDP 30 | 0x92000 ~ 0x93000 PDE 31 | 0x93000 ~ 0x97000 PTE[3:0] (for 8MB-mapping) 32 | 0xA0000 ~ 0x100000 BIOS & VIDEO 33 | 34 | 0x100000 ~ 0x200000 final-loaded kernel area 35 | 36 | 37 | 38 | 39 | 40 | 2. linear address mapping 41 | 42 | 2.1 long-mode switching in setup.asm 43 | 44 | Physical memory area 0~8MB is directly mapped into linear address 0x0 and also 0xFFFF800000000000. 45 | Therefore physical memory 0~8MB is the same with linear address 0x0~8MB. 46 | 47 | Physical linear address linear address 48 | 0x0 ~ 0x800000 => 0x0 ~ 0x800000 & 0xFFFF800000000000 ~ 0xFFFF800000800000 49 | 50 | 51 | 2.2 kernel-booting 52 | 53 | Paging tables are re-builded in paging_init() function. 54 | Then all physical memory is mapped into only linear address 0xFFFF800000000000, not linear address 0x0. 55 | 56 | Physical linear address 57 | 0x0 ~ phy_mem_size => 0xFFFF800000000000 ~ phy_mem_size 58 | 59 | 60 | 61 | 62 | 3. Booting memory allocation 63 | 64 | 65 | For example physical memory size is 512MB, booting-memory is allocated as following. 66 | Total physical page-frames is 131072 and 2406 page-frames is busy. 67 | 68 | 69 | page index 70 | 0x0 BIOS data 71 | 0x9f ~ 0xFF BIOS and ISA video memory 72 | 0x100 ~ 0x1FF Kernel image 73 | 0x200 GDT 74 | 0x201 IDT 75 | 0x202 ~ 0x304 Paging-tables 76 | 0x305 ~ 0xA05 mem_map table 77 | 78 | -------------------------------------------------------------------------------- /docs/mp_spec.txt: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | [ Intel Multiprocessor Specification v1.4, May, 1997 요약 ] 5 | 6 | 7 | 2009.1.20 gurugio 8 | 9 | 10 | - 모든 Local APIC/IO-APIC는 ID레지스터를 가지고, APIC들은 서로간의 독자적인 ID를 가지고, ID로 식별된다. 11 | 12 | - 시스템 메모리 영역중에서 0xA0000~0xFFFFF와 0xFFFE0000~0xFFFFFFFF 영역을 IO 장치와 BIOS 영역으로 예약한다. 13 | 14 | - 멀티프로세서 시스템에서 BIOS는 모든 프로세서와 APIC 등의 멀티프로세서 장치들을 인식하고 configuration 정보를 메모리에 저장하는 역할을 한다. (MP floating pointer) 15 | 16 | - OS 개발자는 MP specification 1.4 문서의 3,4,5, Appendix A,B 를 읽고 바이오스와 OS의 상관관계를 이해해야 한다. 17 | 18 | 19 | - APIC가 사용하는 메모리 영역은 0xFEC0 0000 과 0xFEE0 0000 이다. 20 | 21 | - System memory address map 22 | 23 | 0000 0000 ~ System-based memory 24 | 000A 0000 ~ Video buffer 25 | 000C 0000 ~ Rom extensions 26 | 000D 0000 ~ Expansion rom 27 | 000E 0000 ~ Shadowed expansion BIOS 28 | 000F 0000 ~ Shadowed BIOS 29 | 0010 0000 ~ Extended memory region, memory-mapped IO space 30 | FEC0 0000 ~ IO APIC (shareable by all processors) 31 | FED0 0000 ~ Memory-mapped IO devices 32 | FEE0 0000 ~ Local APIC (accesable only for its own processor) 33 | FEF0 0000 ~ Memory-mapped IO devices 34 | FFFE 0000 ~ BIOS PROM 35 | 36 | 37 | - Local APIC는 82489DX APIC 칩으로도 만들어질 수 있고, 프로세서 내부에서 구현될 수도 있다. Loca APIC Version 레지스터를 읽었을 때, 0x0? 값이면 82489DX APIC이고, 0x1? 값이면 프로세서 내부 APIC 인 것을 알 수 있다. 38 | 39 | - Local APIC의 프로그래밍 순서 40 | 1. 0부터 시작되는 8비트 ID 값 할당 (optional, 바이오스가 정해줌) 41 | 2. logical destination 할당 42 | 3. APIC spurios 벡터 값 할당, 0x?F 값이 되야 함 (?는 4비트 16진수) 43 | 4. IO APIC의 인터럽트 입력 신호의 polarity 지정 44 | 5. STARTUP IPI 정의 --> Appendix B.4 참고 45 | 46 | - 인터럽트 모드 47 | 1. PIC mode - 모든 APIC를 무시하고 싱글 프로세서 모드로 동작함 48 | 2. Virtual Wire Mode - APIC를 가상의 연결선으로 사용하고 PIC 모드와 동일하게 동작 49 | 3. Symmetric IO mode - 시스템이 여러개의 프로세서를 사용하도록함 50 | 51 | - OS 개발자는 Appendix B를 확인하여 Symmetric IO mode의 초기화에 대한 정보를 얻도록 한다. 52 | 53 | - PIC mode는 모든 APIC를 사용하지 않고 인터럽트가 곧바로 프로세서로 전달된다. IMCR (Interrupt mode configuration register) 를 수정해서 다른 모드로 바꿀 수 있다. 54 | 55 | - Symmetric IO mode로 진입하기 위한 순서 56 | 1. IMCR 이 지원되는지 확인 57 | 2. IO APIC Redirection 활성화 58 | 3. 0x22 포트에 0x70 값 쓰기 (IMCR 선택) 59 | 4. 0x23 포트에 0x01 값 쓰기 (Symmetric 선택) 60 | 61 | 62 | - Virtual wire mode 는 하나의 프로세서의 Local APIC를 활성화한다. 인터럽트는 8259를 통해서 Local APIC의 LINTIN0 으로 전달된다. 이 모드에서 IO APIC는 사용되지 않는다. 하지만 IO APIC를 사용하도록 프로그램할 수 있다. 63 | 64 | - Symmetric IO Mode 65 | - 하나 이상의 IO APIC가 동작해야 함 66 | - IO APIC가 IO 인터럽트를 요청하고 8259 라인은 무시됨 67 | - IO APIC의 인터럽트 라인은 시스템 구성에 따라 다르게 구현됨 68 | 69 | 70 | - 바이오스는 시스템의 멀티프로세서 설정 정보를 메모리에 저장해준다. Floating pointer strcuture는 어디에 정보가 저장되어 있는지 알려주고, MP configuration table은 시스템 구성에 대한 정보가 저장되어 있다. 이 정보를 읽는 방법은 mp_spec.c 파일의 smp_read_mpc 함수를 참고한다. 71 | 72 | - OS 프로그래밍 가이드 73 | - 부팅 후 AP는 halt 상태이며 인터럽트를 무시한다. AP는 오직 INIT IPI와 STARTUP IPI에만 반응한다. 74 | - BSP는 가장 먼저 MP floating table과 MP configuration table을 읽어서 시스템 구성 정보를 확인해야 한다. 75 | - 부팅 직후에는 인터럽트 모드가 PIC mode 혹은 Virtual wire mode 가 된다. OS는 인터럽트 모드를 Symmetric IO mode로 바꿔서 멀티 프로세서가 동작하도록 한다. (이것은 AP를 깨운 후에 실행해도 됨) 76 | - 그후에 BSP의 local APIC를 동작시킨다. local APIC가 동작해야만 AP를 깨우는 IPI를 발생시킬 수 있다. local APIC는 아직 인터럽트가 마스킹된 상태이다. 77 | - INIT IPI와 STARTUP IPI를 전송해서 AP를 실행시킨다. 78 | 79 | 80 | 81 | 82 | (보다 더 자세한 사항이 많으므로 Intel Multiprocessor Specification을 반드시 읽어볼 것) 83 | 84 | (실질적인 동작 코드는 인텔 메뉴얼을 참고할 것) 85 | 86 | (Local APIC는 프로세서 메뉴얼에서 설명하지만 IO APIC는 프로세서 밖에 존재하기 때문에 프로세서 메뉴얼에서 다루지 않는다. 인터넷에서 다른 문서들을 찾을 것) 87 | 88 | 89 | 90 | - references 91 | 1. Intel Multiprocessor Specification v1.4, May, 1997 92 | 2. Linux SMP HOWTO v1.4, July, 2002 93 | 94 | 95 | 96 | 97 | 98 | -------------------------------------------------------------------------------- /docs/paging.txt: -------------------------------------------------------------------------------- 1 | 2 | [ Paging Tables Building ] 3 | 4 | 2009.1.20 gurugio 5 | 6 | 7 | - Paging-table building referes "linux/arch/x86_64/kernel/machine_kexec.c" 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /docs/qemu.txt: -------------------------------------------------------------------------------- 1 | [ Run CaOS in qemu ] 2 | 3 | 2009.2.9 gurugio 4 | 5 | 6 | 1. qemu options 7 | 8 | -L: qemu BIOS directory. (for Windows) 9 | -m: memory size 10 | -fda : floppy disk image 11 | -boot a: 'a' means floppy drive booting 12 | -smp #: processor count (max 2) 13 | 14 | 15 | 2. Linux 16 | 17 | Move to CaOS source directory. 18 | 19 | $ qemu-system-x86_64 -m 128 -fda ./floppy.img -boot a -smp2 20 | 21 | 3. Windows 22 | 23 | Move to CaOS source directory and set PATH to qemu directory. 24 | BIOS path should be defined. 25 | 26 | > qemu-system-x86_64.exe -L -m 128 -fda floppy.img -boot a -smp 2 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /docs/slab.txt: -------------------------------------------------------------------------------- 1 | 2 | [ Slab Memory Allocator ] 3 | 4 | 2009.1.20 gurugio 5 | 6 | 7 | 8 | 9 | 1. create new cachep - kmem_cache_create() 10 | 11 | When a new cache descriptor is need, kmem_cache_create() creates a new cache. 12 | There is cache_cache table, which is array of cache descriptor, and kmem_cache_create() allocate a descriptor from cache_cache table. 13 | 14 | 15 | 2. allocate objects to cache - kmem_cache_grow() 16 | 17 | If no object is free or cache has no object, kmem_cache_grow() create new slab and free objects. 18 | 19 | 3. free objects of cache - kmem_cache_shrink() 20 | 21 | kmem_cache_shrink() deletes a slab, if all objects in the slab is free. 22 | 23 | 4. free a slab - slab_destroy() 24 | 25 | Free pages that the slab and objects are included. 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /docs/spinlock_test/Makefile: -------------------------------------------------------------------------------- 1 | 2 | 3 | all: 4 | gcc -Wall -O2 lock.c -lpthread 5 | -------------------------------------------------------------------------------- /docs/spinlock_test/a.out: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gurugio/caos/420ab71b185d07015c569b417ac23edf82514551/docs/spinlock_test/a.out -------------------------------------------------------------------------------- /docs/spinlock_test/ddd: -------------------------------------------------------------------------------- 1 | LOCK by <0> 2 | PREEMPT=2 3 | UNLOCK by <0> 4 | LOCK by <0> 5 | PREEMPT=1 6 | UNLOCK by <0> 7 | LOCK by <1> 8 | PREEMPT=1 9 | UNLOCK by <1> 10 | LOCK by <1> 11 | PREEMPT=1 12 | UNLOCK by <1> 13 | LOCK by <1> 14 | PREEMPT=1 15 | UNLOCK by <1> 16 | LOCK by <0> 17 | PREEMPT=1 18 | UNLOCK by <0> 19 | LOCK by <1> 20 | PREEMPT=1 21 | UNLOCK by <1> 22 | LOCK by <0> 23 | PREEMPT=1 24 | UNLOCK by <0> 25 | LOCK by <1> 26 | PREEMPT=1 27 | UNLOCK by <1> 28 | LOCK by <1> 29 | PREEMPT=1 30 | UNLOCK by <1> 31 | LOCK by <0> 32 | PREEMPT=1 33 | UNLOCK by <0> 34 | LOCK by <0> 35 | PREEMPT=1 36 | UNLOCK by <0> 37 | LOCK by <1> 38 | PREEMPT=1 39 | UNLOCK by <1> 40 | LOCK by <0> 41 | PREEMPT=1 42 | UNLOCK by <0> 43 | LOCK by <0> 44 | PREEMPT=1 45 | UNLOCK by <0> 46 | LOCK by <1> 47 | PREEMPT=1 48 | UNLOCK by <1> 49 | LOCK by <1> 50 | PREEMPT=1 51 | UNLOCK by <1> 52 | LOCK by <1> 53 | PREEMPT=1 54 | UNLOCK by <1> 55 | LOCK by <0> 56 | PREEMPT=1 57 | UNLOCK by <0> 58 | LOCK by <1> 59 | PREEMPT=1 60 | UNLOCK by <1> 61 | LOCK by <1> 62 | PREEMPT=1 63 | UNLOCK by <1> 64 | LOCK by <0> 65 | PREEMPT=1 66 | UNLOCK by <0> 67 | LOCK by <1> 68 | PREEMPT=1 69 | UNLOCK by <1> 70 | LOCK by <0> 71 | PREEMPT=1 72 | UNLOCK by <0> 73 | LOCK by <1> 74 | PREEMPT=1 75 | UNLOCK by <1> 76 | LOCK by <0> 77 | PREEMPT=1 78 | UNLOCK by <0> 79 | LOCK by <1> 80 | PREEMPT=1 81 | UNLOCK by <1> 82 | LOCK by <0> 83 | PREEMPT=1 84 | UNLOCK by <0> 85 | LOCK by <0> 86 | PREEMPT=1 87 | UNLOCK by <0> 88 | LOCK by <0> 89 | PREEMPT=1 90 | UNLOCK by <0> 91 | LOCK by <1> 92 | PREEMPT=1 93 | UNLOCK by <1> 94 | LOCK by <1> 95 | PREEMPT=1 96 | UNLOCK by <1> 97 | LOCK by <0> 98 | PREEMPT=1 99 | UNLOCK by <0> 100 | LOCK by <1> 101 | PREEMPT=1 102 | UNLOCK by <1> 103 | LOCK by <0> 104 | PREEMPT=1 105 | UNLOCK by <0> 106 | LOCK by <1> 107 | PREEMPT=1 108 | UNLOCK by <1> 109 | LOCK by <0> 110 | PREEMPT=1 111 | UNLOCK by <0> 112 | LOCK by <0> 113 | PREEMPT=1 114 | UNLOCK by <0> 115 | LOCK by <0> 116 | PREEMPT=1 117 | UNLOCK by <0> 118 | LOCK by <1> 119 | PREEMPT=1 120 | UNLOCK by <1> 121 | LOCK by <0> 122 | PREEMPT=1 123 | UNLOCK by <0> 124 | LOCK by <1> 125 | PREEMPT=1 126 | UNLOCK by <1> 127 | LOCK by <1> 128 | PREEMPT=1 129 | UNLOCK by <1> 130 | LOCK by <1> 131 | PREEMPT=1 132 | UNLOCK by <1> 133 | LOCK by <0> 134 | PREEMPT=1 135 | UNLOCK by <0> 136 | LOCK by <0> 137 | PREEMPT=1 138 | UNLOCK by <0> 139 | LOCK by <1> 140 | PREEMPT=1 141 | UNLOCK by <1> 142 | LOCK by <0> 143 | PREEMPT=1 144 | UNLOCK by <0> 145 | LOCK by <1> 146 | PREEMPT=1 147 | UNLOCK by <1> 148 | LOCK by <0> 149 | PREEMPT=1 150 | UNLOCK by <0> 151 | -------------------------------------------------------------------------------- /docs/spinlock_test/lock.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | 8 | 9 | // 10 | // type definitions 11 | // 12 | 13 | 14 | typedef signed int ssize_t; 15 | 16 | typedef struct { 17 | volatile ssize_t slock; 18 | } spinlock_t; 19 | 20 | #define SPIN_LOCK_UNLOCKED 1 21 | #define SPIN_LOCK_LOCKED 0 22 | 23 | 24 | 25 | volatile ssize_t preempt_count = 0; 26 | 27 | // 28 | // macros 29 | // 30 | 31 | #define smp_mb() asm volatile("mfence":::"memory") 32 | #define smp_rmb() asm volatile("lfence":::"memory") 33 | #define smp_wmb() asm volatile("sfence":::"memory") 34 | 35 | #define cpu_relax() asm volatile("rep;nop":::"memory") 36 | 37 | 38 | 39 | #define spin_lock_init(lock) \ 40 | do { lock->slock = SPIN_LOCK_UNLOCKED; } while (0) 41 | 42 | 43 | /** 44 | * test_bit - Determine whether a bit is set 45 | * @nr: bit number to test 46 | * @addr: Address to start counting from 47 | */ 48 | 49 | static __inline__ size_t test_bit(size_t nr, const volatile void * addr) 50 | { 51 | 52 | size_t oldbit; 53 | 54 | 55 | __asm__ __volatile__( 56 | "btl %2,%1\n\t" 57 | "sbbl %0,%0\n\t" 58 | :"=r" (oldbit) 59 | :"m" (*(volatile long *)addr), "dlr" (nr)); 60 | return oldbit; 61 | } 62 | 63 | 64 | static __inline__ void set_bit(size_t nr, volatile void * addr) 65 | { 66 | __asm__ __volatile__( 67 | "btsl %1,%0" 68 | :"=m"(*(volatile long *)addr) 69 | :"dIr" (nr) : "memory"); 70 | } 71 | 72 | 73 | 74 | static __inline__ void atomic_inc(int *v) 75 | { 76 | 77 | asm volatile ( 78 | "incl %0" 79 | :"=m"(*v) 80 | :"m"(*v)); 81 | } 82 | 83 | 84 | static __inline__ void atomic_dec(int *v) 85 | { 86 | 87 | asm volatile ( 88 | "decl %0" 89 | :"=m"(*v) 90 | :"m"(*v)); 91 | } 92 | 93 | #define preempt_disable() \ 94 | do { \ 95 | preempt_count += 1;\ 96 | smp_mb();\ 97 | } while (0) 98 | 99 | #define preempt_enable() \ 100 | do { \ 101 | preempt_count -= 1;\ 102 | smp_mb();\ 103 | } while (0) 104 | 105 | 106 | 107 | #define spin_is_locked(lock) test_bit(0, &lock->slock) 108 | 109 | // 110 | // If spin-lock is free, it locks spin-lock and returns 1. 111 | // If spin-lock is locked, it returns 0. 112 | // 113 | size_t raw_spin_trylock(spinlock_t *lock) 114 | { 115 | size_t tmp = 0; 116 | 117 | //printf("tmp=%d lock=%d\n", tmp, lock->slock); 118 | 119 | asm volatile ( 120 | "movb $0, %b0\n\t" 121 | "lock;xchgb %b0, %1\n\t" 122 | : "=&a" (tmp), "+m" (lock->slock) 123 | : 124 | : "memory"); 125 | 126 | //printf("tmp=%d lock=%d\n", tmp, lock->slock); 127 | 128 | return tmp; 129 | } 130 | 131 | 132 | 133 | 134 | 135 | void spin_lock(spinlock_t *lock) 136 | { 137 | 138 | preempt_disable(); 139 | 140 | while (!raw_spin_trylock(lock)) { 141 | preempt_enable(); 142 | while (spin_is_locked(lock)) { 143 | cpu_relax(); 144 | printf("RELAX "); 145 | } 146 | preempt_disable(); 147 | } 148 | 149 | 150 | } 151 | 152 | 153 | void spin_unlock(spinlock_t *lock) 154 | { 155 | set_bit(0, &lock->slock); 156 | preempt_enable(); 157 | } 158 | 159 | 160 | 161 | spinlock_t l = {SPIN_LOCK_UNLOCKED}; 162 | 163 | 164 | 165 | void thread_func(void *tid) 166 | { 167 | srand((unsigned int)time(NULL)); 168 | 169 | 170 | while (1) { 171 | spin_lock(&l); 172 | 173 | 174 | // 175 | // CRITICAL SECTION 176 | // 177 | printf("LOCK by <%d>\n", *(int *)tid); 178 | 179 | usleep(100 * (rand() % 10)); 180 | 181 | if (test_bit(0, &l.slock)) { 182 | printf("ERROR\n"); 183 | return; 184 | } 185 | 186 | printf("======>PREEMPT=%d\n", preempt_count); 187 | 188 | printf("UNLOCK by <%d>\n", *(int *)tid); 189 | fflush(stdout); 190 | // 191 | // CRITICAL SECTION 192 | // 193 | 194 | 195 | spin_unlock(&l); 196 | 197 | 198 | // 199 | // NORMAL SECTION 200 | // 201 | usleep(1000 * (rand() % 10)); 202 | 203 | } 204 | 205 | 206 | 207 | } 208 | 209 | 210 | 211 | void preempt_monitor(void) 212 | { 213 | int old = 0; 214 | 215 | while (1) { 216 | if (preempt_count != old) { 217 | printf("[MONITOR]PREEMPT=%d\n", preempt_count); 218 | old = preempt_count; 219 | } 220 | //if (preempt_count == 0) printf("SCHEDULE"); 221 | } 222 | 223 | } 224 | 225 | 226 | int main(void) 227 | { 228 | 229 | int a=0,b=1,c=2; 230 | pthread_t thr[4]; 231 | int thr_id[4]; 232 | 233 | thr_id[0] = pthread_create(&thr[0], NULL, thread_func, &a); 234 | thr_id[1] = pthread_create(&thr[1], NULL, thread_func, &b); 235 | thr_id[2] = pthread_create(&thr[2], NULL, thread_func, &c); 236 | thr_id[3] = pthread_create(&thr[3], NULL, preempt_monitor, NULL); 237 | 238 | 239 | pthread_join(thr[0], NULL); 240 | pthread_join(thr[1], NULL); 241 | pthread_join(thr[2], NULL); 242 | pthread_join(thr[3], NULL); 243 | 244 | 245 | return 0; 246 | } 247 | 248 | 249 | 250 | -------------------------------------------------------------------------------- /docs/symbols.txt: -------------------------------------------------------------------------------- 1 | 2 | [ Essential Kernel Symbols ] 3 | 4 | 2009.1.20 gurugio 5 | 6 | 7 | 8 | KERNEL_STACK_START equ 0xffff800000200000 9 | 10 | - Kernel image ends and kernel-stack pointer is grow from it. 11 | 12 | 13 | KERNEL_VMA equ 0xffff800000100000 14 | 15 | - linear address that kernel exists 16 | 17 | 18 | Follow addresses are section address of kernel image 19 | 20 | _bss equ 0xffff800000104000 21 | _bss_end equ 0xffff800000105160 22 | _code equ 0xffff800000100000 23 | _code_end equ 0xffff800000102000 24 | _data equ 0xffff800000102000 25 | _data_end equ 0xffff800000103000 26 | _ehframe equ 0xffff800000103370 27 | _ehframe_end equ 0xffff800000104000 28 | _kernel_end equ 0xffff800000105160 29 | 30 | 31 | -------------------------------------------------------------------------------- /docs/x86_64-asm.txt: -------------------------------------------------------------------------------- 1 | 2 | 3 | [ Example of X86_64 Assembly Programming ] 4 | 5 | 6 | 2009.1.20 gurugio 7 | 8 | 9 | (reference. NASM Manual, Chapter 11: Writing 64-bit code) 10 | 11 | 12 | 1. In 64bit mode, data addressing defers from 32bit mode. 13 | 14 | 15 | 2. Function-parameter is passed as the seqeunce rdi, rsi, rdx, rcx, r8, r9, stack. 16 | 17 | 18 | !!! Never invoke caos_printf, if do, system is halted. I don't know why!!! 19 | 20 | 21 | 22 | 3. example 23 | 24 | 25 | Following example works well but it does not address data... 26 | 27 | 28 | ---- 29 | 30 | 31 | [bits 64] 32 | 33 | ; for x86_64 processor assembly 34 | [CPU X64] 35 | 36 | 37 | ; only RIP-relative addressing is active for x86_64 processor 38 | [DEFAULT REL] 39 | 40 | extern caos_putchar 41 | 42 | 43 | ; caos_printf cannot be invoked...WHT??? 44 | ;extern caos_printf 45 | 46 | section .text 47 | global _start 48 | 49 | _start: 50 | 51 | ; According to the AMD64 ABI Draft 0.99, 52 | ; rbx, rbp, r12-r15 registers must be preserved across function calls 53 | push rbx 54 | push rbp 55 | 56 | push r12 57 | push r13 58 | push r14 59 | push r15 60 | 61 | 62 | 63 | ; only "MOV reg64, imm64" intruction can take a full 64bit immediate value. 64 | mov r15, 0x12345678abcdef 65 | 66 | ; data is accessed with RIP-relative addressing 67 | ; function parameter is passed in rdi, rsi, rdx, rcx, r8, r9, stack~ 68 | mov rdi, [byte msg] 69 | call _test_asm 70 | 71 | 72 | ; data is accessed with RIP-relative addressing 73 | mov rdx, [byte msg] 74 | add dl, 1 75 | mov byte [byte msg], dl 76 | 77 | 78 | pop r15 79 | pop r14 80 | pop r13 81 | pop r12 82 | 83 | pop rbp 84 | pop rbx 85 | 86 | ret 87 | 88 | global _test_asm 89 | _test_asm: 90 | ; According to the AMD64 ABI Draft 0.99, 91 | ; rbx, rbp, r12-r15 registers must be preserved across function calls 92 | push rbx 93 | push rbp 94 | 95 | push r12 96 | push r13 97 | push r14 98 | push r15 99 | 100 | 101 | push rdi 102 | 103 | mov rdi, 'T' 104 | call caos_putchar 105 | mov rdi, 'e' 106 | call caos_putchar 107 | mov rdi, 's' 108 | call caos_putchar 109 | mov rdi, 't' 110 | call caos_putchar 111 | 112 | ; function argument is in rdi 113 | pop rdi 114 | call caos_putchar 115 | 116 | 117 | pop r15 118 | pop r14 119 | pop r13 120 | pop r12 121 | 122 | pop rbp 123 | pop rbx 124 | 125 | 126 | 127 | ret 128 | 129 | 130 | section .data 131 | msg db '0' 132 | 133 | ---- 134 | 135 | -------------------------------------------------------------------------------- /run.bat: -------------------------------------------------------------------------------- 1 | ..\qemu-20081229-windows\qemu-system-x86_64.exe -L ..\qemu-20081229-windows\ -m 128 -fda image\floppy.img -boot a -smp 2 2 | -------------------------------------------------------------------------------- /run.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | qemu-system-x86_64 -m 128 -fda ./image/floppy.img -boot a -smp 2 3 | -------------------------------------------------------------------------------- /src/Makefile: -------------------------------------------------------------------------------- 1 | # How to compile 64bit kernel refers to http://wiki.osdev.org/Creating_a_64-bit_kernel 2 | # and the other options refer gcc manual & http://www.osx86.org 3 | 4 | 5 | include ../config.mk 6 | 7 | 8 | # 9 | # local definitions 10 | # 11 | 12 | # linear address where kernel exists 13 | KERNEL_VIRTUAL_ADDR=0xFFFF800000100000 14 | KERNEL_STACK_ADDR=0xFFFF800000200000 15 | 16 | # physical memory size (MIN 16MB ~ MAX 512MB) 17 | MEMORY_SIZE=128 18 | 19 | 20 | # 21 | # compile option 22 | # 23 | 24 | INCLUDE=./include 25 | CFLAGS=-Wall -Wextra -Winline -I$(INCLUDE) -fno-stack-protector -O2 -nostdinc -nostdlib -m64 -ffreestanding -nostdlib -mcmodel=large -DKERNEL_VIRTUAL_ADDR=$(KERNEL_VIRTUAL_ADDR) -DKERNEL_STACK_ADDR=$(KERNEL_STACK_ADDR) -c 26 | 27 | 28 | 29 | 30 | # 31 | # link option 32 | # 33 | 34 | LFLAGS=-m elf_x86_64 -nodefaultlibs -nostdlib -Map link_map.txt --defsym KERNEL_VMA=$(KERNEL_VIRTUAL_ADDR) --defsym KERNEL_STACK_START=$(KERNEL_STACK_ADDR) 35 | 36 | 37 | # 38 | # assemble option 39 | # 40 | 41 | NASMFLAG=-f elf64 42 | 43 | 44 | # 45 | # bootloader 46 | # 47 | 48 | BOOT_SRCS = bootsect.asm setup.asm 49 | 50 | 51 | # 52 | # kernel 53 | # 54 | 55 | C_SRCS = main.c screen.c printf.c string.c setup.c page.c memory.c gdt.c idt.c except_handler.c page_alloc.c slab.c except_handler.c mp_spec.c apic.c irq_handler.c io_apic.c pic8259.c smp.c keyboard.c percpu.c spinlock.c process.c 56 | ASM_SRCS = except_entry.asm irq_entry.asm 57 | C_OBJS = $(C_SRCS:.c=.o) 58 | ASM_OBJS = $(ASM_SRCS:.asm=.o) 59 | 60 | 61 | 62 | # 63 | # binary image 64 | # 65 | 66 | BOOT_IMG = boot.img 67 | KERNEL_IMG = kernel.img 68 | FLOPPY_IMG = floppy.img 69 | BOCHS_IMG = bochs.img 70 | 71 | 72 | # 73 | # system.map 74 | # 75 | MAP=system.map 76 | 77 | # 78 | # BUILD 79 | # 80 | 81 | all:$(FLOPPY_IMG) 82 | objdump -d kernel.elf > disasm.txt 83 | cp floppy.img system.map disasm.txt ../image 84 | 85 | 86 | $(FLOPPY_IMG):$(KERNEL_IMG) $(MAP) $(BOOT_IMG) 87 | cat $(BOOT_IMG) $(KERNEL_IMG) setup.img > $@ 88 | 89 | 90 | $(KERNEL_IMG):$(C_OBJS) $(ASM_OBJS) 91 | $(LD64) $(LFLAGS) -o kernel.elf -T ld-script.ld $^ 92 | $(OBJCOPY64) -j .text -j .rodata -j .data -O binary kernel.elf $@ 93 | 94 | 95 | %.o : %.c 96 | $(GCC64) $(CFLAGS) $< 97 | 98 | 99 | %.o : %.asm 100 | $(NASM) -f elf64 -o $@ $< 101 | 102 | 103 | $(MAP):kernel.elf 104 | $(NM) kernel.elf > system.map 105 | 106 | 107 | $(BOOT_IMG):$(BOOT_SRCS) $(MAP) $(KERNEL_IMG) 108 | ../utils/gen_section ./system.map ./kernel_section.inc 109 | KERNEL_SIZE=`ls -l kernel.img | awk '{ print $$5 }'`; \ 110 | KERNEL_SIZE=`expr \( $$KERNEL_SIZE + 512 \) / 512`; \ 111 | echo "Kernel size(sectors) = " $$KERNEL_SIZE; \ 112 | $(NASM) -DKERNEL_SIZE=$$KERNEL_SIZE -o bootsect.img bootsect.asm;\ 113 | $(NASM) -DKSIZE=$$KERNEL_SIZE -DMSIZE=$(MEMORY_SIZE) -o setup.img setup.asm 114 | cat bootsect.img setup.img > $@ 115 | 116 | 117 | BOCHS:$(FLOPPY_IMG) 118 | $(DD) if=floppy.img of=bochs.img bs=1440K conv=sync 119 | echo "Floppy image for 1.44MB dist is created..bochs.img" 120 | cp bochs.img ../image 121 | 122 | 123 | clean: 124 | rm -f *.o *.img *.elf *.txt *.map cscope.* tags *.out 125 | 126 | -------------------------------------------------------------------------------- /src/a20.inc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gurugio/caos/420ab71b185d07015c569b417ac23edf82514551/src/a20.inc -------------------------------------------------------------------------------- /src/apic.c: -------------------------------------------------------------------------------- 1 | 2 | // 3 | // all functions are copy of linux/arch/x86_64/kernel/apic.c 4 | // refer to include/asm-x86_64/apic.h, apicdef.h 5 | // 6 | // 7 | 8 | #include 9 | #include 10 | 11 | #include 12 | #include 13 | 14 | #include // screen_info 15 | #include 16 | #include // cpu_id() 17 | 18 | #include // boot_cpu_id, mp_lapic_addr 19 | 20 | #include 21 | 22 | #define DEBUG 23 | #undef DEBUG 24 | 25 | 26 | 27 | // each cpu's Local APIC ID 28 | u8 x86_cpu_to_apicid[NR_CPUS] = { [0 ... NR_CPUS-1] = 0xff }; 29 | 30 | 31 | 32 | // 33 | // This processor's Local APIC is working correctly? 34 | // This is copied from the Linux kernel, 2.6.25 35 | // 36 | ssize_t verify_local_APIC(void) 37 | { 38 | u32 reg0, reg1; 39 | 40 | // 41 | // APIC version register 42 | // [23:16]: # of LVT(Local Vector Table) entries - 1 43 | // [7:0] : Version, 1Xh-Local APIC version 44 | // 45 | reg0 = apic_read(APIC_LVR); 46 | 47 | #ifdef DEBUG 48 | caos_printf("local apic version=%x\n", reg0); 49 | #endif 50 | 51 | 52 | apic_write(APIC_LVR, reg0^APIC_LVR_MASK); 53 | reg1 = apic_read(APIC_LVR); 54 | 55 | #ifdef DEBUG 56 | caos_printf("local apic version=%x\n", reg1); 57 | #endif 58 | 59 | /* 60 | * The two version reads above should print the same 61 | * numbers. If the second one is different, then we 62 | * poke at a non-APIC. 63 | */ 64 | if (reg1 != reg0) 65 | return 0; 66 | 67 | /* 68 | * Check if the version looks reasonably. 69 | */ 70 | reg1 = GET_APIC_VERSION(reg0); 71 | if (reg1 == 0x00 || reg1 == 0xff) 72 | return 0; 73 | reg1 = GET_APIC_MAXLVT(reg0); 74 | if (reg1 < 0x02 || reg1 == 0xff) 75 | return 0; 76 | 77 | /* 78 | * The ID register is read/write in a real APIC. 79 | */ 80 | reg0 = apic_read(APIC_ID); 81 | apic_write(APIC_ID, reg0 ^ APIC_ID_MASK); 82 | 83 | reg1 = apic_read(APIC_ID); 84 | #ifdef DEBUG 85 | caos_printf("Getting old ID: %x\n", reg0); 86 | caos_printf("Getting test ID: %x\n", reg1); 87 | #endif 88 | apic_write(APIC_ID, reg0); 89 | if (reg1 != (reg0 ^ APIC_ID_MASK)) 90 | return 0; 91 | 92 | 93 | return 1; 94 | } 95 | 96 | 97 | 98 | 99 | // 100 | // Interrupt Handler of BSP's Local APIC Timer 101 | // 102 | void bsp_local_timer(size_t num) 103 | { 104 | 105 | static u8 tick=0; 106 | ssize_t i; 107 | 108 | // clear the first line of screen 109 | for (i=79; i>=0; i--) 110 | set_screen(i, ' '); 111 | 112 | 113 | // print message that indicates timer running 114 | set_screen(0, 'B'); 115 | set_screen(1, 'S'); 116 | set_screen(2, 'P'); 117 | set_screen(3, tick++); 118 | 119 | 120 | set_screen(77, 'A'); 121 | set_screen(78, 'P'); 122 | 123 | 124 | num = num; /* remove compiler warning */ 125 | #ifdef DEBUG 126 | // ISR bit corresponding to the Timer INT has been setting 127 | caos_printf("ISR SETTING [%x]", apic_read(APIC_ISR+0x10)); 128 | #endif 129 | } 130 | 131 | 132 | 133 | 134 | // 135 | // REFINE!!! APIC timer ISR must be refined!!! 136 | // 137 | // refer to arch/x86_64/kernel_apic.c , arch/x86_64/kernel/entry.S 138 | // Entry point of BSP-timer IRQ -> apic_timer_interrupt in entry.S 139 | // C language Handler -> smp_apic_timer_interrupt in kernel_apic.c 140 | // 141 | void init_bsp_timer(void) 142 | { 143 | u32 lvt_timer; 144 | 145 | 146 | caos_printf("Init local timer of CPU #%d ", cpu_id()); 147 | 148 | // 149 | // Timer interrupt period is hard-coding value. 150 | // Dynamic analysis of processor's bus clock is need. 151 | // 152 | 153 | // Initial Count register 154 | apic_write(APIC_TMICT, 0xFFFFFF); 155 | // Divide Configuration register 156 | apic_write(APIC_TDCR, APIC_TDR_DIV_64); 157 | 158 | 159 | // 160 | // enable timer interrupt 161 | // 162 | lvt_timer = apic_read(APIC_LVTT); 163 | lvt_timer &= (~APIC_LVT_MASKED); // unmask 164 | lvt_timer |= APIC_LVT_TIMER_PERIODIC; // periodically repeat 165 | lvt_timer |= IRQ_TO_VECTOR(BSP_TIMER_IRQ); // vector 166 | apic_write(APIC_LVTT, lvt_timer); 167 | 168 | #ifdef DEBUG 169 | caos_printf("APIC_LVTT=%x\n", lvt_timer); 170 | #endif 171 | 172 | if ((apic_read(APIC_LVTT) & APIC_LVT_MASKED) == 0) { 173 | caos_printf("..success\n"); 174 | // timer irq : local APIC timer do not need PIC-enabling 175 | // only register handler. 176 | register_irq(BSP_TIMER_IRQ, bsp_local_timer); 177 | } else { 178 | caos_printf("..fail\n"); 179 | } 180 | } 181 | 182 | 183 | 184 | 185 | // 186 | // setup BSP's Local APIC, refer linux-kernel 187 | // arch/x86_64/kernel/apic.c - init_bsp_APIC(), setup_local_APIC() 188 | // 189 | void init_bsp_APIC(void) 190 | { 191 | 192 | u32 lapic_SVR; 193 | u32 lapic_id; 194 | 195 | 196 | // 197 | // check BSP's Local APIC exists 198 | // 199 | 200 | // print BSP's Local APIC ID (which is equal to CPU ID) 201 | lapic_id = apic_read(APIC_ID); 202 | 203 | if (lapic_id != boot_cpu_id || lapic_id != x86_cpu_to_apicid[boot_cpu_id]) { 204 | /* If AP should call this function, remove following codes and just exit function */ 205 | caos_printf("This is not BSP! Please reboot system.\n"); 206 | halt(); 207 | } 208 | 209 | 210 | // check Local APIC version 211 | if (!verify_local_APIC()) { 212 | caos_printf("\nCannot verify BSP's Local APIC!!\n"); 213 | halt(); 214 | } 215 | 216 | 217 | // mask all interrupts ([16] = 1) 218 | apic_write(APIC_LVTT, 0x10000); // local timer 219 | apic_write(APIC_LVTTHMR, 0x10000); // Thermal monitor 220 | apic_write(APIC_LVTPC, 0x10000); // Performance monitor 221 | apic_write(APIC_LVT1, 0x10000); // Local INT #1 222 | apic_write(APIC_LVT0, 0x10000); // Local INT #0 223 | apic_write(APIC_LVTERR, 0x10000); // Error 224 | 225 | 226 | 227 | // 228 | // Vector 0~31 is invalid because they are reserved for 229 | // processor exceptions and Intel's own purpose. 230 | // 231 | 232 | 233 | // 234 | // interrupt priority = vector / 16 235 | // 1 being the lowest priority and 15 is the highest 236 | // 237 | 238 | 239 | // task priority register 240 | // The task priority allows software to set a priority threshold 241 | // for interrupt the processor 242 | // [7:4]: Task priority 243 | // [3:0]: Task priority sub-class 244 | apic_write(APIC_TASKPRI, 0); // BSP accepts all INTs & exceptions 245 | 246 | 247 | 248 | // 249 | // Delivery mode ExtINT: 250 | // Causes the processor to respond to the interrupts 251 | // as if the interrupt originated in an externally connected 252 | // interrupt controller. The external controller is 253 | // expected to supply the vector information. 254 | // The APIC architecture supports only one ExtINT source in a system, 255 | // usually contained in the compatibility bridge. 256 | // 257 | 258 | 259 | // 260 | // I do not know how local interrupts work 261 | // 262 | 263 | #if 0 264 | do 265 | { 266 | u32 reg; 267 | reg = apic_read(APIC_LVT0); 268 | reg &= ~APIC_LVT_MASKED; // enable 269 | reg |= APIC_LVT_LEVEL_TRIGGER; // only level trigger mode for ExtINT 270 | reg |= APIC_INPUT_POLARITY; // active low 271 | reg |= APIC_DM_FIXED;; // delivery mode ExtINT 272 | reg |= IRQ_TO_VECTOR(LINT0_IRQ); // vector of LINT0 273 | apic_write(APIC_LVT0, reg); 274 | } while (0); 275 | #endif 276 | 277 | 278 | // I do not know what spurious interrupt 279 | // spurious interrupt vector 280 | apic_write(APIC_SPIV, apic_read(APIC_SPIV) | IRQ_TO_VECTOR(SPURIOUS_IRQ)); 281 | 282 | 283 | #ifdef DEBUG 284 | caos_printf("SPIV=%x", apic_read(APIC_SPIV)); 285 | caos_printf("LINT0=%x\n", apic_read(0x350)); 286 | caos_printf("LINT1=%x", apic_read(0x360)); 287 | caos_printf("error=%x\n", apic_read(0x370)); 288 | caos_printf("perfor=%x", apic_read(0x340)); 289 | caos_printf("therm=%x\n", apic_read(0x330)); 290 | #endif 291 | 292 | apic_write(APIC_EOI, 0); // clear ISR reg 293 | 294 | 295 | // 296 | // activate BSP's local APIC 297 | // 298 | lapic_SVR = apic_read(APIC_SPIV); // Spurious Interrupt Vector reg 299 | lapic_SVR |= APIC_SPIV_APIC_ENABLED; // set enable bit explicitly 300 | apic_write(APIC_SPIV, lapic_SVR); 301 | 302 | lapic_SVR = apic_read(APIC_SPIV); 303 | if (lapic_SVR & APIC_SPIV_APIC_ENABLED) 304 | caos_printf("enabled\n"); 305 | 306 | apic_write(APIC_EOI, 0); // clear ISR reg 307 | 308 | return; 309 | } 310 | 311 | 312 | -------------------------------------------------------------------------------- /src/bootsect.asm: -------------------------------------------------------------------------------- 1 | ;==================================================== 2 | ; DESCRIPTION: 1. load setup.asm at 0x9000 3 | ; 2. load kernel at 0x9200 4 | ; FILE NAME: bootsect.asm 5 | ;==================================================== 6 | 7 | 8 | [org 0x0] 9 | 10 | 11 | SETUP_SECT equ 8 ; sutup.img size is 4096 (8 sectors) 12 | KERNEL_SECT equ KERNEL_SIZE 13 | 14 | BOOT_SEG equ 0x7c0 15 | SETUP_SEG equ 0x900 16 | 17 | ; Kernel is copied to 0xA000 at first, 18 | ; and to 0x100000 in setup.asm 19 | KERNEL_SEG equ 0xA00 20 | 21 | SETUP_ADDR equ 0x9000 22 | 23 | 24 | jmp BOOT_SEG:start 25 | 26 | boot_drv db 0 ; floppy drive A: 27 | sect_per_track dw 18 ; sectors per one track 28 | head_per_drv dw 2 ; floppy has 2 heads 29 | current_sect dw 1 ; current reading sector # (relative) 30 | read_sect db 0 ; it read how many sectors 31 | 32 | ; define routines for A20 line activation 33 | %include "a20.inc" 34 | 35 | start: 36 | mov ax, cs 37 | mov ds, ax ; ds=es=0x7c0 38 | mov es, ax 39 | 40 | mov ss, ax ; stack: 0x7c0:0 -> low memory 41 | mov sp, 0x0 42 | 43 | mov [boot_drv], dl ; bios store drive number in dl 44 | 45 | 46 | mov ax, SETUP_SEG ; read image of setup.asm 47 | mov es, ax 48 | mov si, 0 ; store image at es:si=0x900:0 49 | mov cx, SETUP_SECT ; how many sectors? 50 | call read_sectors 51 | 52 | mov ax, KERNEL_SEG 53 | mov es, ax 54 | mov si, 0 55 | mov cx, KERNEL_SECT 56 | call read_sectors 57 | 58 | call a20_try_loop ; activate A20 line 59 | 60 | 61 | mov ax, 0xb800 62 | mov es, ax 63 | mov bx, 0x0 64 | mov al, byte [hello_msg] ; Greeting! 65 | mov byte [es:bx], al 66 | 67 | 68 | mov ax, KERNEL_SECT 69 | 70 | ;========================================== 71 | ; segment addres = 0x0 72 | ; offset = 0x9000 73 | ; Segment must be 0x0000. 74 | ;========================================== 75 | jmp 0x0:SETUP_ADDR ; execute setup 76 | 77 | 78 | jmp $ ; or die! 79 | 80 | ; es: segment address 81 | ; cx: sector count 82 | read_sectors: 83 | push cx 84 | call read_one_sect ; load one sector 85 | pop cx 86 | 87 | add si, 512 ; offset for next sector 88 | dec cx ; next sector 89 | 90 | or cx, cx 91 | jz _read_sectors 92 | 93 | jmp read_sectors 94 | _read_sectors: 95 | ret 96 | 97 | 98 | 99 | read_one_sect: 100 | ; relative sector # (ax) / sectors per one track (di) 101 | ; = relative track # (ax), absolute sector # in track (dx) 102 | mov ax, [current_sect] 103 | mov di, [sect_per_track] 104 | xor dx, dx 105 | div di 106 | 107 | ; sector # is 1-based count 108 | inc dl 109 | mov byte [read_sect], dl 110 | 111 | ; relative track # (ax) / headers count 112 | ; = absolute track # (ax), head number (dx) 113 | xor dx, dx 114 | div word [head_per_drv] 115 | 116 | mov ch, al ; track(cylinder) # 117 | mov cl, [read_sect] ; sector # 118 | mov ah, 2 ; service # 119 | mov al, 1 ; sector count 120 | mov dh, dl ; head # 121 | mov dl, [boot_drv] ; floppy 122 | mov bx, si ; offset 123 | int 0x13 124 | 125 | ; next sector to be read 126 | inc byte [current_sect] 127 | 128 | ret 129 | 130 | 131 | hello_msg db "C" 132 | 133 | times 510-($-$$) db 0 134 | dw 0xaa55 135 | 136 | 137 | 138 | -------------------------------------------------------------------------------- /src/except_entry.asm: -------------------------------------------------------------------------------- 1 | 2 | [bits 64] 3 | [CPU X64] 4 | [DEFAULT REL] 5 | 6 | 7 | 8 | 9 | extern do_divide_error 10 | 11 | extern do_divide_error ; 0 12 | extern do_debug ;1 13 | extern do_nmi ;2 14 | extern do_int3 ;3 15 | extern do_overflow ;4 16 | extern do_bounds ;5 17 | extern do_invalid_op ;6 18 | extern do_device_not_available ;7 19 | extern do_doublefault_fn ;8 20 | extern do_coprocessor_segment_overrun ;9 21 | extern do_invalid_TSS ;10 22 | extern do_segment_not_present ;11 23 | extern do_stack_segment ;12 24 | extern do_general_protection ;13 25 | extern do_page_fault ;14 26 | extern do_coprocessor_error ;16 27 | extern do_alignment_check ;17 28 | extern do_machine_check ;18 29 | extern do_simd_coprocessor_error ;19 30 | 31 | 32 | 33 | _ERROR equ 17*8 34 | _RIP equ 18*8 35 | _CS equ 19*8 36 | 37 | 38 | 39 | ; every general register is 40 | %macro SAVE_ALL 0 41 | 42 | push rax 43 | push rbx 44 | push rcx 45 | push rdx 46 | 47 | push rsi 48 | push rdi 49 | push rbp 50 | 51 | push r8 52 | push r9 53 | push r10 54 | push r11 55 | push r12 56 | push r13 57 | push r14 58 | push r15 59 | 60 | push fs 61 | push gs 62 | 63 | %endmacro 64 | 65 | 66 | ; SAVE_ALL is referred to linux-kernel 67 | %macro RESTORE_ALL 0 68 | 69 | pop fs 70 | pop gs 71 | 72 | pop r15 73 | pop r14 74 | pop r13 75 | pop r12 76 | pop r11 77 | pop r10 78 | pop r9 79 | pop r8 80 | 81 | ;pop rsp 82 | pop rbp 83 | pop rdi 84 | pop rsi 85 | 86 | pop rdx 87 | pop rcx 88 | pop rbx 89 | pop rax 90 | 91 | 92 | %endmacro 93 | 94 | 95 | 96 | section .text 97 | 98 | 99 | global _local_timer_test 100 | 101 | global _test_except 102 | global _ignore_isr 103 | 104 | 105 | global _divide_error ; 0 106 | global _debug ;1 107 | global _nmi ;2 108 | global _int3 ;3 109 | global _overflow ;4 110 | global _bounds ;5 111 | global _invalid_op ;6 112 | global _device_not_available ;7 113 | global _doublefault_fn ;8 114 | global _coprocessor_segment_overrun ;9 115 | global _invalid_TSS ;10 116 | global _segment_not_present ;11 117 | global _stack_segment ;12 118 | global _general_protection ;13 119 | global _page_fault ;14 120 | ; 15th exception is reserved for INTEL 121 | global _coprocessor_error ;16 122 | global _alignment_check ;17 123 | global _machine_check ;18 124 | global _simd_coprocessor_error ;19 125 | 126 | 127 | 128 | align 8 129 | _divide_error: 130 | 131 | push 0 ; no error code 132 | SAVE_ALL 133 | 134 | mov rdi, [rsp+_ERROR] 135 | mov rsi, [rsp+_RIP] 136 | call do_divide_error 137 | 138 | RESTORE_ALL 139 | add rsp, 8 140 | 141 | jmp $ 142 | 143 | 144 | align 8 145 | _debug: 146 | push 0 ; no error code 147 | SAVE_ALL 148 | 149 | mov rdi, [rsp+_ERROR] 150 | mov rsi, [rsp+_RIP] 151 | call do_debug 152 | 153 | 154 | RESTORE_ALL 155 | add rsp, 8 156 | 157 | jmp $ 158 | 159 | 160 | align 8 161 | _nmi: 162 | push 0 ; no error code 163 | SAVE_ALL 164 | 165 | mov rdi, [rsp+_ERROR] 166 | mov rsi, [rsp+_RIP] 167 | call do_nmi 168 | 169 | RESTORE_ALL 170 | add rsp, 8 171 | 172 | jmp $ 173 | 174 | 175 | align 8 176 | _int3: 177 | push 0 ; no error code 178 | SAVE_ALL 179 | 180 | mov rdi, [rsp+_ERROR] 181 | mov rsi, [rsp+_RIP] 182 | call do_int3 183 | 184 | RESTORE_ALL 185 | add rsp, 8 186 | 187 | jmp $ 188 | 189 | 190 | align 8 191 | _overflow: 192 | push 0 ; no error code 193 | SAVE_ALL 194 | 195 | mov rdi, [rsp+_ERROR] 196 | mov rsi, [rsp+_RIP] 197 | call do_overflow 198 | 199 | RESTORE_ALL 200 | add rsp, 8 201 | 202 | jmp $ 203 | 204 | 205 | 206 | align 8 207 | _bounds: 208 | push 0 ; no error code 209 | SAVE_ALL 210 | 211 | mov rdi, [rsp+_ERROR] 212 | mov rsi, [rsp+_RIP] 213 | call do_bounds 214 | 215 | RESTORE_ALL 216 | add rsp, 8 217 | 218 | jmp $ 219 | 220 | 221 | align 8 222 | _invalid_op: 223 | push 0 ; no error code 224 | SAVE_ALL 225 | 226 | mov rdi, [rsp+_ERROR] 227 | mov rsi, [rsp+_RIP] 228 | call do_invalid_op 229 | 230 | RESTORE_ALL 231 | add rsp, 8 232 | 233 | jmp $ 234 | 235 | 236 | 237 | align 8 238 | _device_not_available: 239 | push 0 ; no error code 240 | SAVE_ALL 241 | 242 | mov rdi, [rsp+_ERROR] 243 | mov rsi, [rsp+_RIP] 244 | call do_device_not_available 245 | 246 | RESTORE_ALL 247 | add rsp, 8 248 | 249 | jmp $ 250 | 251 | 252 | 253 | align 8 254 | _doublefault_fn: 255 | push 0 256 | SAVE_ALL 257 | 258 | mov rdi, [rsp+_ERROR] 259 | mov rsi, [rsp+_RIP] 260 | call do_doublefault_fn 261 | 262 | RESTORE_ALL 263 | add rsp, 8 264 | 265 | jmp $ 266 | 267 | 268 | 269 | align 8 270 | _coprocessor_segment_overrun: 271 | push 0 ; no error code 272 | SAVE_ALL 273 | 274 | mov rdi, [rsp+_ERROR] 275 | mov rsi, [rsp+_RIP] 276 | call do_coprocessor_segment_overrun 277 | 278 | RESTORE_ALL 279 | add rsp, 8 280 | 281 | jmp $ 282 | 283 | 284 | 285 | align 8 286 | _invalid_TSS: 287 | SAVE_ALL 288 | 289 | mov rdi, [rsp+_ERROR] 290 | mov rsi, [rsp+_RIP] 291 | call do_invalid_TSS 292 | 293 | RESTORE_ALL 294 | add rsp, 8 295 | 296 | jmp $ 297 | 298 | 299 | align 8 300 | _segment_not_present: 301 | SAVE_ALL 302 | 303 | mov rdi, [rsp+_ERROR] 304 | mov rsi, [rsp+_RIP] 305 | call do_segment_not_present 306 | 307 | RESTORE_ALL 308 | add rsp, 8 309 | 310 | jmp $ 311 | 312 | 313 | align 8 314 | _stack_segment: 315 | SAVE_ALL 316 | 317 | mov rdi, [rsp+_ERROR] 318 | mov rsi, [rsp+_RIP] 319 | call do_stack_segment 320 | 321 | RESTORE_ALL 322 | add rsp, 8 323 | 324 | jmp $ 325 | 326 | 327 | align 8 328 | _general_protection: 329 | SAVE_ALL 330 | 331 | mov rdi, [rsp+_ERROR] 332 | mov rsi, [rsp+_RIP] 333 | call do_general_protection 334 | 335 | RESTORE_ALL 336 | add rsp, 8 337 | 338 | iretq 339 | 340 | 341 | align 8 342 | _page_fault: 343 | SAVE_ALL 344 | 345 | mov rdi, [rsp+_ERROR] 346 | mov rsi, [rsp+_RIP] 347 | call do_page_fault 348 | 349 | RESTORE_ALL 350 | add rsp, 8 351 | 352 | jmp $ 353 | 354 | 355 | align 8 356 | _coprocessor_error: 357 | push 0 ; no error code 358 | SAVE_ALL 359 | 360 | mov rdi, [rsp+_ERROR] 361 | mov rsi, [rsp+_RIP] 362 | call do_coprocessor_error 363 | 364 | RESTORE_ALL 365 | add rsp, 8 366 | 367 | jmp $ 368 | 369 | 370 | align 8 371 | _alignment_check: 372 | SAVE_ALL 373 | 374 | mov rdi, [rsp+_ERROR] 375 | mov rsi, [rsp+_RIP] 376 | call do_alignment_check 377 | 378 | RESTORE_ALL 379 | add rsp, 8 380 | 381 | jmp $ 382 | 383 | 384 | align 8 385 | _machine_check: 386 | push 0 ; no error code 387 | SAVE_ALL 388 | 389 | mov rdi, [rsp+_ERROR] 390 | mov rsi, [rsp+_RIP] 391 | call do_machine_check 392 | 393 | RESTORE_ALL 394 | add rsp, 8 395 | 396 | jmp $ 397 | 398 | 399 | align 8 400 | _simd_coprocessor_error: 401 | push 0 ; no error code 402 | SAVE_ALL 403 | 404 | mov rdi, [rsp+_ERROR] 405 | mov rsi, [rsp+_RIP] 406 | call do_simd_coprocessor_error 407 | 408 | RESTORE_ALL 409 | add rsp, 8 410 | 411 | jmp $ 412 | 413 | 414 | 415 | 416 | ;----------------------------------------------------- 417 | 418 | align 8 419 | _local_timer_test: 420 | SAVE_ALL 421 | 422 | 423 | 424 | mov rdi, [rsp+_ERROR] 425 | mov rsi, [rsp+_RIP] 426 | call do_machine_check 427 | 428 | ;set EOI 429 | 430 | 431 | RESTORE_ALL 432 | 433 | 434 | 435 | iretq 436 | 437 | 438 | 439 | align 8 440 | _test_except: 441 | 442 | 443 | push rbx 444 | push rbp 445 | 446 | push r12 447 | push r13 448 | push r14 449 | push r15 450 | 451 | 452 | 453 | int 100 454 | 455 | 456 | pop r15 457 | pop r14 458 | pop r13 459 | pop r12 460 | pop rbp 461 | pop rbx 462 | 463 | ret 464 | 465 | 466 | -------------------------------------------------------------------------------- /src/except_handler.c: -------------------------------------------------------------------------------- 1 | 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | 9 | 10 | void do_divide_error(int err, u64 rip) 11 | { 12 | caos_printf("EXCEPTION: divide_error, error=%x, rip=%x\n", err, rip); 13 | 14 | } 15 | 16 | 17 | void do_debug(int err, u64 rip) 18 | { 19 | caos_printf("EXCEPTION: debug, error=%x, rip=%x\n", err, rip); 20 | } 21 | 22 | 23 | void do_nmi(int err, u64 rip) 24 | { 25 | caos_printf("EXCEPTION: nmi, error=%x, rip=%x\n", err, rip); 26 | } 27 | 28 | 29 | void do_int3(int err, u64 rip) 30 | { 31 | caos_printf("EXCEPTION: int3, error=%x, rip=%x\n", err, rip); 32 | } 33 | 34 | 35 | void do_overflow(int err, u64 rip) 36 | { 37 | caos_printf("EXCEPTION: overflow, error=%x, rip=%x\n", err, rip); 38 | } 39 | 40 | 41 | void do_bounds(int err, u64 rip) 42 | { 43 | caos_printf("EXCEPTION: bounds, error=%x, rip=%x\n", err, rip); 44 | } 45 | 46 | 47 | void do_invalid_op(int err, u64 rip) 48 | { 49 | caos_printf("EXCEPTION: invalid operatioin, error=%x, rip=%x\n", err, rip); 50 | } 51 | 52 | 53 | void do_device_not_available(int err, u64 rip) 54 | { 55 | caos_printf("EXCEPTION: device not avalible, error=%x, rip=%x\n", err, rip); 56 | } 57 | 58 | 59 | void do_doublefault_fn(int err, u64 rip) 60 | { 61 | caos_printf("EXCEPTION: doublefault, error=%x, rip=%x\n", err, rip); 62 | } 63 | 64 | 65 | void do_coprocessor_segment_overrun(int err, u64 rip) 66 | { 67 | caos_printf("EXCEPTION: coprocessor segment overrun, error=%x, rip=%x\n", err, rip); 68 | } 69 | 70 | 71 | void do_invalid_TSS(int err, u64 rip) 72 | { 73 | caos_printf("EXCEPTION: invalid TSS, error=%x, rip=%x\n", err, rip); 74 | } 75 | 76 | 77 | void do_segment_not_present(int err, u64 rip) 78 | { 79 | caos_printf("EXCEPTION: segment not present, error=%x, rip=%x\n", err, rip); 80 | } 81 | 82 | 83 | void do_stack_segment(int err, u64 rip) 84 | { 85 | caos_printf("EXCEPTION: stack segment, error=%x, rip=%x\n", err, rip); 86 | } 87 | 88 | 89 | void do_general_protection(int err, u64 rip) 90 | { 91 | caos_printf("EXCEPTION: general protection, error=%x, rip=%x\n", err, rip); 92 | } 93 | 94 | 95 | void do_page_fault(int err, u64 rip) 96 | { 97 | caos_printf("EXCEPTION: page fault, error=%x, rip=%x\n", err, rip); 98 | } 99 | 100 | 101 | void do_coprocessor_error(int err, u64 rip) 102 | { 103 | caos_printf("EXCEPTION: coprocessor error, error=%x, rip=%x\n", err, rip); 104 | } 105 | 106 | 107 | void do_alignment_check(int err, u64 rip) 108 | { 109 | caos_printf("EXCEPTION: alignment check, error=%x, rip=%x\n", err, rip); 110 | } 111 | 112 | 113 | void do_machine_check(int err, u64 rip) 114 | { 115 | caos_printf("EXCEPTION: machine check , error=%x, rip=%x\n", err, rip); 116 | } 117 | 118 | 119 | void do_simd_coprocessor_error(int err, u64 rip) 120 | { 121 | caos_printf("EXCEPTION: SIMD coprocessor error, error=%x, rip=%x\n", err, rip); 122 | } 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | -------------------------------------------------------------------------------- /src/gdt.c: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | #include 5 | #include 6 | #include // alloc_bootmem() 7 | #include // memset 8 | 9 | #include 10 | 11 | 12 | #define DEBUG 13 | #undef DEBUG 14 | 15 | 16 | struct gdt_desc *gdt_table; 17 | 18 | struct tss_struct *tss; 19 | 20 | 21 | // 22 | // address in GDTR must be linear address 23 | // @newgdt: linear address of new GDT 24 | // @limit: size of GDT 25 | // 26 | void set_gdt(void *newgdt, u16 limit) 27 | { 28 | struct gdt_desc_ptr curgdtr; 29 | 30 | curgdtr.size = limit; 31 | curgdtr.address = (u64)newgdt; 32 | 33 | 34 | 35 | __asm__ __volatile__ ( 36 | "lgdtq %0\n" 37 | : : "m" (curgdtr) 38 | ); 39 | 40 | load_segments(); 41 | 42 | } 43 | 44 | 45 | 46 | // 47 | // initialize segment registers, ds,es,ss,fs,gs, with data segment index. 48 | // 49 | void load_segments(void) 50 | { 51 | // memory barrier is needed 52 | __asm__ __volatile__ ( 53 | "\tmovl %0, %%ds\n" 54 | "\tmovl %0, %%es\n" 55 | "\tmovl %0, %%ss\n" 56 | "\tmovl %0, %%fs\n" 57 | "\tmovl %0, %%gs\n" 58 | : : "a" (__KERNEL_DS64) : "memory" 59 | ); 60 | } 61 | 62 | 63 | 64 | // 65 | // allocated one page for TSS and set TR register. 66 | // @num: TSS segment index in GDT 67 | // 68 | void set_tss(size_t num) 69 | { 70 | 71 | u64 address = (u64)alloc_bootmem(1); 72 | u16 tss_selector = num << 3; 73 | 74 | set_gdt_desc(num, (u32)(address & 0xFFFFFFFF), 104, 0x89); 75 | 76 | gdt_table[num+1].l = (u32)((address>>32) & 0xFFFFFFFF); 77 | 78 | 79 | caos_printf("TSS address=%x\n", address); 80 | caos_memset((void *)address, 0, PAGE_SIZE); 81 | 82 | __asm__ __volatile__ ( 83 | "\tltrw %0\n" 84 | : : "m" (tss_selector) 85 | ); 86 | 87 | tss = (struct tss_struct *)address; 88 | 89 | 90 | } 91 | 92 | 93 | 94 | void gdt_init(u64 boot_gdt_addr) 95 | { 96 | u64 *boot_gdt = (u64 *)boot_gdt_addr; 97 | int i = 1; 98 | 99 | gdt_table = (struct gdt_desc *)alloc_bootmem(1); 100 | 101 | 102 | // 103 | // copy booting-step GDT and re-use it. 104 | // 105 | while (boot_gdt[i] != 0) { 106 | caos_memcpy(&gdt_table[i], &boot_gdt[i], sizeof(struct gdt_desc)); 107 | i++; 108 | } 109 | 110 | #ifdef DEBUG 111 | caos_printf("%d desc copy\n", i); 112 | 113 | for (; i>0; i--) { 114 | caos_printf("%x\n", gdt_table[i]); 115 | } 116 | 117 | #endif 118 | 119 | set_gdt(gdt_table, PAGE_SIZE); 120 | 121 | caos_printf("GDT table at %x\n", (u64)gdt_table); 122 | 123 | // 0: null desc 124 | // 1~2: 32bit desc 125 | // 3~4: 64bit desc 126 | // 5~6: TSS desc 127 | 128 | set_tss(5); 129 | 130 | 131 | } 132 | 133 | 134 | 135 | void set_gdt_desc(size_t num, u32 addr, u32 offset, flag_t type ) 136 | { 137 | 138 | gdt_table[num].l = (u32)(offset & 0xffff) 139 | | (u32)((addr & 0xffff)<<16); 140 | 141 | gdt_table[num].h = (u32)(addr & 0xff000000) 142 | | (u32)((addr>>16) & 0xff) 143 | | (u32)(offset & 0xf0000) 144 | | (u32)((type<<12) & 0xf00000) 145 | | (u32)((type<<8) & 0xff00); 146 | } 147 | 148 | 149 | 150 | 151 | 152 | -------------------------------------------------------------------------------- /src/idt.c: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | #include 6 | #include // __KERNEL_CS64 7 | #include 8 | 9 | #include // caos_memset() 10 | #include // PAGE_SIZE 11 | #include // alloc_bootmem() 12 | 13 | #include 14 | #include // _ignore_isr 15 | 16 | #include 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | // 25 | // load IDTR with linear address and size of IDT 26 | // @newidt: linear address of IDT 27 | // @limit: size of IDT 28 | // 29 | static void set_idt(void *newidt, u16 limit) 30 | { 31 | struct idt_desc_ptr curidtr; 32 | 33 | curidtr.size = limit; 34 | curidtr.address = (u64)newidt; 35 | 36 | __asm__ __volatile__ ( 37 | "lidtq %0\n" 38 | : : "m" (curidtr) 39 | ); 40 | 41 | } 42 | 43 | 44 | 45 | // 46 | // IDT table build 47 | // 48 | void idt_init(void) 49 | { 50 | size_t i; 51 | 52 | idt_table = (struct idt_desc *)alloc_bootmem(1); 53 | 54 | 55 | 56 | // clear IDT area 57 | caos_memset(idt_table, 0, PAGE_SIZE); 58 | 59 | 60 | // default interrupt handler 61 | for (i = 0; i < IDT_SIZE; i++) { 62 | set_trap_gate(i, _ignore_isr); 63 | } 64 | 65 | 66 | // set GDTR 67 | set_idt(idt_table, PAGE_SIZE); 68 | 69 | caos_printf("IDT table at %x\n", (u64)idt_table); 70 | 71 | 72 | // processor exception handlers 73 | set_trap_gate(0, _divide_error); 74 | set_trap_gate(1, _debug); 75 | set_intr_gate(2, _nmi); 76 | set_system_gate(3, _int3); 77 | set_system_gate(4, _overflow); 78 | set_system_gate(5, _bounds); 79 | set_trap_gate(6, _invalid_op); 80 | set_trap_gate(7, _device_not_available); 81 | set_trap_gate(8, _doublefault_fn); 82 | set_trap_gate(9, _coprocessor_segment_overrun); 83 | set_trap_gate(10, _invalid_TSS); 84 | set_trap_gate(11, _segment_not_present); 85 | set_trap_gate(12, _stack_segment); 86 | set_trap_gate(13, _general_protection); 87 | set_intr_gate(14, _page_fault); 88 | set_trap_gate(16, _coprocessor_error); 89 | set_trap_gate(17, _alignment_check); 90 | set_trap_gate(18, _machine_check); 91 | set_trap_gate(19, _simd_coprocessor_error); 92 | 93 | 94 | } 95 | 96 | 97 | 98 | // 99 | // add interrupt-gate into IDT 100 | // @num: exception number 101 | // @handler: linear address of entry point of exception handler 102 | // 103 | void set_intr_gate(size_t num, void *handler) 104 | { 105 | if (num < IDT_SIZE) { 106 | idt_table[num].offset0_15 = (u16)((u64)handler & 0xffff); 107 | idt_table[num].selector = __KERNEL_CS64; 108 | idt_table[num].type = DESTYPE_INT; 109 | idt_table[num].offset16_31 = (u16)(((u64)handler & 0xFFFF0000) >> 16); 110 | idt_table[num].offset32_63 = (u32)(((u64)handler & 0xFFFFFFFF00000000) >> 32); 111 | idt_table[num].reserved = (u32)0; 112 | } 113 | 114 | } 115 | 116 | 117 | // system-call descriptor 118 | void set_system_gate(size_t num, void *handler) 119 | { 120 | if (num < IDT_SIZE) { 121 | idt_table[num].offset0_15 = (u16)((u64)handler & 0xffff); 122 | idt_table[num].selector = __KERNEL_CS64; 123 | idt_table[num].type = DESTYPE_SYS; 124 | idt_table[num].offset16_31 = (u16)(((u64)handler & 0xFFFF0000) >> 16); 125 | idt_table[num].offset32_63 = (u32)(((u64)handler & 0xFFFFFFFF00000000) >> 32); 126 | idt_table[num].reserved = (u32)0; 127 | } 128 | 129 | 130 | } 131 | 132 | void set_trap_gate(size_t num, void *handler) 133 | { 134 | if (num < IDT_SIZE) { 135 | idt_table[num].offset0_15 = (u16)((u64)handler & 0xffff); 136 | idt_table[num].selector = __KERNEL_CS64; 137 | idt_table[num].type = DESTYPE_TRAP; 138 | idt_table[num].offset16_31 = (u16)(((u64)handler & 0xFFFF0000) >> 16); 139 | idt_table[num].offset32_63 = (u32)(((u64)handler & 0xFFFFFFFF00000000) >> 32); 140 | idt_table[num].reserved = (u32)0; 141 | } 142 | 143 | 144 | } 145 | 146 | 147 | 148 | 149 | -------------------------------------------------------------------------------- /src/include/atomic.h: -------------------------------------------------------------------------------- 1 | #ifndef __ATOMIC_H__ 2 | #define __ATOMIC_H__ 3 | 4 | 5 | #include "types.h" 6 | 7 | 8 | // 9 | // If SMP machine, atomic operation needs bus-locking instruction. 10 | // 11 | #define LOCK_PREFIX "lock; " 12 | 13 | 14 | 15 | /* The 64-bit atomic type */ 16 | 17 | #define ATOMIC_INIT(i) { (i) } 18 | 19 | /** 20 | * atomic_read - read atomic variable 21 | * @v: pointer of type atomic_t 22 | * 23 | * Atomically reads the value of @v. 24 | * Doesn't imply a read memory barrier. 25 | */ 26 | #define atomic_read(v) ((v)->counter) 27 | 28 | /** 29 | * atomic_set - set atomic variable 30 | * @v: pointer to type atomic_t 31 | * @i: required value 32 | * 33 | * Atomically sets the value of @v to @i. 34 | */ 35 | #define atomic_set(v, i) (((v)->counter) = (i)) 36 | 37 | /** 38 | * atomic_add - add integer to atomic variable 39 | * @i: integer value to add 40 | * @v: pointer to type atomic_t 41 | * 42 | * Atomically adds @i to @v. 43 | */ 44 | static inline void atomic_add(long i, atomic_t *v) 45 | { 46 | asm volatile(LOCK_PREFIX "addq %1,%0" 47 | : "=m" (v->counter) 48 | : "er" (i), "m" (v->counter)); 49 | } 50 | 51 | /** 52 | * atomic_sub - subtract the atomic variable 53 | * @i: integer value to subtract 54 | * @v: pointer to type atomic_t 55 | * 56 | * Atomically subtracts @i from @v. 57 | */ 58 | static inline void atomic_sub(long i, atomic_t *v) 59 | { 60 | asm volatile(LOCK_PREFIX "subq %1,%0" 61 | : "=m" (v->counter) 62 | : "er" (i), "m" (v->counter)); 63 | } 64 | 65 | /** 66 | * atomic_sub_and_test - subtract value from variable and test result 67 | * @i: integer value to subtract 68 | * @v: pointer to type atomic_t 69 | * 70 | * Atomically subtracts @i from @v and returns 71 | * true if the result is zero, or false for all 72 | * other cases. 73 | */ 74 | static inline int atomic_sub_and_test(long i, atomic_t *v) 75 | { 76 | unsigned char c; 77 | 78 | asm volatile(LOCK_PREFIX "subq %2,%0; sete %1" 79 | : "=m" (v->counter), "=qm" (c) 80 | : "er" (i), "m" (v->counter) : "memory"); 81 | return c; 82 | } 83 | 84 | /** 85 | * atomic_inc - increment atomic variable 86 | * @v: pointer to type atomic_t 87 | * 88 | * Atomically increments @v by 1. 89 | */ 90 | static inline void atomic_inc(atomic_t *v) 91 | { 92 | asm volatile(LOCK_PREFIX "incq %0" 93 | : "=m" (v->counter) 94 | : "m" (v->counter)); 95 | } 96 | 97 | /** 98 | * atomic_dec - decrement atomic variable 99 | * @v: pointer to type atomic_t 100 | * 101 | * Atomically decrements @v by 1. 102 | */ 103 | static inline void atomic_dec(atomic_t *v) 104 | { 105 | asm volatile(LOCK_PREFIX "decq %0" 106 | : "=m" (v->counter) 107 | : "m" (v->counter)); 108 | } 109 | 110 | 111 | /** 112 | * atomic_dec_and_test - decrement and test 113 | * @v: pointer to type atomic_t 114 | * 115 | * Atomically decrements @v by 1 and 116 | * returns true if the result is 0, or false for all other 117 | * cases. 118 | */ 119 | static inline int atomic_dec_and_test(atomic_t *v) 120 | { 121 | unsigned char c; 122 | 123 | asm volatile(LOCK_PREFIX "decq %0; sete %1" 124 | : "=m" (v->counter), "=qm" (c) 125 | : "m" (v->counter) : "memory"); 126 | return c != 0; 127 | } 128 | 129 | /** 130 | * atomic_inc_and_test - increment and test 131 | * @v: pointer to type atomic_t 132 | * 133 | * Atomically increments @v by 1 134 | * and returns true if the result is zero, or false for all 135 | * other cases. 136 | */ 137 | static inline int atomic_inc_and_test(atomic_t *v) 138 | { 139 | unsigned char c; 140 | 141 | asm volatile(LOCK_PREFIX "incq %0; sete %1" 142 | : "=m" (v->counter), "=qm" (c) 143 | : "m" (v->counter) : "memory"); 144 | return c != 0; 145 | } 146 | 147 | 148 | /** 149 | * atomic_add_return - add and return 150 | * @i: integer value to add 151 | * @v: pointer to type atomic_t 152 | * 153 | * Atomically adds @i to @v and returns @i + @v 154 | */ 155 | static inline long atomic_add_return(long i, atomic_t *v) 156 | { 157 | long __i = i; 158 | asm volatile(LOCK_PREFIX "xaddq %0, %1;" 159 | : "+r" (i), "+m" (v->counter) 160 | : : "memory"); 161 | return i + __i; 162 | } 163 | 164 | /** 165 | * substract and return result 166 | * 167 | * @param i 168 | * @param v 169 | * 170 | * @return 171 | */ 172 | static inline long atomic_sub_return(long i, atomic_t *v) 173 | { 174 | return atomic_add_return(-i, v); 175 | } 176 | 177 | /** 178 | * compare and swap 179 | * 180 | * @param ptr data to swap 181 | * @param old comparation value 182 | * @param new new value 183 | * 184 | * @return old value 185 | */ 186 | static inline unsigned long atomic_cmpxchg(volatile void *ptr, 187 | unsigned long old, 188 | unsigned long new) 189 | { 190 | unsigned long prev; 191 | 192 | asm volatile(LOCK_PREFIX "cmpxchgq %1,%2" 193 | : "=a"(prev) 194 | : "r"(new), "m"(*(volatile long *)ptr), "0"(old) 195 | : "memory"); 196 | return prev; 197 | 198 | } 199 | 200 | 201 | #endif 202 | -------------------------------------------------------------------------------- /src/include/bitops.h: -------------------------------------------------------------------------------- 1 | 2 | // 3 | // copy of linux/include/asm-x86_64/bitops.h 4 | // 5 | #ifndef __BITOPS_H__ 6 | #define __BITOPS_H__ 7 | 8 | #include 9 | 10 | 11 | 12 | // 13 | // Every bit-operation must consider SMP and use LOCK primitive. 14 | // Bit-operations for UP are removed. - 2009.4.22 15 | // 16 | 17 | 18 | // 19 | // If SMP machine, atomic operation needs bus-locking instruction. 20 | // 21 | #define LOCK_PREFIX \ 22 | "lock; " 23 | 24 | 25 | 26 | 27 | #define ADDR(x) "+m" (*(volatile long *) (x)) 28 | 29 | /** 30 | * set_bit - Atomically set a bit in memory 31 | * @nr: the bit to set 32 | * @addr: the address to start counting from 33 | * 34 | * This function is atomic and may not be reordered. See __set_bit() 35 | * if you do not require the atomic guarantees. 36 | * Note that @nr may be almost arbitrarily large; this function is not 37 | * restricted to acting on a single-word quantity. 38 | */ 39 | static __inline__ void set_bit(size_t nr, volatile void * addr) 40 | { 41 | __asm__ __volatile__( 42 | LOCK_PREFIX 43 | "btsq %1,%0" 44 | :ADDR(addr) 45 | :"dIr" (nr) : "memory"); 46 | } 47 | 48 | 49 | /** 50 | * clear_bit - Clears a bit in memory 51 | * @nr: Bit to clear 52 | * @addr: Address to start counting from 53 | * 54 | * clear_bit() is atomic and may not be reordered. However, it does 55 | * not contain a memory barrier, so if it is used for locking purposes, 56 | * you should call smp_mb__before_clear_bit() and/or smp_mb__after_clear_bit() 57 | * in order to ensure changes are visible on other processors. 58 | */ 59 | static __inline__ void clear_bit(ssize_t nr, volatile void * addr) 60 | { 61 | __asm__ __volatile__( 62 | LOCK_PREFIX 63 | "btrq %1,%0" 64 | :ADDR(addr) 65 | :"dIr" (nr)); 66 | } 67 | 68 | 69 | 70 | /** 71 | * change_bit - Toggle a bit in memory 72 | * @nr: Bit to change 73 | * @addr: Address to start counting from 74 | * 75 | * change_bit() is atomic and may not be reordered. 76 | * Note that @nr may be almost arbitrarily large; this function is not 77 | * restricted to acting on a single-word quantity. 78 | */ 79 | static __inline__ void change_bit(ssize_t nr, volatile void * addr) 80 | { 81 | __asm__ __volatile__( 82 | LOCK_PREFIX 83 | "btcq %1,%0" 84 | :ADDR(addr) 85 | :"dIr" (nr)); 86 | } 87 | 88 | /** 89 | * test_and_set_bit - Set a bit and return its old value 90 | * @nr: Bit to set 91 | * @addr: Address to count from 92 | * 93 | * This operation is atomic and cannot be reordered. 94 | * It also implies a memory barrier. 95 | */ 96 | static __inline__ ssize_t test_and_set_bit(ssize_t nr, volatile void * addr) 97 | { 98 | ssize_t oldbit; 99 | 100 | __asm__ __volatile__( 101 | LOCK_PREFIX 102 | "btsq %2,%1\n\t" 103 | "sbbl %0,%0\n\t" 104 | :"=r" (oldbit),ADDR(addr) 105 | :"dIr" (nr) : "memory"); 106 | return oldbit; 107 | } 108 | 109 | 110 | 111 | /** 112 | * test_and_clear_bit - Clear a bit and return its old value 113 | * @nr: Bit to clear 114 | * @addr: Address to count from 115 | * 116 | * This operation is atomic and cannot be reordered. 117 | * It also implies a memory barrier. 118 | */ 119 | static __inline__ ssize_t test_and_clear_bit(ssize_t nr, volatile void * addr) 120 | { 121 | ssize_t oldbit; 122 | 123 | __asm__ __volatile__( 124 | LOCK_PREFIX 125 | "btrq %2,%1\n\t" 126 | "sbbl %0,%0\n\t" 127 | :"=r" (oldbit),ADDR(addr) 128 | :"dIr" (nr) : "memory"); 129 | return oldbit; 130 | } 131 | 132 | 133 | 134 | /** 135 | * test_and_change_bit - Change a bit and return its old value 136 | * @nr: Bit to change 137 | * @addr: Address to count from 138 | * 139 | * This operation is atomic and cannot be reordered. 140 | * It also implies a memory barrier. 141 | */ 142 | static __inline__ ssize_t test_and_change_bit(ssize_t nr, volatile void * addr) 143 | { 144 | ssize_t oldbit; 145 | 146 | __asm__ __volatile__( 147 | LOCK_PREFIX 148 | "btcq %2,%1\n\t" 149 | "sbbl %0,%0\n\t" 150 | :"=r" (oldbit),ADDR(addr) 151 | :"dIr" (nr) : "memory"); 152 | return oldbit; 153 | } 154 | 155 | /** 156 | * test_bit - Determine whether a bit is set 157 | * @nr: bit number to test 158 | * @addr: Address to start counting from 159 | */ 160 | 161 | static __inline__ ssize_t test_bit(ssize_t nr, const volatile void * addr) 162 | { 163 | 164 | size_t oldbit; 165 | 166 | __asm__ __volatile__( 167 | LOCK_PREFIX 168 | "btq %2,%1\n\t" 169 | "sbbq %0,%0\n\t" 170 | :"=r" (oldbit) 171 | :"m" (*(volatile long *)addr), "dlr" (nr)); 172 | return oldbit; 173 | } 174 | 175 | 176 | 177 | /** 178 | * ffz - find first zero in word. 179 | * @word: The word to search 180 | * 181 | * Undefined if no zero exists, so code should check against ~0UL first. 182 | */ 183 | static __inline__ size_t ffz(size_t word) 184 | { 185 | if (word == ((unsigned long)0x0) - 1) 186 | return (unsigned long)0x0 - 1; 187 | 188 | __asm__ __volatile__( 189 | "bsfq %1,%0" 190 | :"=r" (word) 191 | :"r" (~word)); 192 | return word; 193 | } 194 | 195 | /** 196 | * __ffs - find first bit in word. 197 | * @word: The word to search 198 | * 199 | * Undefined if no bit exists, so code should check against 0 first. 200 | */ 201 | static __inline__ size_t __ffs(size_t word) 202 | { 203 | if (word == 0) 204 | return 0; 205 | 206 | __asm__ __volatile__( 207 | "bsfq %1,%0" 208 | :"=r" (word) 209 | :"rm" (word)); 210 | return word; 211 | } 212 | 213 | 214 | /* 215 | * __fls: find last bit set. 216 | * @word: The word to search 217 | * 218 | * Undefined if no zero exists, so code should check against ~0UL first. 219 | */ 220 | static __inline__ size_t __fls(size_t word) 221 | { 222 | __asm__ __volatile__( 223 | "bsrq %1,%0" 224 | :"=r" (word) 225 | :"rm" (word)); 226 | return word; 227 | } 228 | 229 | /** 230 | * fls64 - find last bit set in 64 bit word 231 | * @x: the word to search 232 | * 233 | * This is defined the same way as fls. 234 | */ 235 | static __inline__ size_t fls64(size_t x) 236 | { 237 | if (x == 0) 238 | return 0; 239 | return __fls(x) + 1; 240 | } 241 | 242 | 243 | 244 | #endif 245 | -------------------------------------------------------------------------------- /src/include/cdev.h: -------------------------------------------------------------------------------- 1 | 2 | struct file_operations { 3 | struct module *owner; 4 | loff_t (*llseek) (struct file *, loff_t, int); 5 | ssize_t (*read) (struct file *, char __user *, size_t, loff_t *); 6 | ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *); 7 | int (*ioctl) (struct inode *, struct file *, unsigned int, unsigned long); 8 | int (*mmap) (struct file *, struct vm_area_struct *); 9 | int (*open) (struct inode *, struct file *); 10 | int (*flush) (struct file *); 11 | int (*release) (struct inode *, struct file *); 12 | int (*lock) (struct file *, int, struct file_lock *); 13 | }; 14 | -------------------------------------------------------------------------------- /src/include/char_device.h: -------------------------------------------------------------------------------- 1 | #ifndef __CHAR_DEVICE_H__ 2 | #define __CHAR_DEVICE_H__ 3 | 4 | 5 | 6 | 7 | typedef struct char_device_struct { 8 | //struct char_device_struct *next; 9 | unsigned int major; 10 | //unsigned int minor; 11 | char *name; 12 | struct file_operations *fops; 13 | } char_device_struct_t; 14 | 15 | 16 | 17 | typedef struct file_operations { 18 | int (*read)(char *buf, int size, int offset); 19 | int (*write)(const char *buf, int size, int offset); 20 | int (*open)(const char *name); 21 | int (*close)(const char *name); 22 | int (*ioctl)(unsigned int cmd); 23 | } file_operations_t; 24 | 25 | 26 | int register_chrdev(char *name, char_device_struct_t *cdev); 27 | int unregister_chrdev(int major_num, char *); 28 | void init_char_dev(void); 29 | 30 | 31 | #endif 32 | -------------------------------------------------------------------------------- /src/include/except_entry.h: -------------------------------------------------------------------------------- 1 | 2 | 3 | #ifndef __EXCEPT_ENTRY_H__ 4 | #define __EXCEPT_ENTRY_H__ 5 | 6 | 7 | 8 | //void _local_timer_test(void); 9 | 10 | void _test_except(void); 11 | //void _ignore_isr(void); 12 | //void ignore_isr_handler(size_t err, u64 rip); 13 | 14 | 15 | // 16 | // assembly routines that are invoked by processor exceptions 17 | // 18 | extern void _divide_error(void); 19 | extern void _debug(void); 20 | extern void _nmi(void); 21 | extern void _int3(void); 22 | extern void _overflow(void); 23 | extern void _bounds(void); 24 | extern void _invalid_op(void); 25 | extern void _device_not_available(void); 26 | extern void _doublefault_fn(void); 27 | extern void _coprocessor_segment_overrun(void); 28 | extern void _invalid_TSS(void); 29 | extern void _segment_not_present(void); 30 | extern void _stack_segment(void); 31 | extern void _general_protection(void); 32 | extern void _page_fault(void); 33 | extern void _coprocessor_error(void); 34 | extern void _alignment_check(void); 35 | extern void _machine_check(void); 36 | extern void _simd_coprocessor_error(void); 37 | 38 | 39 | 40 | #endif 41 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /src/include/except_handler.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef __EXCEPT_HANDLER_H__ 3 | #define __EXCEPT_HANDLER_H__ 4 | 5 | #include 6 | 7 | 8 | // 9 | // processor exception handlers that are invoked by assembly routines 10 | // 11 | void do_divide_error(int err, u64 rip); 12 | void do_debug(int err, u64 rip); 13 | void do_nmi(int err, u64 rip); 14 | void do_int3(int err, u64 rip); 15 | void do_overflow(int err, u64 rip); 16 | void do_bounds(int err, u64 rip); 17 | void do_invalid_op(int err, u64 rip); 18 | void do_device_not_available(int err, u64 rip); 19 | void do_doublefault(int err, u64 rip); 20 | void do_coprocessor_segment_overrun(int err, u64 rip); 21 | void do_invalid_TSS(int err, u64 rip); 22 | void do_segment_not_present(int err, u64 rip); 23 | void do_stack_segment(int err, u64 rip); 24 | void do_general_protection(int err, u64 rip); 25 | void do_page_fault(int err, u64 rip); 26 | void do_coprocessor_error(int err, u64 rip); 27 | void do_alignment_check(int err, u64 rip); 28 | void do_machine_check(int err, u64 rip); 29 | void do_simd_coprocessor_error(int err, u64 rip); 30 | 31 | 32 | 33 | #endif 34 | -------------------------------------------------------------------------------- /src/include/gdt.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef __GDT_H__ 3 | #define __GDT_H__ 4 | 5 | #include 6 | 7 | 8 | #define __KERNEL_CS32 0x08 9 | #define __KERNEL_DS32 0x10 10 | #define __KERNEL_CS64 0x18 11 | #define __KERNEL_DS64 0x20 12 | 13 | 14 | // copy of linux/include/asm-x86_64/desc_defs.h 15 | // 8byte descriptor 16 | struct gdt_desc { 17 | u32 l,h; 18 | } __attribute__((packed)); 19 | 20 | 21 | struct gdt_desc_ptr { 22 | u16 size; // 16bit table limit 23 | u64 address; // 64bit linear address 24 | } __attribute__ ((packed)); 25 | 26 | 27 | /* 28 | * Size of io_bitmap. 29 | */ 30 | #define IO_BITMAP_BITS 65536 31 | #define IO_BITMAP_BYTES (IO_BITMAP_BITS/8) 32 | #define IO_BITMAP_LONGS (IO_BITMAP_BYTES/sizeof(long)) 33 | #define IO_BITMAP_OFFSET offsetof(struct tss_struct,io_bitmap) 34 | #define INVALID_IO_BITMAP_OFFSET 0x8000 35 | 36 | 37 | 38 | struct tss_struct { 39 | u32 reserved1; 40 | u64 rsp0; 41 | u64 rsp1; 42 | u64 rsp2; 43 | u64 reserved2; 44 | u64 ist[7]; 45 | u32 reserved3; 46 | u32 reserved4; 47 | u16 reserved5; 48 | u16 io_bitmap_base; 49 | /* 50 | * The extra 1 is there because the CPU will access an 51 | * additional byte beyond the end of the IO permission 52 | * bitmap. The extra byte must be all 1 bits, and must 53 | * be within the limit. Thus we have: 54 | * 55 | * 128 bytes, the bitmap itself, for ports 0..0x3ff 56 | * 8 bytes, for an extra "long" of ~0UL 57 | */ 58 | unsigned long io_bitmap[IO_BITMAP_LONGS + 1]; 59 | } __attribute__((packed)) ____cacheline_aligned; 60 | 61 | 62 | 63 | 64 | 65 | void gdt_init(u64); 66 | void set_gdt_desc(size_t num, u32 addr, u32 offset, flag_t type ); 67 | 68 | /* set task state segment... */ 69 | #define set_tss_desc(num,addr) set_gdt_desc(num,addr,235,0x89) 70 | 71 | void load_segments(void); 72 | 73 | #endif 74 | -------------------------------------------------------------------------------- /src/include/idt.h: -------------------------------------------------------------------------------- 1 | /******************************************************************** 2 | * DESCRIPTION : functions and data for initializing Interrupt Descriptor Table 3 | * FILE NAME : idt.h 4 | *******************************************************************/ 5 | 6 | #ifndef __IDT_H__ 7 | #define __IDT_H__ 8 | 9 | //#include 10 | #include 11 | 12 | 13 | 14 | /* 15 | * exception type 16 | */ 17 | #define DESTYPE_INT 0x8e00 /* interrupt descriptor type : 01110, DPL=0 */ 18 | #define DESTYPE_TRAP 0x8f00 /* trap descriptor type : 01111, DPL=0 */ 19 | 20 | #define DESTYPE_SYS 0xef00 // system call type, trap-type, DPL=3 21 | 22 | #define IDT_SIZE 256 /* length of table */ 23 | 24 | /* Interrupt Descriptor Table */ 25 | struct idt_desc { 26 | u16 offset0_15; 27 | u16 selector; 28 | u16 type; 29 | u16 offset16_31; 30 | u32 offset32_63; 31 | u32 reserved; 32 | 33 | } __attribute__ ((packed)); 34 | 35 | struct idt_desc_ptr { 36 | u16 size; // 16bit table limit 37 | u64 address; // 64bit linear address 38 | } __attribute__ ((packed)); 39 | 40 | 41 | 42 | struct idt_desc *idt_table; 43 | 44 | void idt_init(void); 45 | void set_intr_gate(size_t, void *); 46 | void set_system_gate(size_t num, void *handler); 47 | void set_trap_gate(size_t num, void *handler); 48 | 49 | 50 | 51 | 52 | #endif 53 | -------------------------------------------------------------------------------- /src/include/init.h: -------------------------------------------------------------------------------- 1 | #ifndef __INIT_H__ 2 | #define __INIT_H__ 3 | 4 | 5 | 6 | 7 | void init(void); 8 | 9 | 10 | 11 | #endif 12 | -------------------------------------------------------------------------------- /src/include/io.h: -------------------------------------------------------------------------------- 1 | /******************************************************************** 2 | * DESCRIPTION : port I/O 3 | * FILE NAME : IO.h 4 | *******************************************************************/ 5 | 6 | #ifndef __IO_H__ 7 | 8 | #define __IO_H__ 9 | 10 | 11 | #include 12 | #include 13 | 14 | 15 | #define __outb(p,v) __asm__ __volatile__ ("outb %b0,%w1"::"a"(v),"Nd"(p)) 16 | 17 | static inline u64 virt_to_phys(volatile void *address) 18 | { 19 | return __pa(address); 20 | } 21 | 22 | static inline void *phys_to_virt(u64 address) 23 | { 24 | return __va(address); 25 | } 26 | 27 | 28 | /* 29 | * gcc inline assembly indentifier 30 | * Output/Input list 31 | * = : value will be changed 32 | * a : ax 33 | * d : dx 34 | * N : 0~255 35 | */ 36 | 37 | /**************************************************************** 38 | * NAME : inb 39 | * SYNOPSIS : in byte 40 | * EXTERNAL EFFECTS : N/A 41 | * ARGUMENTS : port port number 42 | * RETURNS : _v read value from AL 43 | * ERRNOS : N/A 44 | ***************************************************************/ 45 | static inline unsigned char inb(unsigned short port) 46 | { 47 | unsigned char _v; 48 | __asm__ __volatile__ ("inb %w1, %0":"=a" (_v):"Nd" (port)); 49 | return _v; 50 | } 51 | 52 | /**************************************************************** 53 | * NAME : inw 54 | * SYNOPSIS : in word 55 | * EXTERNAL EFFECTS : N/A 56 | * ARGUMENTS : port port number 57 | * RETURNS : _v read value from word 58 | * ERRNOS : N/A 59 | ***************************************************************/ 60 | static inline unsigned short inw(unsigned short port) 61 | { 62 | unsigned short _v; 63 | __asm__ __volatile__ ("inw %w1,%0":"=a" (_v):"Nd"(port)); 64 | return _v; 65 | } 66 | 67 | /**************************************************************** 68 | * NAME : outb 69 | * SYNOPSIS : out byte 70 | * EXTERNAL EFFECTS : N/A 71 | * ARGUMENTS : port port number 72 | * value write value 73 | * RETURNS : N/A 74 | * ERRNOS : N/A 75 | ***************************************************************/ 76 | static inline void outb(unsigned short port, unsigned char value) 77 | { 78 | __asm__ __volatile__ ("outb %b0,%w1": :"a" (value), "Nd"(port)); 79 | } 80 | 81 | /**************************************************************** 82 | * NAME : outw 83 | * SYNOPSIS : out word 84 | * EXTERNAL EFFECTS : N/A 85 | * ARGUMENTS : port port number 86 | * value write value 87 | * RETURNS : N/A 88 | * ERRNOS : N/A 89 | ***************************************************************/ 90 | static inline void outw(unsigned short port, unsigned short value) 91 | { 92 | __asm__ __volatile__ ("outw %w0,%w1": :"a" (value), "Nd"(port)); 93 | } 94 | 95 | 96 | 97 | 98 | /* 99 | * readX/writeX() are used to access memory mapped devices. On some 100 | * architectures the memory mapped IO stuff needs to be accessed 101 | * differently. On the x86 architecture, we just read/write the 102 | * memory location directly. 103 | */ 104 | 105 | static inline u8 __readb(const volatile void *addr) 106 | { 107 | return *( volatile u8 *)addr; 108 | } 109 | static inline u16 __readw(const volatile void *addr) 110 | { 111 | return *( volatile u16 *)addr; 112 | } 113 | static inline u32 __readl(const volatile void *addr) 114 | { 115 | return *( volatile u32 *)addr; 116 | } 117 | static inline u64 __readq(const volatile void *addr) 118 | { 119 | return *( volatile u64 *)addr; 120 | } 121 | #define readb(x) __readb(x) 122 | #define readw(x) __readw(x) 123 | #define readl(x) __readl(x) 124 | #define readq(x) __readq(x) 125 | 126 | static inline void __writel(u32 b, volatile void *addr) 127 | { 128 | *( volatile u32 *)addr = b; 129 | } 130 | static inline void __writeq(u64 b, volatile void *addr) 131 | { 132 | *( volatile u64 *)addr = b; 133 | } 134 | static inline void __writeb(u8 b, volatile void *addr) 135 | { 136 | *( volatile u8 *)addr = b; 137 | } 138 | static inline void __writew(u16 b, volatile void *addr) 139 | { 140 | *( volatile u16 *)addr = b; 141 | } 142 | #define writeq(val,addr) __writeq((val),(addr)) 143 | #define writel(val,addr) __writel((val),(addr)) 144 | #define writew(val,addr) __writew((val),(addr)) 145 | #define writeb(val,addr) __writeb((val),(addr)) 146 | 147 | 148 | 149 | 150 | #endif 151 | -------------------------------------------------------------------------------- /src/include/io_apic.h: -------------------------------------------------------------------------------- 1 | #ifndef __IO_APIC_H__ 2 | #define __IO_APIC_H__ 3 | 4 | 5 | #include 6 | #include 7 | 8 | 9 | /* 10 | * REFINE!! refer to linux-2.6.27/include/asm-x86/io_apic.h 11 | * 12 | */ 13 | 14 | 15 | #define IO_APIC_BASE 0xFFFF8000C0000000 16 | 17 | //#define MAX_IO_APICS 128 18 | 19 | #define IO_APIC_ID 0x0 20 | #define IO_APIC_VERSION 0x1 21 | #define GET_IO_APIC_VERSION(x) ((x)&0xF) 22 | #define GET_IO_APIC_ENTRY(x) (((x)>>16)&0xFF) // max entry number 23 | #define IO_APIC_ARB 0x2 24 | 25 | #define IO_APIC_REDTBL_BASE 0x10 26 | #define IO_APIC_REDTBL0 0x10 27 | #define IO_APIC_REDTBL1 0x12 28 | #define IO_APIC_REDTBL2 0x14 29 | #define IO_APIC_REDTBL3 0x16 30 | #define IO_APIC_REDTBL4 0x18 31 | #define IO_APIC_REDTBL5 0x1A 32 | #define IO_APIC_REDTBL6 0x1C 33 | #define IO_APIC_REDTBL7 0x1E 34 | #define IO_APIC_REDTBL8 0x20 35 | #define IO_APIC_REDTBL9 0x22 36 | #define IO_APIC_REDTBL10 0x24 37 | #define IO_APIC_REDTBL11 0x26 38 | #define IO_APIC_REDTBL12 0x28 39 | #define IO_APIC_REDTBL13 0x2A 40 | #define IO_APIC_REDTBL14 0x2C 41 | #define IO_APIC_REDTBL15 0x2E 42 | #define IO_APIC_REDTBL16 0x30 43 | #define IO_APIC_REDTBL17 0x32 44 | #define IO_APIC_REDTBL18 0x34 45 | #define IO_APIC_REDTBL19 0x36 46 | #define IO_APIC_REDTBL20 0x38 47 | #define IO_APIC_REDTBL21 0x3A 48 | #define IO_APIC_REDTBL22 0x3C 49 | #define IO_APIC_REDTBL23 0x3E 50 | #define SET_IO_APIC_DEST(x) (((x)&0xFF)<<56) 51 | #define IO_APIC_IRQ_MASK (1<<16) 52 | #define IO_APIC_TRIG_MODE (1<<15) 53 | #define IO_APIC_IRR (1<<14) 54 | #define IO_APIC_INTPOL (1<<13) 55 | #define IO_APIC_DELIVS (1<<12) 56 | #define IO_APIC_DESTMOD (1<<11) 57 | #define IO_APIC_DELMOD_FIX ((0)<<8) 58 | #define IO_APIC_DELMOD_LOW ((1)<<8) 59 | #define IO_APIC_DELMOD_SMI ((2)<<8) 60 | #define IO_APIC_DELMOD_NMI ((4)<<8) 61 | #define IO_APIC_DELMOD_INIT ((5)<<8) 62 | #define IO_APIC_DELMOD_ExtINT ((7)<<8) 63 | 64 | 65 | 66 | // 67 | // copy of linux-2.6.20/arch/x86_64/kernel/io_apic.c 68 | // 69 | struct io_apic { 70 | // IO_APIC_BASE address is mapped to IO Register Select register (index) 71 | // IO_APIC_BASE+0x10 is mapped to IO Window register (data) 72 | u32 index; 73 | u32 unused[3]; 74 | u32 data; 75 | }; 76 | 77 | 78 | 79 | int io_apic_enable_irq(size_t irq); 80 | void io_apic_init(void); 81 | 82 | 83 | 84 | 85 | #endif 86 | -------------------------------------------------------------------------------- /src/include/irq_entry.h: -------------------------------------------------------------------------------- 1 | #ifndef __IRQ_ENTRY_H__ 2 | #define __IRQ_ENTRY_H__ 3 | 4 | 5 | 6 | 7 | extern void _ignore_isr(void); 8 | 9 | 10 | 11 | 12 | #endif 13 | -------------------------------------------------------------------------------- /src/include/irq_handler.h: -------------------------------------------------------------------------------- 1 | 2 | /******************************************************************** 3 | * DESCRIPTION : I do not know what these function do exactly. 4 | * I just copy it from several source. 5 | * I hate hardware programming, 6 | * but I have studied how hardware work for 2 years 7 | * to make my own OS. It is so difficult to me. ;-) 8 | * The most important thing is I cannot write any 9 | * description this file. :-( 10 | * FILE NAME : IRQ.h 11 | *******************************************************************/ 12 | #ifndef __IRQ_HANDLER_H__ 13 | 14 | #define __IRQ_HANDLER_H__ 15 | 16 | #include 17 | #include 18 | 19 | 20 | // maximum IRQ 21 | #define MAX_IRQ 32 22 | 23 | 24 | // Vector number is IDT index 25 | // IDT[0~0x1F] are reserved for processor's exceptions. 26 | // Then the base of vector number of IRQ 27 | // If keyboard's irq is #1, vector number of keyboard irq is 0x21 28 | // IO APIC vector must begin at 0x20 so that this value become 0x20 29 | #define VECTOR_BASE 0x20 30 | 31 | typedef void (*irq_handler_t)(size_t); 32 | 33 | 34 | 35 | // 36 | // IRQ number is device number (eg. keyboard irq = #1) 37 | // But vector number is the index of IDT 38 | // and then vector number is (#irq + 0x20). 39 | // 40 | #define IRQ_TO_VECTOR(num) (num+VECTOR_BASE) 41 | 42 | #define DECLARE_IRQ(num) \ 43 | extern void _irq_##num(void); \ 44 | set_intr_gate(IRQ_TO_VECTOR(num), _irq_##num); 45 | 46 | 47 | void irq_init(void); 48 | void ignore_isr_handler(size_t); 49 | 50 | extern irq_handler_t irq_handler[MAX_IRQ]; 51 | 52 | void handle_irq(size_t); 53 | void end_irq(size_t); 54 | 55 | int register_irq(size_t, irq_handler_t); 56 | 57 | #endif 58 | -------------------------------------------------------------------------------- /src/include/irq_vector.h: -------------------------------------------------------------------------------- 1 | #ifndef __IRQ_H__ 2 | #define __IRQ_H__ 3 | 4 | 5 | 6 | 7 | // 8 | // IRQ numbers and vector numbers of devices 9 | // 10 | 11 | 12 | 13 | 14 | 15 | 16 | // external devices 17 | #define DEVICE_IRQ_BASE 0x0 18 | #define EXTERNAL_TIMER (DEVICE_IRQ_BASE + 0x0) 19 | #define KEYBOARD_IRQ (DEVICE_IRQ_BASE + 0x1) 20 | 21 | 22 | // CPU internal 23 | #define CPU_IRQ_BASE 0x10 24 | #define BSP_TIMER_IRQ (CPU_IRQ_BASE+0x0) 25 | #define LINT0_IRQ (CPU_IRQ_BASE+0x1) 26 | #define LINT1_IRQ (CPU_IRQ_BASE+0x2) 27 | #define SPURIOUS_IRQ (CPU_IRQ_BASE+0x3) 28 | 29 | 30 | #endif 31 | -------------------------------------------------------------------------------- /src/include/keyboard.h: -------------------------------------------------------------------------------- 1 | /******************************************************************** 2 | * DESCRIPTION : 3 | * FILE NAME : keyboard.h 4 | *******************************************************************/ 5 | 6 | #ifndef __KEYBOARD_H__ 7 | #define __KEYBOARD_H__ 8 | 9 | 10 | #include 11 | 12 | 13 | 14 | 15 | 16 | 17 | #define MK_SHIFT (1<<0) 18 | #define MK_CTRL (1<<1) 19 | #define MK_ALT (1<<2) 20 | #define MK_CAPSLOCK (1<<3) 21 | #define MK_SCROLLLOCK (1<<4) 22 | #define MK_NUMLOCK (1<<5) 23 | 24 | 25 | 26 | #define SCAN_NUMLOCK 0x45 27 | #define SCAN_CAPSLOCK 0x1d 28 | #define SCAN_SCROLLLOCK 0x46 29 | //#define SCAN_RIGHTSHIFT 0x36 // prefix 0xe0 30 | #define SCAN_LEFTSHIFT 0x2a 31 | #define SCAN_LEFTALT 0x38 32 | #define SCAN_LEFTCTRL 0x3a 33 | //#define SCAN_RIGHTALT SCAN_LEFTALT // prefix 0xe0 34 | 35 | #define SCAN_ENTER 0x1c 36 | #define SCAN_BACKSPACE 0x0e 37 | #define SCAN_TAB 0x0f 38 | #define SCAN_KOR 0x72 39 | 40 | #define SCAN_ESC 0x1 41 | 42 | #define SCAN_F1 0x3b 43 | #define SCAN_F2 0x3c 44 | #define SCAN_F3 0x3d 45 | #define SCAN_F4 0x3e 46 | #define SCAN_F5 0x3f 47 | #define SCAN_F6 0x40 48 | #define SCAN_F7 0x41 49 | #define SCAN_F8 0x42 50 | #define SCAN_F9 0x43 51 | #define SCAN_F10 0x44 52 | #define SCAN_F11 0x57 53 | #define SCAN_F12 0x58 54 | 55 | // 56 | // Blow are need prefix 0xe0 57 | #define SCAN_INSERT 0x52 58 | #define SCAN_HOME 0x47 59 | #define SCAN_PAGEUP 0x49 60 | #define SCAN_DELETE 0x53 61 | #define SCAN_END 0x4f 62 | #define SCAN_PAGEDOWN 0x51 63 | #define SCAN_UP 0x48 64 | #define SCAN_DOWN 0x50 65 | #define SCAN_LEFT 0x4b 66 | #define SCAN_RIGHT 0x4d 67 | 68 | #define SCAN_DIVIDE 0x35 // prefix 0xe0 69 | #define SCAN_MULTIPLY 0x37 70 | #define SCAN_SUBTRACT 0x4a 71 | #define SCAN_ADD 0x4e 72 | #define SCAN_SMALLENTER 0x1c // prefix 0xe0 73 | #define SCAN_POINT 0x53 74 | #define SCAN_PAD_0 0x52 75 | #define SCAN_PAD_1 0x4f 76 | #define SCAN_PAD_2 0x50 77 | #define SCAN_PAD_3 0x51 78 | #define SCAN_PAD_4 0x4b 79 | #define SCAN_PAD_5 0x4c 80 | #define SCAN_PAD_6 0x4d 81 | #define SCAN_PAD_7 0x47 82 | #define SCAN_PAD_8 0x48 83 | #define SCAN_PAD_9 0xc9 84 | 85 | 86 | 87 | struct key_tag_t { 88 | ssize_t status; 89 | u8 code; 90 | }; 91 | 92 | ssize_t keyboard_init(void); 93 | 94 | void keyboard_isr(size_t); 95 | 96 | #endif 97 | -------------------------------------------------------------------------------- /src/include/list.h: -------------------------------------------------------------------------------- 1 | #ifndef _LINUX_LIST_H 2 | #define _LINUX_LIST_H 3 | 4 | 5 | /* 6 | * These are non-NULL pointers that will result in page faults 7 | * under normal circumstances, used to verify that nobody uses 8 | * non-initialized list entries. 9 | */ 10 | #define LIST_POISON1 ((void *) 0x00100100) 11 | #define LIST_POISON2 ((void *) 0x00200200) 12 | 13 | 14 | /* 15 | * Simple doubly linked list implementation. 16 | * 17 | * Some of the internal functions ("__xxx") are useful when 18 | * manipulating whole lists rather than single entries, as 19 | * sometimes we already know the next/prev entries and we can 20 | * generate better code by using them directly rather than 21 | * using the generic single-entry routines. 22 | */ 23 | 24 | struct list_head { 25 | struct list_head *next, *prev; 26 | }; 27 | 28 | #define LIST_HEAD_INIT(name) { &(name), &(name) } 29 | 30 | #define LIST_HEAD(name) \ 31 | struct list_head name = LIST_HEAD_INIT(name) 32 | 33 | static inline void INIT_LIST_HEAD(struct list_head *list) 34 | { 35 | list->next = list; 36 | list->prev = list; 37 | } 38 | 39 | /* 40 | * Insert a new entry between two known consecutive entries. 41 | * 42 | * This is only for internal list manipulation where we know 43 | * the prev/next entries already! 44 | */ 45 | static inline void __list_add(struct list_head *new, 46 | struct list_head *prev, 47 | struct list_head *next) 48 | { 49 | next->prev = new; 50 | new->next = next; 51 | new->prev = prev; 52 | prev->next = new; 53 | } 54 | 55 | /** 56 | * list_add - add a new entry 57 | * @new: new entry to be added 58 | * @head: list head to add it after 59 | * 60 | * Insert a new entry after the specified head. 61 | * This is good for implementing stacks. 62 | */ 63 | static inline void list_add(struct list_head *new, struct list_head *head) 64 | { 65 | __list_add(new, head, head->next); 66 | } 67 | 68 | /** 69 | * list_add_tail - add a new entry 70 | * @new: new entry to be added 71 | * @head: list head to add it before 72 | * 73 | * Insert a new entry before the specified head. 74 | * This is useful for implementing queues. 75 | */ 76 | static inline void list_add_tail(struct list_head *new, struct list_head *head) 77 | { 78 | __list_add(new, head->prev, head); 79 | } 80 | 81 | 82 | /* 83 | * Delete a list entry by making the prev/next entries 84 | * point to each other. 85 | * 86 | * This is only for internal list manipulation where we know 87 | * the prev/next entries already! 88 | */ 89 | static inline void __list_del(struct list_head * prev, struct list_head * next) 90 | { 91 | next->prev = prev; 92 | prev->next = next; 93 | } 94 | 95 | /** 96 | * list_del - deletes entry from list. 97 | * @entry: the element to delete from the list. 98 | * Note: list_empty on entry does not return true after this, the entry is 99 | * in an undefined state. 100 | */ 101 | static inline void list_del(struct list_head *entry) 102 | { 103 | __list_del(entry->prev, entry->next); 104 | entry->next = LIST_POISON1; 105 | entry->prev = LIST_POISON2; 106 | } 107 | 108 | 109 | /** 110 | * list_empty - tests whether a list is empty 111 | * @head: the list to test. 112 | */ 113 | static inline int list_empty(const struct list_head *head) 114 | { 115 | return head->next == head; 116 | } 117 | 118 | 119 | #define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER) 120 | 121 | /** 122 | * container_of - cast a member of a structure out to the containing structure 123 | * @ptr: the pointer to the member. 124 | * @type: the type of the container struct this is embedded in. 125 | * @member: the name of the member within the struct. 126 | * 127 | */ 128 | #define container_of(ptr, type, member) ({ \ 129 | const typeof( ((type *)0)->member ) *__mptr = (ptr); \ 130 | (type *)( (char *)__mptr - offsetof(type,member) );}) 131 | 132 | 133 | 134 | 135 | /** 136 | * prefetch does not do anything.. 137 | */ 138 | static inline void prefetch(const void *x) { x=x; /* remove compiler warning */ } 139 | 140 | 141 | /** 142 | * list_entry - get the struct for this entry 143 | * @ptr: the &struct list_head pointer. 144 | * @type: the type of the struct this is embedded in. 145 | * @member: the name of the list_struct within the struct. 146 | */ 147 | #define list_entry(ptr, type, member) \ 148 | container_of(ptr, type, member) 149 | 150 | /** 151 | * list_for_each - iterate over a list 152 | * @pos: the &struct list_head to use as a loop counter. 153 | * @head: the head for your list. 154 | */ 155 | #define list_for_each(pos, head) \ 156 | for (pos = (head)->next; prefetch(pos->next), pos != (head); \ 157 | pos = pos->next) 158 | 159 | /** 160 | * __list_for_each - iterate over a list 161 | * @pos: the &struct list_head to use as a loop counter. 162 | * @head: the head for your list. 163 | * 164 | * This variant differs from list_for_each() in that it's the 165 | * simplest possible list iteration code, no prefetching is done. 166 | * Use this for code that knows the list to be very short (empty 167 | * or 1 entry) most of the time. 168 | */ 169 | #define __list_for_each(pos, head) \ 170 | for (pos = (head)->next; pos != (head); pos = pos->next) 171 | 172 | 173 | /** 174 | * list_for_each_entry - iterate over list of given type 175 | * @pos: the type * to use as a loop counter. 176 | * @head: the head for your list. 177 | * @member: the name of the list_struct within the struct. 178 | */ 179 | #define list_for_each_entry(pos, head, member) \ 180 | for (pos = list_entry((head)->next, typeof(*pos), member); \ 181 | prefetch(pos->member.next), &pos->member != (head); \ 182 | pos = list_entry(pos->member.next, typeof(*pos), member)) 183 | 184 | 185 | 186 | #endif 187 | -------------------------------------------------------------------------------- /src/include/memory.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef __MEMORY_H__ 3 | #define __MEMORY_H__ 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | 11 | // 12 | // zoned buddy allocator. 13 | // Maximum order of page number to be a buddy. 14 | // 15 | #define MAX_ORDER 5 16 | 17 | 18 | // 19 | // I have only one node. 20 | // 21 | enum zone_type { 22 | ZONE_NORMAL, // 0 23 | MAX_NR_ZONES // 1 24 | }; 25 | 26 | 27 | 28 | 29 | 30 | // 31 | // memory-zone structure 32 | // 33 | // zone is contiguos page-sequence, 34 | // that page-allocation search free pages in each zone at a time. 35 | // Only page in the same zone can be allocated, not across zones. 36 | // 37 | struct zone { 38 | // number of free pages in zone 39 | size_t free_pages; 40 | // node includes zone 41 | struct pglist_data *zone_pgdat; 42 | // physical memory address 43 | u64 zone_start_paddr; 44 | // zone name 45 | char *name; 46 | // memory size (in byte) 47 | size_t size; 48 | // number of total pages 49 | size_t pages; 50 | 51 | // first mem_map entry belongs to zone 52 | struct page *zone_mem_map; 53 | // first page-frame number belongs to zone 54 | size_t zone_start_pfn; 55 | 56 | }; 57 | 58 | 59 | 60 | // system-node structure 61 | typedef struct pglist_data { 62 | // zone 63 | struct zone node_zones[MAX_NR_ZONES]; 64 | // number of zones 65 | size_t nr_zones; 66 | // pointer to mem_map of this node 67 | struct page *node_mem_map; 68 | // physical memory address 69 | u64 node_start_paddr; 70 | // memory size 71 | size_t node_size; 72 | // node index 73 | size_t node_id; 74 | // pointer to next node 75 | struct pglist_data *node_next; 76 | } pg_data_t; 77 | 78 | 79 | 80 | 81 | void memory_init(size_t); 82 | 83 | 84 | extern pg_data_t contig_page_data; 85 | 86 | 87 | #endif 88 | -------------------------------------------------------------------------------- /src/include/mp_spec.h: -------------------------------------------------------------------------------- 1 | #ifndef __MPCORE_H__ 2 | #define __MPCORE_H__ 3 | 4 | #include 5 | #include 6 | 7 | 8 | // 9 | // 10 | // copy of linux/include/asm-x86_64/mpspec.h 11 | // 12 | 13 | /* 14 | * Structure definitions for SMP machines following the 15 | * Intel Multiprocessing Specification 1.1 and 1.4. 16 | */ 17 | 18 | /* 19 | * This tag identifies where the SMP configuration 20 | * information is. 21 | */ 22 | 23 | #define SMP_MAGIC_IDENT (('_'<<24)|('P'<<16)|('M'<<8)|'_') 24 | 25 | /* 26 | * A maximum of 255 APICs with the current APIC ID architecture, 27 | * but Caos supports only 2 APICs. 28 | */ 29 | #define MAX_APICS 2 /* 255 */ 30 | 31 | #define MAX_IO_APICS 2 /* 128 */ 32 | 33 | 34 | struct intel_mp_floating 35 | { 36 | char mpf_signature[4]; /* "_MP_" */ 37 | unsigned int mpf_physptr; /* Configuration table address */ 38 | unsigned char mpf_length; /* Our length (paragraphs) */ 39 | unsigned char mpf_specification;/* Specification version */ 40 | unsigned char mpf_checksum; /* Checksum (makes sum 0) */ 41 | unsigned char mpf_feature1; /* Standard or configuration ? */ 42 | unsigned char mpf_feature2; /* Bit7 set for IMCR|PIC */ 43 | unsigned char mpf_feature3; /* Unused (0) */ 44 | unsigned char mpf_feature4; /* Unused (0) */ 45 | unsigned char mpf_feature5; /* Unused (0) */ 46 | } __attribute__ ((packed)); 47 | 48 | struct mp_config_table 49 | { 50 | char mpc_signature[4]; // string "PCMP" 51 | #define MPC_SIGNATURE "PCMP" 52 | unsigned short mpc_length; /* Size of table */ 53 | char mpc_spec; /* 0x01 or 0x04 */ 54 | char mpc_checksum; // checksum of the table 55 | char mpc_oem[8]; // OEM ID: system hardware manufacturer 56 | char mpc_productid[12]; // Product familly ID 57 | unsigned int mpc_oemptr; /* 0 if not present, optional */ 58 | unsigned short mpc_oemsize; /* 0 if not present, optional */ 59 | unsigned short mpc_oemcount; // entry count 60 | unsigned int mpc_lapic; /* Local APIC address */ 61 | unsigned int reserved; 62 | } __attribute__ ((packed)); 63 | 64 | /* Followed by entries */ 65 | 66 | #define MP_PROCESSOR 0 67 | #define MP_BUS 1 68 | #define MP_IOAPIC 2 69 | #define MP_INTSRC 3 70 | #define MP_LINTSRC 4 71 | 72 | struct mpc_config_processor 73 | { 74 | unsigned char mpc_type; // A value of 0 identifies a processor entry 75 | unsigned char mpc_apicid; /* Local APIC ID number */ 76 | unsigned char mpc_apicver; /* Local APIC's versions */ 77 | unsigned char mpc_cpuflag; 78 | #define CPU_ENABLED 1 /* Processor is available */ 79 | #define CPU_BOOTPROCESSOR 2 /* Processor is the BP */ 80 | unsigned int mpc_cpufeature; 81 | #define CPU_STEPPING_MASK 0x0F 82 | #define CPU_MODEL_MASK 0xF0 83 | #define CPU_FAMILY_MASK 0xF00 84 | unsigned int mpc_featureflag; /* CPUID feature value */ 85 | unsigned int mpc_reserved[2]; 86 | } __attribute__ ((packed)); 87 | 88 | struct mpc_config_bus 89 | { 90 | unsigned char mpc_type; 91 | unsigned char mpc_busid; 92 | unsigned char mpc_bustype[6]; 93 | } __attribute__ ((packed)); 94 | 95 | /* List of Bus Type string values, Intel MP Spec. */ 96 | #define BUSTYPE_EISA "EISA" 97 | #define BUSTYPE_ISA "ISA" 98 | #define BUSTYPE_INTERN "INTERN" /* Internal BUS */ 99 | #define BUSTYPE_MCA "MCA" 100 | #define BUSTYPE_VL "VL" /* Local bus */ 101 | #define BUSTYPE_PCI "PCI" 102 | #define BUSTYPE_PCMCIA "PCMCIA" 103 | #define BUSTYPE_CBUS "CBUS" 104 | #define BUSTYPE_CBUSII "CBUSII" 105 | #define BUSTYPE_FUTURE "FUTURE" 106 | #define BUSTYPE_MBI "MBI" 107 | #define BUSTYPE_MBII "MBII" 108 | #define BUSTYPE_MPI "MPI" 109 | #define BUSTYPE_MPSA "MPSA" 110 | #define BUSTYPE_NUBUS "NUBUS" 111 | #define BUSTYPE_TC "TC" 112 | #define BUSTYPE_VME "VME" 113 | #define BUSTYPE_XPRESS "XPRESS" 114 | 115 | struct mpc_config_ioapic 116 | { 117 | unsigned char mpc_type; // must be 2 118 | unsigned char mpc_apicid; // ID if this IO APIC 119 | unsigned char mpc_apicver; // version 120 | unsigned char mpc_flags; // usable flag 121 | #define MPC_APIC_USABLE 0x01 122 | unsigned int mpc_apicaddr; // base address of this IO APIC 123 | } __attribute__ ((packed)); 124 | 125 | struct mpc_config_intsrc 126 | { 127 | unsigned char mpc_type; // must be 3 128 | unsigned char mpc_irqtype; // interrupt type value 129 | unsigned short mpc_irqflag; // int polarity and trigger mode 130 | /* bits[1:0]: polarity 131 | * 00 = conforms to specifications of bus 132 | * 01 = active high 133 | * 10 = reserved 134 | * 11 = active low 135 | * bits[3:2]: trigger mode 136 | * 00 = conforms to specifications of bus 137 | * 01 = edge 138 | * 10 = reserved 139 | * 11 = level 140 | */ 141 | unsigned char mpc_srcbus; // bus id which the int comes from 142 | unsigned char mpc_srcbusirq; // vector onto source bus signals 143 | unsigned char mpc_dstapic; // IO APIC id the signal connected 144 | unsigned char mpc_dstirq; // INTINn pin of IO APIC the signal connected 145 | } __attribute__ ((packed)); 146 | 147 | enum mp_irq_source_types { 148 | mp_INT = 0,// vectored interrupt, vector is supplied by IO APIC 149 | mp_NMI = 1,// nonmaskable int 150 | mp_SMI = 2,// system management int 151 | mp_ExtINT = 3// vectored int, vector is supplied by externam PIC 152 | }; 153 | 154 | #define MP_IRQDIR_DEFAULT 0 155 | #define MP_IRQDIR_HIGH 1 156 | #define MP_IRQDIR_LOW 3 157 | 158 | 159 | struct mpc_config_lintsrc 160 | { 161 | unsigned char mpc_type; // entry type 4 162 | unsigned char mpc_irqtype; // same value with IO interrupt entry 163 | unsigned short mpc_irqflag; // same with IO interrupt entry 164 | unsigned char mpc_srcbusid; // bus ID the interrupt came from 165 | unsigned char mpc_srcbusirq; // vector from the bus 166 | unsigned char mpc_destapic; // Local APIC ID the signal connected 167 | #define MP_APIC_ALL 0xFF 168 | unsigned char mpc_destapiclint; // LINTINn pin the signal connected 169 | } __attribute__ ((packed)); 170 | 171 | /* 172 | * Default configurations 173 | * 174 | * 1 2 CPU ISA 82489DX 175 | * 2 2 CPU EISA 82489DX neither IRQ 0 timer nor IRQ 13 DMA chaining 176 | * 3 2 CPU EISA 82489DX 177 | * 4 2 CPU MCA 82489DX 178 | * 5 2 CPU ISA+PCI 179 | * 6 2 CPU EISA+PCI 180 | * 7 2 CPU MCA+PCI 181 | */ 182 | 183 | #define MAX_MP_BUSSES 256 184 | 185 | #define MAX_IRQ_SOURCES (MAX_MP_BUSSES*4) 186 | 187 | 188 | 189 | void mp_spec_init(void); 190 | 191 | 192 | extern ssize_t smp_found_config; // MP configuration is found? 193 | extern u64 mp_lapic_addr; // address of Local APIC of BSP 194 | extern size_t disabled_cpus; // 195 | extern size_t boot_cpu_id; // BSP index 196 | extern size_t num_processors; // processor count 197 | extern size_t mp_current_pci_id; // pci bus index 198 | extern size_t nr_ioapics; // IO APIC count 199 | extern size_t mp_irq_entries; 200 | 201 | // 202 | // bitmap for system configuration 203 | // 204 | extern u64 cpu_present_map; // each bit indicates a processor present 205 | extern DECLARE_BITMAP(mp_bus_not_pci, MAX_MP_BUSSES); 206 | // ID tables 207 | extern struct intel_mp_floating *mpf_found; // address of MP floating pointer 208 | // APIC ID of each logical processor 209 | extern u8 bios_cpu_apicid[NR_CPUS]; 210 | // IO APIC entry of MP configuration table 211 | extern struct mpc_config_ioapic mp_ioapics[MAX_IO_APICS]; 212 | extern struct mpc_config_intsrc mp_irqs[MAX_IRQ_SOURCES]; 213 | extern size_t mp_bus_id_to_pci_bus[MAX_MP_BUSSES]; 214 | 215 | 216 | #endif 217 | -------------------------------------------------------------------------------- /src/include/msr.h: -------------------------------------------------------------------------------- 1 | 2 | 3 | #ifndef __MSR_H__ 4 | #define __MSR_H__ 1 5 | 6 | 7 | 8 | static inline void cpuid(int op, unsigned int *eax, unsigned int *ebx, 9 | unsigned int *ecx, unsigned int *edx) 10 | { 11 | 12 | __asm__("cpuid" 13 | : "=a" (*eax), "=b" (*ebx), "=c" (*ecx), "=d" (*edx) 14 | : "0" (op) 15 | ); 16 | 17 | } 18 | 19 | 20 | 21 | 22 | #endif 23 | 24 | -------------------------------------------------------------------------------- /src/include/oops.h: -------------------------------------------------------------------------------- 1 | #include "inline_asm.h" 2 | 3 | 4 | void oops(unsigned int data); 5 | -------------------------------------------------------------------------------- /src/include/page-flags.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Macros for manipulating and testing page->flags 3 | * copy of linux/include/linux/page-flags.h 4 | */ 5 | 6 | #ifndef __PAGE_FLAGS_H__ 7 | #define __PAGE_FLAGS_H__ 8 | 9 | #include 10 | //#include 11 | 12 | /* 13 | * Various page->flags bits: 14 | * 15 | * PG_reserved is set for special pages, which can never be swapped out. Some 16 | * of them might not even exist (eg empty_bad_page)... 17 | * 18 | * The PG_private bitflag is set on pagecache pages if they contain filesystem 19 | * specific data (which is normally at page->private). It can be used by 20 | * private allocations for its own usage. 21 | * 22 | * During initiation of disk I/O, PG_locked is set. This bit is set before I/O 23 | * and cleared when writeback _starts_ or when read _completes_. PG_writeback 24 | * is set before writeback starts and cleared when it finishes. 25 | * 26 | * PG_locked also pins a page in pagecache, and blocks truncation of the file 27 | * while it is held. 28 | * 29 | * page_waitqueue(page) is a wait queue of all tasks waiting for the page 30 | * to become unlocked. 31 | * 32 | * PG_uptodate tells whether the page's contents is valid. When a read 33 | * completes, the page becomes uptodate, unless a disk I/O error happened. 34 | * 35 | * PG_referenced, PG_reclaim are used for page reclaim for anonymous and 36 | * file-backed pagecache (see mm/vmscan.c). 37 | * 38 | * PG_error is set to indicate that an I/O error occurred on this page. 39 | * 40 | * PG_arch_1 is an architecture specific page state bit. The generic code 41 | * guarantees that this bit is cleared for a page when it first is entered into 42 | * the page cache. 43 | * 44 | * PG_highmem pages are not permanently mapped into the kernel virtual address 45 | * space, they need to be kmapped separately for doing IO on the pages. The 46 | * struct page (these bits with information) are always mapped into kernel 47 | * address space... 48 | * 49 | * PG_buddy is set to indicate that the page is free and in the buddy system 50 | * (see mm/page_alloc.c). 51 | * 52 | */ 53 | 54 | /* 55 | * Don't use the *_dontuse flags. Use the macros. Otherwise you'll break 56 | * locked- and dirty-page accounting. 57 | * 58 | * The page flags field is split into two parts, the main flags area 59 | * which extends from the low bits upwards, and the fields area which 60 | * extends from the high bits downwards. 61 | * 62 | * | FIELD | ... | FLAGS | 63 | * N-1 ^ 0 64 | * (N-FLAGS_RESERVED) 65 | * 66 | * The fields area is reserved for fields mapping zone, node and SPARSEMEM 67 | * section. The boundry between these two areas is defined by 68 | * FLAGS_RESERVED which defines the width of the fields section 69 | * (see linux/mmzone.h). New flags must _not_ overlap with this area. 70 | */ 71 | #define PG_locked 0 /* Page is locked. Don't touch. */ 72 | #define PG_error 1 73 | #define PG_referenced 2 74 | #define PG_uptodate 3 75 | 76 | #define PG_dirty 4 77 | #define PG_lru 5 78 | #define PG_active 6 /* Page is busy */ 79 | #define PG_slab 7 /* slab debug (Suparna wants this) */ 80 | 81 | #define PG_owner_priv_1 8 /* Owner use. If pagecache, fs may use*/ 82 | #define PG_arch_1 9 83 | #define PG_reserved 10 84 | #define PG_private 11 /* If pagecache, has fs-private data */ 85 | 86 | #define PG_writeback 12 /* Page is under writeback */ 87 | #define PG_compound 14 /* Part of a compound page */ 88 | #define PG_swapcache 15 /* Swap page: swp_entry_t in private */ 89 | 90 | #define PG_mappedtodisk 16 /* Has blocks allocated on-disk */ 91 | #define PG_reclaim 17 /* To be reclaimed asap */ 92 | #define PG_buddy 19 /* Page is free, on buddy lists */ 93 | 94 | /* PG_readahead is only used for file reads; PG_reclaim is only for writes */ 95 | #define PG_readahead PG_reclaim /* Reminder to do async read-ahead */ 96 | 97 | /* PG_owner_priv_1 users should have descriptive aliases */ 98 | #define PG_checked PG_owner_priv_1 /* Used by some filesystems */ 99 | #define PG_pinned PG_owner_priv_1 /* Xen pinned pagetable */ 100 | 101 | #if (BITS_PER_LONG > 32) 102 | /* 103 | * 64-bit-only flags build down from bit 31 104 | * 105 | * 32 bit -------------------------------| FIELDS | FLAGS | 106 | * 64 bit | FIELDS | ?????? FLAGS | 107 | * 63 32 0 108 | */ 109 | #define PG_uncached 31 /* Page has been mapped as uncached */ 110 | #endif 111 | 112 | /* 113 | * Manipulation of page state flags 114 | */ 115 | #define PageLocked(page) \ 116 | test_bit(PG_locked, &(page)->flags) 117 | #define SetPageLocked(page) \ 118 | set_bit(PG_locked, &(page)->flags) 119 | #define TestSetPageLocked(page) \ 120 | test_and_set_bit(PG_locked, &(page)->flags) 121 | #define ClearPageLocked(page) \ 122 | clear_bit(PG_locked, &(page)->flags) 123 | #define TestClearPageLocked(page) \ 124 | test_and_clear_bit(PG_locked, &(page)->flags) 125 | 126 | #define PageError(page) test_bit(PG_error, &(page)->flags) 127 | #define SetPageError(page) set_bit(PG_error, &(page)->flags) 128 | #define ClearPageError(page) clear_bit(PG_error, &(page)->flags) 129 | 130 | #define PageReferenced(page) test_bit(PG_referenced, &(page)->flags) 131 | #define SetPageReferenced(page) set_bit(PG_referenced, &(page)->flags) 132 | #define ClearPageReferenced(page) clear_bit(PG_referenced, &(page)->flags) 133 | #define TestClearPageReferenced(page) test_and_clear_bit(PG_referenced, &(page)->flags) 134 | 135 | #define PageUptodate(page) test_bit(PG_uptodate, &(page)->flags) 136 | #ifdef CONFIG_S390 137 | static inline void SetPageUptodate(struct page *page) 138 | { 139 | if (!test_and_set_bit(PG_uptodate, &page->flags)) 140 | page_clear_dirty(page); 141 | } 142 | #else 143 | #define SetPageUptodate(page) set_bit(PG_uptodate, &(page)->flags) 144 | #endif 145 | #define ClearPageUptodate(page) clear_bit(PG_uptodate, &(page)->flags) 146 | 147 | #define PageDirty(page) test_bit(PG_dirty, &(page)->flags) 148 | #define SetPageDirty(page) set_bit(PG_dirty, &(page)->flags) 149 | #define TestSetPageDirty(page) test_and_set_bit(PG_dirty, &(page)->flags) 150 | #define ClearPageDirty(page) clear_bit(PG_dirty, &(page)->flags) 151 | //#define __ClearPageDirty(page) __clear_bit(PG_dirty, &(page)->flags) 152 | #define TestClearPageDirty(page) test_and_clear_bit(PG_dirty, &(page)->flags) 153 | 154 | #define PageLRU(page) test_bit(PG_lru, &(page)->flags) 155 | #define SetPageLRU(page) set_bit(PG_lru, &(page)->flags) 156 | #define ClearPageLRU(page) clear_bit(PG_lru, &(page)->flags) 157 | //#define __ClearPageLRU(page) __clear_bit(PG_lru, &(page)->flags) 158 | 159 | #define PageActive(page) test_bit(PG_active, &(page)->flags) 160 | #define SetPageActive(page) set_bit(PG_active, &(page)->flags) 161 | #define ClearPageActive(page) clear_bit(PG_active, &(page)->flags) 162 | //#define __ClearPageActive(page) __clear_bit(PG_active, &(page)->flags) 163 | 164 | #define PageSlab(page) test_bit(PG_slab, &(page)->flags) 165 | #define SetPageSlab(page) set_bit(PG_slab, &(page)->flags) 166 | #define ClearPageSlab(page) clear_bit(PG_slab, &(page)->flags) 167 | 168 | #ifdef CONFIG_HIGHMEM 169 | #define PageHighMem(page) is_highmem(page_zone(page)) 170 | #else 171 | #define PageHighMem(page) 0 /* needed to optimize away at compile time */ 172 | #endif 173 | 174 | #define PageChecked(page) test_bit(PG_checked, &(page)->flags) 175 | #define SetPageChecked(page) set_bit(PG_checked, &(page)->flags) 176 | #define ClearPageChecked(page) clear_bit(PG_checked, &(page)->flags) 177 | 178 | #define PagePinned(page) test_bit(PG_pinned, &(page)->flags) 179 | #define SetPagePinned(page) set_bit(PG_pinned, &(page)->flags) 180 | #define ClearPagePinned(page) clear_bit(PG_pinned, &(page)->flags) 181 | 182 | #define PageReserved(page) test_bit(PG_reserved, &(page)->flags) 183 | #define SetPageReserved(page) set_bit(PG_reserved, &(page)->flags) 184 | #define ClearPageReserved(page) clear_bit(PG_reserved, &(page)->flags) 185 | //#define __ClearPageReserved(page) __clear_bit(PG_reserved, &(page)->flags) 186 | 187 | #define SetPagePrivate(page) set_bit(PG_private, &(page)->flags) 188 | #define ClearPagePrivate(page) clear_bit(PG_private, &(page)->flags) 189 | #define PagePrivate(page) test_bit(PG_private, &(page)->flags) 190 | //#define __SetPagePrivate(page) __set_bit(PG_private, &(page)->flags) 191 | //#define __ClearPagePrivate(page) __clear_bit(PG_private, &(page)->flags) 192 | 193 | /* 194 | * Only test-and-set exist for PG_writeback. The unconditional operators are 195 | * risky: they bypass page accounting. 196 | */ 197 | #define PageWriteback(page) test_bit(PG_writeback, &(page)->flags) 198 | #define TestSetPageWriteback(page) test_and_set_bit(PG_writeback, \ 199 | &(page)->flags) 200 | #define TestClearPageWriteback(page) test_and_clear_bit(PG_writeback, \ 201 | &(page)->flags) 202 | 203 | #define PageBuddy(page) test_bit(PG_buddy, &(page)->flags) 204 | #define SetPageBuddy(page) set_bit(PG_buddy, &(page)->flags) 205 | #define ClearPageBuddy(page) clear_bit(PG_buddy, &(page)->flags) 206 | 207 | #define PageMappedToDisk(page) test_bit(PG_mappedtodisk, &(page)->flags) 208 | #define SetPageMappedToDisk(page) set_bit(PG_mappedtodisk, &(page)->flags) 209 | #define ClearPageMappedToDisk(page) clear_bit(PG_mappedtodisk, &(page)->flags) 210 | 211 | #define PageReadahead(page) test_bit(PG_readahead, &(page)->flags) 212 | #define SetPageReadahead(page) set_bit(PG_readahead, &(page)->flags) 213 | #define ClearPageReadahead(page) clear_bit(PG_readahead, &(page)->flags) 214 | 215 | #define PageReclaim(page) test_bit(PG_reclaim, &(page)->flags) 216 | #define SetPageReclaim(page) set_bit(PG_reclaim, &(page)->flags) 217 | #define ClearPageReclaim(page) clear_bit(PG_reclaim, &(page)->flags) 218 | #define TestClearPageReclaim(page) test_and_clear_bit(PG_reclaim, &(page)->flags) 219 | 220 | #define PageCompound(page) test_bit(PG_compound, &(page)->flags) 221 | #define SetPageCompound(page) set_bit(PG_compound, &(page)->flags) 222 | #define ClearPageCompound(page) clear_bit(PG_compound, &(page)->flags) 223 | 224 | 225 | 226 | #endif /* PAGE_FLAGS_H */ 227 | -------------------------------------------------------------------------------- /src/include/page.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef __PAGE_H__ 3 | #define __PAGE_H__ 4 | 5 | 6 | #include 7 | #include 8 | #include 9 | 10 | #include 11 | #include 12 | 13 | 14 | 15 | 16 | /* mem_mep_t presents a page frame */ 17 | struct page { 18 | struct list_head list; // free page-list in the same zone 19 | size_t private; // for buddy system, order of buddy-pages 20 | size_t index; // page number 21 | size_t count; // reference counter 22 | flag_t flags; // status flag 23 | void * virtual; // virtual address the page is mapped 24 | 25 | struct zone *page_zone; // including zone 26 | 27 | void *slab; // including slab 28 | }; 29 | 30 | 31 | extern struct page *mem_map; 32 | 33 | void bootmem_init(void); 34 | void *alloc_bootmem(size_t); 35 | 36 | void paging_init(size_t); 37 | void mem_map_init(void); 38 | 39 | struct page *virt_to_page(u64 vaddr); 40 | u64 page_to_virt(struct page *); 41 | 42 | 43 | 44 | 45 | #endif 46 | -------------------------------------------------------------------------------- /src/include/page_alloc.h: -------------------------------------------------------------------------------- 1 | #ifndef __PAGE_ALLOC_H__ 2 | #define __PAGE_ALLOC_H__ 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | 9 | #define MAX_PAGE_ORDER 0x5 10 | 11 | 12 | 13 | // convert page-count to page-order 14 | #define PAGE_ORDER(x) fls64(x) 15 | 16 | 17 | struct page *alloc_pages(flag_t gfp_mask, size_t order); 18 | struct page *__alloc_pages(flag_t, size_t, struct zone *); 19 | unsigned long get_free_pages(flag_t gfp_mask, size_t order); 20 | 21 | void free_pages(u64 addr, size_t order); 22 | void __free_pages(struct page *, size_t order); 23 | 24 | 25 | 26 | 27 | 28 | 29 | #endif 30 | -------------------------------------------------------------------------------- /src/include/percpu.h: -------------------------------------------------------------------------------- 1 | #ifndef __PERCPU_H__ 2 | #define __PERCPU_H__ 3 | 4 | 5 | 6 | 7 | #define DEFINE_PER_CPU(type, name) \ 8 | __attribute__((__section__(".data.percpu"))) __typeof__(type) per_cpu__##name 9 | 10 | 11 | 12 | 13 | void setup_per_cpu_areas(void); 14 | 15 | 16 | #endif 17 | -------------------------------------------------------------------------------- /src/include/pgtable.h: -------------------------------------------------------------------------------- 1 | #ifndef __PGTABLE_H__ 2 | #define __PGTABLE_H__ 3 | 4 | /* 5 | * pgtable.h 6 | * 7 | * Here are macros and constant values for page table processing 8 | * 9 | * Everything here is almost same with the linux kernel include/asm_x86-64/pgtable.h 10 | * and comment is copied from Understanding Linux Kernel book. 11 | * 12 | * - 2008.11.24 gurugio 13 | * 14 | */ 15 | 16 | 17 | /* 18 | * linear address of kernel area 19 | * 20 | * Physical memory 0~8MB is mapped to 0xFFFF800000000000UL 21 | */ 22 | #define PAGE_OFFSET (0xFFFF800000000000UL) 23 | 24 | 25 | //#define KERNEL_TEXT_START (0xFFFF800000100000UL) 26 | //#define KERNEL_STACK_START (0xFFFF800000200000UL) 27 | 28 | #define KERNEL_TEXT_START KERNEL_VIRTUAL_ADDR 29 | #define KERNEL_STACK_START KERNEL_STACK_ADDR 30 | 31 | 32 | #define BSP_STACK_START KERNEL_STACK_START 33 | #define AP_STACK_START (0xFFFF80000010E000UL) // 2 pages are for BSP stack 34 | 35 | 36 | // 37 | // The first implementation fo Intel 64 support 48bit linear address 38 | // and 40bit physical address 39 | // 40 | #define __PHYSICAL_MASK_SHIFT 40 41 | #define __VIRTUAL_MASK_SHIFT 48 42 | #define __PHYSICAL_MASK ((1UL<<__PHYSICAL_MASK_SHIFT)-1) 43 | #define __VIRTUAL_MASK ((1UL<<__VIRTUAL_MASK_SHIFT)-1) 44 | 45 | 46 | /* 47 | * bit field of page table entry 48 | */ 49 | #define _PAGE_BIT_PRESENT 0 50 | #define _PAGE_BIT_RW 1 51 | #define _PAGE_BIT_USER 2 52 | #define _PAGE_BIT_PWT 3 53 | #define _PAGE_BIT_PCD 4 54 | #define _PAGE_BIT_ACCESSED 5 55 | #define _PAGE_BIT_DIRTY 6 // only for page-table entry 56 | #define _PAGE_BIT_PSE 7 57 | #define _PAGE_BIT_GLOBAL 8 58 | 59 | 60 | #define _PAGE_PRESENT 0x001 61 | #define _PAGE_RW 0x002 62 | #define _PAGE_USER 0x004 63 | #define _PAGE_PWT 0x008 64 | #define _PAGE_PCD 0x010 65 | #define _PAGE_ACCESSED 0x020 66 | #define _PAGE_DIRTY 0x040 67 | #define _PAGE_PSE 0x080 68 | #define _PAGE_GLOBAL 0x100 69 | 70 | 71 | 72 | 73 | // 74 | // Physical address <-> Virtual address 75 | // 76 | #define __pa(x) ((unsigned long long)(x)-PAGE_OFFSET) 77 | #define __va(x) ((void *)((unsigned long long)(x)+PAGE_OFFSET)) 78 | 79 | 80 | 81 | 82 | /* entry format of page-table */ 83 | // In x86-64 arch, entry of every paging structure is 64bit 84 | typedef struct { unsigned long long pte; } pte_t; 85 | typedef struct { unsigned long long pmd; } pmd_t; 86 | typedef struct { unsigned long long pud; } pud_t; 87 | typedef struct { unsigned long long pgd; } pgd_t; 88 | typedef struct { unsigned long long pgprot; } pgprot_t; 89 | 90 | 91 | 92 | // 93 | // access page DIR/Table entry, cast specialized type into an unsigned integer 94 | // 95 | #define pte_val(x) ((x).pte) 96 | #define pmd_val(x) ((x).pmd) 97 | #define pud_val(x) ((x).pud) 98 | #define pgd_val(x) ((x).pgd) 99 | #define pgprot_val(x) ((x).pgprot) 100 | 101 | 102 | // 103 | // cast an unsigned integer into the required type 104 | // 105 | #define __pte(x) ((pte_t) { (x) } ) 106 | #define __pmd(x) ((pmd_t) { (x) } ) 107 | #define __pud(x) ((pud_t) { (x) } ) 108 | #define __pgd(x) ((pgd_t) { (x) } ) 109 | #define __pgprot(x) ((pgprot_t) { (x) } ) 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | /* 118 | * macros for page table handling 119 | * 120 | */ 121 | 122 | 123 | // the address of page-descriptor of page-frame number pfn. 124 | #define __pfn_to_page(pfn) (mem_map + (pfn)) 125 | 126 | // the number of physical page-frame of page-descriptor 'page'. 127 | #define __page_to_pfn(page) ((unsigned long)((page) - mem_map)) 128 | 129 | 130 | 131 | /* 132 | * PGD (Page Global DIR) is PML4 table of x86-64 133 | * Level 4 access. 134 | */ 135 | #define PGDIR_SHIFT 39 // length in bits of the PGDIR field, linear address [47:39] 136 | #define PGD_SIZE (1UL<> PAGE_SHIFT)) 147 | 148 | // index of the entry of PGD that map the linear address 'address' 149 | #define pgd_index(address) (((address) >> PGDIR_SHIFT) & (PTRS_PER_PGD-1)) 150 | 151 | // Receives as parameters of the address of a memory descriptor mm, 152 | // and a linear address addr. 153 | // This macro yields the linear address of the entry in PGD 154 | // that corresponds to the address addr. 155 | #define pgd_offset(mm, addr) ((mm)->pgd + pgd_index(addr)) 156 | #define pgd_present(pgd) (pgd_val(pgd) & _PAGE_PRESENT) 157 | 158 | static inline void set_pgd(pgd_t *dst, pgd_t val) 159 | { 160 | pgd_val(*dst) = pgd_val(val); 161 | } 162 | 163 | static inline void pgd_clear (pgd_t * pgd) 164 | { 165 | set_pgd(pgd, __pgd(0)); 166 | } 167 | 168 | 169 | 170 | 171 | 172 | /* 173 | * PUD (Page Upper DIR) is page-directory-pointer table of x86-64 174 | * PUD - Level3 access 175 | */ 176 | #define PUD_SHIFT 30 // linear address [38:30] 177 | #define PUD_SIZE (1UL<> PAGE_SHIFT)) 185 | 186 | // index of entry in PUD to the address 187 | #define pud_index(address) (((address) >> PUD_SHIFT) & (PTRS_PER_PUD-1)) 188 | 189 | // Yield the inear address of the entry in a PUD that corresponds to pgd, addr. 190 | // pgd: PGD entry corresponds to the pud_offset 191 | // address: linear address of somewhere in memory 192 | #define pud_offset(pgd, address) ((pud_t *) pgd_page_vaddr(*(pgd)) + pud_index(address)) 193 | #define pud_present(pud) (pud_val(pud) & _PAGE_PRESENT) 194 | #define pud_none(x) (!pud_val(x)) 195 | 196 | static inline void set_pud(pud_t *dst, pud_t val) 197 | { 198 | pud_val(*dst) = pud_val(val); 199 | } 200 | 201 | static inline void pud_clear (pud_t *pud) 202 | { 203 | set_pud(pud, __pud(0)); 204 | } 205 | 206 | 207 | 208 | /* 209 | * PMD (Page Middle DIR) is page-directory table of x86-64 210 | * PMD - Level 2 access 211 | */ 212 | #define PMD_SHIFT 21 // linear address [29:21] 213 | #define PMD_SIZE (1UL<> PAGE_SHIFT)) 218 | 219 | // index of PMD entry 220 | #define pmd_index(address) (((address) >> PMD_SHIFT) & (PTRS_PER_PMD-1)) 221 | 222 | // linear address of the PMD entry that maps address 223 | #define pmd_offset(dir, address) ((pmd_t *) pud_page_vaddr(*(dir)) + \ 224 | pmd_index(address)) 225 | #define pmd_none(x) (!pmd_val(x)) 226 | #define pmd_present(x) (pmd_val(x) & _PAGE_PRESENT) 227 | #define pmd_clear(xp) do { set_pmd(xp, __pmd(0)); } while (0) 228 | #define pfn_pmd(nr,prot) (__pmd(((nr) << PAGE_SHIFT) | pgprot_val(prot))) 229 | #define pmd_pfn(x) ((pmd_val(x) & __PHYSICAL_MASK) >> PAGE_SHIFT) 230 | 231 | 232 | static inline void set_pmd(pmd_t *dst, pmd_t val) 233 | { 234 | pmd_val(*dst) = pmd_val(val); 235 | } 236 | 237 | 238 | 239 | /* 240 | * PTE (page Table) is page-table of x86-64 241 | * PTE - Level 1 access. 242 | */ 243 | #define PTE_SHIFT 12 // linear address [20:12] 244 | #define PTE_SIZE (1UL< pte */ 249 | #define mk_pte(page, pgprot) pfn_pte(page_to_pfn(page), (pgprot)) 250 | #define mk_pte_huge(entry) (pte_val(entry) |= _PAGE_PRESENT | _PAGE_PSE) 251 | 252 | #define pte_present(x) (pte_val(x) & (_PAGE_PRESENT | _PAGE_PROTNONE)) 253 | #define pte_clear(mm,addr,xp) do { set_pte(mm, addr, xp, __pte(0)); } while (0) 254 | 255 | 256 | // page-descriptor for PTE entry x 257 | #define pte_page(x) pfn_to_page(pte_pfn(x)) 258 | // page-frame number of PTE entry x 259 | #define pte_pfn(x) ((pte_val(x) & __PHYSICAL_MASK) >> PAGE_SHIFT) 260 | 261 | #define pte_none(x) (!pte_val(x)) 262 | 263 | #define pte_index(address) \ 264 | (((address) >> PAGE_SHIFT) & (PTRS_PER_PTE - 1)) 265 | 266 | // address of PTE entry that corresponds the address and PMD dir 267 | #define pte_offset_kernel(dir, address) ((pte_t *) \ 268 | pmd_page_vaddr(*(dir)) + pte_index(address)) 269 | 270 | 271 | static inline void set_pte(pte_t *dst, pte_t val) 272 | { 273 | pte_val(*dst) = pte_val(val); 274 | } 275 | 276 | 277 | /* 278 | * PAGE is physical page-frame 279 | * 280 | */ 281 | #define PAGE_SHIFT 12 282 | #define PAGE_SIZE (1UL< 7 | 8 | 9 | void caos_putchar(char); 10 | void caos_delchar(ssize_t cnt); 11 | ssize_t asmlinkage caos_printf(const char *format, ...); 12 | void asmlinkage caos_vsprintf(char *A_szString, const char *A_szFormat, va_list A_pAp); 13 | ssize_t print_decimal(char *A_szBuffer, ssize_t a); 14 | ssize_t print_hex(char *buf, ssize_t a); 15 | 16 | ssize_t asmlinkage caos_sprintf(char *outbuf, const char *format, ...); 17 | 18 | #endif 19 | -------------------------------------------------------------------------------- /src/include/process.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef __PROCESS_H__ 3 | #define __PROCESS_H__ 4 | 5 | 6 | #include 7 | 8 | /* declare process's statements... */ 9 | #define PROCESS_RUNNING 1 10 | #define PROCESS_INTERRUPTIBLE 2 11 | #define PROCESS_UNINTERRUPTIBLE 3 12 | #define PROCESS_STOPPED 4 13 | 14 | 15 | /* process table... */ 16 | struct task_struct 17 | { 18 | ssize_t status; 19 | size_t pid; 20 | char name[16]; 21 | 22 | u64 cr3; 23 | 24 | //struct thread_struct thread; 25 | 26 | }; 27 | 28 | 29 | 30 | 31 | #endif 32 | -------------------------------------------------------------------------------- /src/include/processor.h: -------------------------------------------------------------------------------- 1 | #ifndef __PROCESSOR_H 2 | #define __PROCESSOR_H 3 | 4 | #include 5 | #include 6 | 7 | #include 8 | 9 | 10 | 11 | // 12 | // Maximum 2 processor supported 13 | // 14 | #define NR_CPUS 2 15 | 16 | 17 | 18 | // CPUID 19 | #define X86_VENDOR_UNKNOWN 0xff 20 | #define X86_VENDOR_INTEL 0 21 | #define X86_VENDOR_AMD 1 22 | 23 | 24 | // x86_64 cache align 25 | #define X86_64_CACHE_ALIGN 16 26 | 27 | 28 | /* 29 | * EFLAGS bits 30 | */ 31 | #define X86_EFLAGS_CF 0x00000001 /* Carry Flag */ 32 | #define X86_EFLAGS_PF 0x00000004 /* Parity Flag */ 33 | #define X86_EFLAGS_AF 0x00000010 /* Auxillary carry Flag */ 34 | #define X86_EFLAGS_ZF 0x00000040 /* Zero Flag */ 35 | #define X86_EFLAGS_SF 0x00000080 /* Sign Flag */ 36 | #define X86_EFLAGS_TF 0x00000100 /* Trap Flag */ 37 | #define X86_EFLAGS_IF 0x00000200 /* Interrupt Flag */ 38 | #define X86_EFLAGS_DF 0x00000400 /* Direction Flag */ 39 | #define X86_EFLAGS_OF 0x00000800 /* Overflow Flag */ 40 | #define X86_EFLAGS_IOPL 0x00003000 /* IOPL mask */ 41 | #define X86_EFLAGS_NT 0x00004000 /* Nested Task */ 42 | #define X86_EFLAGS_RF 0x00010000 /* Resume Flag */ 43 | #define X86_EFLAGS_VM 0x00020000 /* Virtual Mode */ 44 | #define X86_EFLAGS_AC 0x00040000 /* Alignment Check */ 45 | #define X86_EFLAGS_VIF 0x00080000 /* Virtual Interrupt Flag */ 46 | #define X86_EFLAGS_VIP 0x00100000 /* Virtual Interrupt Pending */ 47 | #define X86_EFLAGS_ID 0x00200000 /* CPUID detection flag */ 48 | 49 | /* 50 | * Basic CPU control in CR0 51 | */ 52 | #define X86_CR0_PE 0x00000001 /* Protection Enable */ 53 | #define X86_CR0_MP 0x00000002 /* Monitor Coprocessor */ 54 | #define X86_CR0_EM 0x00000004 /* Emulation */ 55 | #define X86_CR0_TS 0x00000008 /* Task Switched */ 56 | #define X86_CR0_ET 0x00000010 /* Extension Type */ 57 | #define X86_CR0_NE 0x00000020 /* Numeric Error */ 58 | #define X86_CR0_WP 0x00010000 /* Write Protect */ 59 | #define X86_CR0_AM 0x00040000 /* Alignment Mask */ 60 | #define X86_CR0_NW 0x20000000 /* Not Write-through */ 61 | #define X86_CR0_CD 0x40000000 /* Cache Disable */ 62 | #define X86_CR0_PG 0x80000000 /* Paging */ 63 | 64 | /* 65 | * Paging options in CR3 66 | */ 67 | #define X86_CR3_PWT 0x00000008 /* Page Write Through */ 68 | #define X86_CR3_PCD 0x00000010 /* Page Cache Disable */ 69 | 70 | /* 71 | * Intel CPU features in CR4 72 | */ 73 | #define X86_CR4_VME 0x00000001 /* enable vm86 extensions */ 74 | #define X86_CR4_PVI 0x00000002 /* virtual interrupts flag enable */ 75 | #define X86_CR4_TSD 0x00000004 /* disable time stamp at ipl 3 */ 76 | #define X86_CR4_DE 0x00000008 /* enable debugging extensions */ 77 | #define X86_CR4_PSE 0x00000010 /* enable page size extensions */ 78 | #define X86_CR4_PAE 0x00000020 /* enable physical address extensions */ 79 | #define X86_CR4_MCE 0x00000040 /* Machine check enable */ 80 | #define X86_CR4_PGE 0x00000080 /* enable global pages */ 81 | #define X86_CR4_PCE 0x00000100 /* enable performance counters at ipl 3 */ 82 | #define X86_CR4_OSFXSR 0x00000200 /* enable fast FPU save and restore */ 83 | #define X86_CR4_OSXMMEXCPT 0x00000400 /* enable unmasked SSE exceptions */ 84 | #define X86_CR4_VMXE 0x00002000 /* enable VMX virtualization */ 85 | 86 | 87 | 88 | 89 | /* thread structure... */ 90 | typedef struct _thread_struct 91 | { 92 | unsigned int edi; 93 | unsigned int esi; 94 | unsigned int ebp; 95 | unsigned int esp0; 96 | unsigned int ebx; 97 | unsigned int edx; 98 | unsigned int ecx; 99 | unsigned int eax; 100 | unsigned short ds; 101 | unsigned short ds_res; 102 | unsigned short es; 103 | unsigned short es_res; 104 | unsigned short fs; 105 | unsigned short fs_res; 106 | unsigned short gs; 107 | unsigned short gs_res; 108 | unsigned int eip; 109 | unsigned short cs; 110 | unsigned short cs_res; 111 | unsigned int eflags; 112 | unsigned int esp; 113 | unsigned short ss; 114 | unsigned short ss_res; 115 | } thread_struct; 116 | 117 | 118 | 119 | typedef struct _tss_struct { 120 | u32 reserved1; 121 | u64 rsp0; 122 | u64 rsp1; 123 | u64 rsp2; 124 | u64 reserved2; 125 | u64 ist[7]; 126 | u32 reserved3; 127 | u32 reserved4; 128 | u16 reserved5; 129 | u16 io_bitmap_base; 130 | /* 131 | * The extra 1 is there because the CPU will access an 132 | * additional byte beyond the end of the IO permission 133 | * bitmap. The extra byte must be all 1 bits, and must 134 | * be within the limit. Thus we have: 135 | * 136 | * 128 bytes, the bitmap itself, for ports 0..0x3ff 137 | * 8 bytes, for an extra "long" of ~0UL 138 | */ 139 | unsigned long io_bitmap[IO_BITMAP_LONGS + 1]; 140 | } __attribute__((packed)) tss_struct; 141 | 142 | 143 | 144 | 145 | struct cpuinfo_x86 { 146 | //u8 x86; // CPU family 147 | u8 x86_vendor; // CPU vendor 148 | //u8 x86_model; 149 | int cpuid_level; // maximum supported CPUID level 150 | char x86_vendor_id[16]; 151 | //char x86_model_id[64]; 152 | int x86_cache_size; // in KB 153 | int x86_cache_alignment; 154 | int x86_tlbsize; // number of 4K pages in DTLB/ITLB combined 155 | u8 x86_virt_bits, x86_phys_bits; 156 | u8 x86_max_cores; // cpuid returend max cores value 157 | 158 | 159 | u8 apicid; 160 | 161 | u8 booted_cores; // number of cores as seen by OS 162 | u8 phys_proc_id; // physical processor id 163 | u8 cpu_core_id; // core id 164 | 165 | }; 166 | 167 | 168 | 169 | #define HALT while(1); 170 | 171 | static inline void halt(void) 172 | { 173 | while (1); 174 | } 175 | 176 | 177 | // 178 | // CR0~CR4,CR8 handling functions, copied from linux-2.6.23 179 | // 180 | 181 | static inline u64 read_cr0(void) 182 | { 183 | u64 cr0; 184 | asm volatile("movq %%cr0,%0" : "=r" (cr0)); 185 | return cr0; 186 | } 187 | 188 | static inline void write_cr0(u64 val) 189 | { 190 | asm volatile("movq %0,%%cr0" :: "r" (val)); 191 | } 192 | 193 | static inline u64 read_cr2(void) 194 | { 195 | u64 cr2; 196 | asm("movq %%cr2,%0" : "=r" (cr2)); 197 | return cr2; 198 | } 199 | 200 | static inline void write_cr2(u64 val) 201 | { 202 | asm volatile("movq %0,%%cr2" :: "r" (val)); 203 | } 204 | 205 | static inline u64 read_cr3(void) 206 | { 207 | u64 cr3; 208 | asm("movq %%cr3,%0" : "=r" (cr3)); 209 | return cr3; 210 | } 211 | 212 | static inline void write_cr3(u64 val) 213 | { 214 | asm volatile("movq %0,%%cr3" :: "r" (val) : "memory"); 215 | } 216 | 217 | static inline u64 read_cr4(void) 218 | { 219 | u64 cr4; 220 | asm("movq %%cr4,%0" : "=r" (cr4)); 221 | return cr4; 222 | } 223 | 224 | static inline void write_cr4(u64 val) 225 | { 226 | asm volatile("movq %0,%%cr4" :: "r" (val) : "memory"); 227 | } 228 | 229 | static inline u64 read_cr8(void) 230 | { 231 | u64 cr8; 232 | asm("movq %%cr8,%0" : "=r" (cr8)); 233 | return cr8; 234 | } 235 | 236 | static inline void write_cr8(u64 val) 237 | { 238 | asm volatile("movq %0,%%cr8" :: "r" (val) : "memory"); 239 | } 240 | 241 | 242 | 243 | static inline void __flush_tlb(void) 244 | { 245 | // writing CR3 does flushing TLB 246 | write_cr3(read_cr3()); 247 | } 248 | 249 | static inline void __flush_tlb_all(void) 250 | { 251 | u64 cr4 = read_cr4(); 252 | 253 | // disable Page-Global-Enable means 254 | // all TLB must be flushed including global pages 255 | write_cr4(cr4 & ~X86_CR4_PGE); 256 | 257 | // restore CR4 258 | write_cr4(cr4); 259 | } 260 | 261 | static inline void flush_cache(void) 262 | { 263 | asm volatile("wbinvd":::"memory"); 264 | } 265 | 266 | #define cli() __asm__ __volatile__("cli":::"memory") 267 | #define sti() __asm__ __volatile__("sti":::"memory") 268 | 269 | 270 | 271 | 272 | 273 | #endif /* __PROCESSOR_H */ 274 | -------------------------------------------------------------------------------- /src/include/sched.h: -------------------------------------------------------------------------------- 1 | #ifndef __SCHED_H__ 2 | #define __SCHED_H__ 3 | 4 | #include "processor.h" 5 | #include 6 | 7 | /* 8 | * Task state bitmask. NOTE! These bits are also 9 | * encoded in fs/proc/array.c: get_task_state(). 10 | * 11 | * We have two separate sets of flags: task->state 12 | * is about runnability, while task->exit_state are 13 | * about the task exiting. Confusing, but this way 14 | * modifying one set can't modify the other one by 15 | * mistake. 16 | */ 17 | #define TASK_RUNNING 0 18 | #define TASK_INTERRUPTIBLE 1 19 | #define TASK_UNINTERRUPTIBLE 2 20 | #define TASK_STOPPED 4 21 | #define TASK_TRACED 8 22 | /* in tsk->exit_state */ 23 | #define EXIT_ZOMBIE 16 24 | #define EXIT_DEAD 32 25 | /* in tsk->state again */ 26 | #define TASK_NONINTERACTIVE 64 27 | 28 | #define set_task_state(tsk, state_value) \ 29 | do { (tsk)->state = (state_value); } while (0) 30 | 31 | /* 32 | * set_current_state() includes a barrier so that the write of current->state 33 | * is correctly serialised wrt the caller's subsequent test of whether to 34 | * actually sleep: 35 | * 36 | * set_current_state(TASK_UNINTERRUPTIBLE); 37 | * if (do_i_need_to_sleep()) 38 | * schedule(); 39 | * 40 | * If the caller does not need such serialisation then use __set_current_state() 41 | */ 42 | #define set_current_state(state_value) \ 43 | do { current->state = (state_value); } while (0) 44 | 45 | 46 | /* 47 | * Per process flags 48 | */ 49 | #define PF_ALIGNWARN 0x00000001 /* Print alignment warning msgs */ 50 | /* Not implemented yet, only for 486*/ 51 | #define PF_STARTING 0x00000002 /* being created */ 52 | #define PF_EXITING 0x00000004 /* getting shut down */ 53 | #define PF_DEAD 0x00000008 /* Dead */ 54 | #define PF_FORKNOEXEC 0x00000040 /* forked but didn't exec */ 55 | #define PF_SUPERPRIV 0x00000100 /* used super-user privileges */ 56 | #define PF_DUMPCORE 0x00000200 /* dumped core */ 57 | #define PF_SIGNALED 0x00000400 /* killed by a signal */ 58 | #define PF_MEMALLOC 0x00000800 /* Allocating memory */ 59 | #define PF_FLUSHER 0x00001000 /* responsible for disk writeback */ 60 | #define PF_USED_MATH 0x00002000 /* if unset the fpu must be initialized before use */ 61 | #define PF_FREEZE 0x00004000 /* this task is being frozen for suspend now */ 62 | #define PF_NOFREEZE 0x00008000 /* this thread should not be frozen */ 63 | #define PF_FROZEN 0x00010000 /* frozen for system suspend */ 64 | #define PF_FSTRANS 0x00020000 /* inside a filesystem transaction */ 65 | #define PF_KSWAPD 0x00040000 /* I am kswapd */ 66 | #define PF_SWAPOFF 0x00080000 /* I am in swapoff */ 67 | #define PF_LESS_THROTTLE 0x00100000 /* Throttle me less: I clean memory */ 68 | #define PF_SYNCWRITE 0x00200000 /* I am doing a sync write */ 69 | #define PF_BORROWED_MM 0x00400000 /* I am a kthread doing use_mm */ 70 | #define PF_RANDOMIZE 0x00800000 /* randomize virtual address space */ 71 | 72 | 73 | void init_scheduler(void); 74 | void schedule(void); 75 | void start_scheduler(void); 76 | 77 | void stop_scheduler(void); 78 | 79 | 80 | 81 | 82 | 83 | // memory status of process 84 | struct mm_struct { 85 | 86 | u64 start_code, end_code; 87 | u64 start_data, end_data; 88 | u64 start_bss, end_bss; 89 | u64 start_brk, brk, start_stack; 90 | u64 start_heap, end_heap; 91 | u64 start_percpu, end_percpu; 92 | 93 | u64 start_reserved, end_reserved; 94 | 95 | }; 96 | 97 | 98 | 99 | #endif 100 | -------------------------------------------------------------------------------- /src/include/screen.h: -------------------------------------------------------------------------------- 1 | #ifndef __SCREEN_H__ 2 | 3 | #define __SCREEN_H__ 4 | 5 | #include 6 | #include 7 | 8 | #define VIDEO_ADDRESS (PAGE_OFFSET+0xb8000UL) 9 | #define SCREEN_ROW 25 10 | #define SCREEN_COL 80 11 | #define ONECHAR_SIZE 2 12 | //#define ONELINE_SIZE (SCREEN_COL * ONECHAR_SIZE) 13 | 14 | #define BG_BLACK ((unsigned short)0x0700) 15 | 16 | 17 | void init_screen(void); 18 | void set_cursor(ssize_t); 19 | 20 | void scroll_screen(ssize_t); 21 | void clear_screen(void); 22 | 23 | 24 | struct screen_info { 25 | size_t cursor_offset; 26 | volatile u16 *video_mem; 27 | 28 | }; 29 | 30 | extern struct screen_info screen_info; 31 | 32 | 33 | 34 | static inline void set_screen(size_t offset, u8 c) 35 | { 36 | 37 | screen_info.video_mem[offset] = (BG_BLACK | c); 38 | 39 | } 40 | 41 | 42 | 43 | 44 | 45 | #endif 46 | -------------------------------------------------------------------------------- /src/include/setup.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef _SETUP_H 3 | #define _SETUP_H 1 4 | 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | 12 | 13 | #define BOOT_PARAMS (u64 *)(0x9F000+PAGE_OFFSET) 14 | 15 | #define PARAMS_OFFSET_START_CODE 0 16 | #define PARAMS_OFFSET_END_CODE 1 17 | #define PARAMS_OFFSET_START_DATA 2 18 | #define PARAMS_OFFSET_END_DATA 3 19 | #define PARAMS_OFFSET_START_BSS 4 20 | #define PARAMS_OFFSET_END_BSS 5 21 | #define PARAMS_OFFSET_END_KERNEL 6 22 | #define PARAMS_OFFSET_PHYMEM_SIZE 7 23 | #define PARAMS_OFFSET_BOOT_GDT 8 24 | #define PARAMS_OFFSET_BOOT_SIZE 9 25 | #define PARAMS_OFFSET_START_VIDEO 10 26 | #define PARAMS_OFFSET_END_VIDEO 11 27 | #define PARAMS_OFFSET_START_PERCPU 12 28 | #define PARAMS_OFFSET_END_PERCPU 13 29 | 30 | 31 | 32 | void setup_arch(void); 33 | void early_identify_cpu(struct cpuinfo_x86 *); 34 | 35 | 36 | extern struct mm_struct init_mm; 37 | extern size_t phy_mem_size; 38 | 39 | 40 | 41 | #endif 42 | -------------------------------------------------------------------------------- /src/include/slab.h: -------------------------------------------------------------------------------- 1 | 2 | 3 | #ifndef __SLAB_H__ 4 | #define __SLAB_H__ 5 | 6 | 7 | 8 | #include 9 | #include 10 | #include 11 | 12 | 13 | 14 | #define SLAB_DEFAULT_NUM 10 15 | #define CACHE_CACHE_PAGE 1 16 | 17 | #define KMALLOC_RETRY_MAX 3 18 | 19 | #define BUFCTL_END (u16)0xFFFF 20 | 21 | 22 | typedef u16 kmem_bufctl_t; 23 | 24 | 25 | // 26 | // struct kmem_cache 27 | // 28 | // manages a cache, which manages slabs. 29 | // A cache size is statically fixed, multiples of 16bytes. 30 | // 31 | struct kmem_cache { 32 | //size_t limit; // max # of objs per cache 33 | size_t objsize; // size of obj 34 | flag_t flag; // flags of cache 35 | size_t num; // # of objs per slab 36 | 37 | size_t gfporder; // # of page per slab 38 | struct list_head slabs; // pointer to slab 39 | 40 | u64 colour_off; 41 | 42 | const char *name; 43 | }; 44 | 45 | 46 | // 47 | // struct slab 48 | // 49 | // Manages the objs in a slab. Placed at the beginning of page allocated for a slab. 50 | // A kmem_cache can have list of slabs 51 | // 52 | struct slab { 53 | struct list_head list; 54 | u64 s_mem; // pointer to free object 55 | size_t inuse; // busy objects count 56 | size_t free; // index of free object 57 | u64 offset; // offset of the first object from page boundary 58 | kmem_bufctl_t *bufctl; 59 | 60 | struct kmem_cache *cache; 61 | }; 62 | 63 | 64 | 65 | extern struct kmem_cache *cache_cache; 66 | 67 | 68 | 69 | void kmem_cache_init(void); 70 | struct kmem_cache *kmem_cache_create(const char *name, size_t size, size_t align, flag_t flags); 71 | 72 | size_t kmem_cache_grow(struct kmem_cache *cachep, flag_t flags); 73 | void *kmem_getpages(struct kmem_cache *cachep, flag_t flag); 74 | void kmem_freepages(struct kmem_cache *cachep, void *addr); 75 | 76 | 77 | void slab_destroy(struct kmem_cache *cachep, struct slab *slabp); 78 | 79 | 80 | void kmem_cache_shrink(struct kmem_cache *cachep, flag_t flags); 81 | 82 | 83 | void *caos_kmalloc(size_t size, flag_t flags); 84 | void caos_kfree(void *objp); 85 | 86 | #endif 87 | -------------------------------------------------------------------------------- /src/include/smp.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef __SMP_H__ 3 | #define __SMP_H__ 4 | 5 | 6 | #include 7 | 8 | 9 | 10 | // 11 | // macros 12 | // 13 | 14 | #define smp_mb() asm volatile("mfence":::"memory") 15 | #define smp_rmb() asm volatile("lfence":::"memory") 16 | #define smp_wmb() asm volatile("sfence":::"memory") 17 | 18 | 19 | #define preempt_count() (preempt_count) 20 | 21 | 22 | 23 | 24 | // 25 | // interrupt-disable is necessary for preempt-disable?? 26 | // 27 | 28 | #define preempt_disable() \ 29 | do { \ 30 | preempt_count() += 1;\ 31 | smp_wmb();\ 32 | } while (0) 33 | 34 | #define preempt_enable() \ 35 | do { \ 36 | preempt_count() -= 1;\ 37 | smp_wmb();\ 38 | } while (0) 39 | 40 | 41 | 42 | 43 | // 44 | // The address that AP start executin at 45 | // 46 | #define AP_INIT_ADDRESS 0x9000 47 | 48 | 49 | // 50 | // get CPU's ID 51 | // 52 | static inline size_t cpu_id(void) 53 | { 54 | return apic_read(APIC_ID); 55 | } 56 | 57 | 58 | 59 | extern ssize_t preempt_count; 60 | 61 | void smp_init(void); 62 | void wake_ap(void); 63 | 64 | 65 | #endif 66 | 67 | 68 | -------------------------------------------------------------------------------- /src/include/spinlock.h: -------------------------------------------------------------------------------- 1 | #ifndef __SPINLOCK_H__ 2 | #define __SPINLOCK_H__ 3 | 4 | 5 | 6 | #include 7 | 8 | 9 | 10 | typedef struct { 11 | ssize_t slock; 12 | } spinlock_t; 13 | 14 | #define SPIN_LOCK_UNLOCKED 1 15 | #define SPIN_LOCK_LOCKED 0 16 | 17 | 18 | 19 | #define cpu_relax() asm volatile("rep;nop":::"memory") 20 | 21 | 22 | 23 | #define spin_lock_init(lock) \ 24 | do { lock->slock = SPIN_LOCK_UNLOCKED; } while (0) 25 | 26 | 27 | #define spin_is_locked(lock) test_bit(0, &lock->slock) 28 | 29 | #endif 30 | -------------------------------------------------------------------------------- /src/include/stamp-h1: -------------------------------------------------------------------------------- 1 | timestamp for ./src/include/platform.h 2 | -------------------------------------------------------------------------------- /src/include/string.h: -------------------------------------------------------------------------------- 1 | #ifndef __STRING_H__ 2 | 3 | #define __STRING_H__ 4 | 5 | #include 6 | 7 | 8 | size_t caos_strcat(char *A_szDest, char *A_szSrc); 9 | size_t caos_strcmp(const char *src, const char *dst); 10 | size_t caos_strlen(const char *); 11 | void *caos_memcpy(void *dst, void *src, size_t len); 12 | void *caos_memset(void *dst, size_t c, size_t len); 13 | 14 | size_t caos_memcmp(const void *cs, const void *ct, size_t count); 15 | #endif 16 | -------------------------------------------------------------------------------- /src/include/syscall.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef __SYSCALL_H__ 3 | #define __SYSCALL_H__ 4 | 5 | 6 | #define SYSCALL_VECTOR 0x80 7 | 8 | 9 | 10 | #define __NR_sys_syscall_test 0 11 | #define __NR_sys_cputstr 1 12 | #define __NR_sys_cgetstr 2 13 | #define __NR_sys_cprintf 3 14 | 15 | #define __NR_sys_system_info 4 16 | #define __NR_sys_turnoff 5 17 | #define __NR_sys_open 6 18 | #define __NR_sys_close 7 19 | #define __NR_sys_read 8 20 | #define __NR_sys_write 9 21 | 22 | extern int sys_call_max; 23 | 24 | 25 | 26 | #endif 27 | -------------------------------------------------------------------------------- /src/include/types.h: -------------------------------------------------------------------------------- 1 | #ifndef __TYPES_H__ 2 | 3 | #define __TYPES_H__ 4 | 5 | #define NULL (void *)0 6 | 7 | 8 | 9 | // 10 | // x86_64 processor saves function-parameters in registers, 11 | // so that gcc built-in functions are used like this. 12 | // 13 | typedef __builtin_va_list va_list; 14 | #define va_start(v,l) __builtin_va_start(v,l) 15 | #define va_arg(v,l) __builtin_va_arg(v,l) 16 | #define va_end(v) __builtin_va_end(v) 17 | 18 | 19 | #define asmlinkage __attribute__((regparm(0))) 20 | 21 | 22 | #define BITS_PER_LONG 64 23 | #define BYTES_PER_LONG 8 24 | #define BITS_PER_BYTE 8 25 | 26 | 27 | 28 | #define BITS_TO_LONGS(bits) \ 29 | (((bits)+BITS_PER_LONG-1)/BITS_PER_LONG) 30 | #define DECLARE_BITMAP(name,bits) \ 31 | unsigned long name[BITS_TO_LONGS(bits)] 32 | 33 | 34 | typedef signed char s8; 35 | typedef unsigned char u8; 36 | 37 | typedef signed short s16; 38 | typedef unsigned short u16; 39 | 40 | typedef signed int s32; 41 | typedef unsigned int u32; 42 | 43 | typedef signed long s64; 44 | typedef unsigned long u64; 45 | 46 | 47 | // coungting, index of something.. 48 | typedef unsigned long size_t; 49 | typedef signed long ssize_t; 50 | 51 | 52 | // flag type for bit-attributes 53 | typedef unsigned long flag_t; 54 | 55 | 56 | 57 | // for atomic operations 58 | typedef struct { 59 | volatile long counter; // long type for 64bit 60 | } atomic_t; 61 | 62 | 63 | #define CAOS_TRUE 1 64 | #define CAOS_FALSE 0 65 | 66 | #define CAOS_SUCCESS 0 67 | 68 | 69 | #endif 70 | -------------------------------------------------------------------------------- /src/include/user_syscall.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef __USER_SYSCALL_H__ 3 | #define __USER_SYSCALL_H__ 4 | 5 | 6 | #include "syscall.h" 7 | 8 | 9 | 10 | // 11 | // definitions of system-call library 12 | // 13 | int sys_syscall_test(void); // 0 14 | int sys_cputstr(const char *); // 1 15 | int sys_cgetstr(const char *, long); // 2 16 | int sys_cprintf(const char *, long); // 3 17 | int sys_system_info(void); // 4 18 | int sys_turnoff(void); // 5 19 | 20 | int sys_open(const char *, int); // 6 21 | int sys_close(int); // 7 22 | int sys_read(int, char *, int); // 8 23 | int sys_write(int, char *, int); // 9 24 | 25 | 26 | #define _syscall0(type, name)\ 27 | inline type name(void)\ 28 | {\ 29 | long __res;\ 30 | asm volatile (\ 31 | "int $0x80\n\t"\ 32 | :"=a"(__res)\ 33 | :"a"(__NR_##name)\ 34 | );\ 35 | return __res;\ 36 | } 37 | 38 | 39 | #define _syscall1(type, name, type1, arg1)\ 40 | inline type name(type1 arg1)\ 41 | {\ 42 | long __res;\ 43 | asm volatile (\ 44 | "int $0x80\n\t"\ 45 | :"=a"(__res)\ 46 | :"a"(__NR_##name), "b"((long)arg1)\ 47 | );\ 48 | return __res;\ 49 | } 50 | 51 | 52 | #define _syscall2(type, name, type1, arg1, type2, arg2)\ 53 | inline type name(type1 arg1, type2 arg2)\ 54 | {\ 55 | long __res;\ 56 | asm volatile (\ 57 | "int $0x80\n\t"\ 58 | :"=a"(__res)\ 59 | :"a"(__NR_##name), "b"((long)arg1), "c"((long)arg2)\ 60 | );\ 61 | return __res;\ 62 | } 63 | 64 | #define _syscall3(type, name, type1, arg1, type2, arg2, type3, arg3)\ 65 | inline type name(type1 arg1, type2 arg2, type3 arg3)\ 66 | {\ 67 | long __res;\ 68 | asm volatile (\ 69 | "int $0x80\n\t"\ 70 | :"=a"(__res)\ 71 | :"a"(__NR_##name), "b"((long)arg1), "c"((long)arg2), "d"((long)arg3)\ 72 | );\ 73 | return __res;\ 74 | } 75 | 76 | 77 | 78 | #endif 79 | -------------------------------------------------------------------------------- /src/include/user_tasks.h: -------------------------------------------------------------------------------- 1 | #ifndef __USER_TASKS_H__ 2 | #define __USER_TASKS_H__ 3 | 4 | 5 | 6 | #define USER1_ADDR 0x40002000 7 | #define USER1_PCB 0x40003000 8 | #define USER2_ADDR 0x40004000 9 | #define USER2_PCB 0x40005000 10 | 11 | 12 | 13 | void user1(void); 14 | 15 | void user2(void); 16 | 17 | 18 | 19 | 20 | 21 | #endif 22 | -------------------------------------------------------------------------------- /src/io_apic.c: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | // 5 | // IO APIC setting is under constructing. 6 | // 7 | // WARNING! Never use this file till it's completed. 8 | // 9 | 10 | 11 | #include 12 | #include 13 | #include // IRQ_TO_VECTOR 14 | 15 | static struct io_apic *io_apic_base(void) 16 | { 17 | return (void *)IO_APIC_BASE; 18 | } 19 | 20 | static inline unsigned int io_apic_read(unsigned int reg) 21 | { 22 | struct io_apic *io_apic = io_apic_base(); 23 | writel(reg, &io_apic->index); 24 | return readl(&io_apic->data); 25 | } 26 | 27 | static inline void io_apic_write(unsigned int reg, unsigned int value) 28 | { 29 | struct io_apic *io_apic = io_apic_base(); 30 | writel(reg, &io_apic->index); 31 | writel(value, &io_apic->data); 32 | } 33 | 34 | /* 35 | * Re-write a value: to be used for read-modify-write 36 | * cycles where the read already set up the index register. 37 | */ 38 | static inline void io_apic_modify(unsigned int value) 39 | { 40 | struct io_apic *io_apic = io_apic_base(); 41 | writel(value, &io_apic->data); 42 | } 43 | 44 | /* 45 | * Synchronize the IO-APIC and the CPU by doing 46 | * a dummy read from the IO-APIC 47 | */ 48 | static inline void io_apic_sync(void) 49 | { 50 | struct io_apic *io_apic = io_apic_base(); 51 | readl(&io_apic->data); 52 | } 53 | 54 | 55 | int io_apic_enable_irq(size_t irq) 56 | { 57 | u64 tbl = 0; 58 | ssize_t entry; 59 | 60 | entry = GET_IO_APIC_ENTRY(io_apic_read(IO_APIC_VERSION)); 61 | 62 | if ((ssize_t)irq > entry) 63 | return -1; 64 | 65 | tbl |= SET_IO_APIC_DEST(0x0UL); // destination cpu has #0 APIC ID 66 | tbl &= ~IO_APIC_IRQ_MASK; // enable INTR 67 | tbl |= IO_APIC_TRIG_MODE;// 1:level 0:edge 68 | tbl |= IO_APIC_INTPOL;// 1:active low, 0: active high 69 | 70 | tbl &= ~IO_APIC_DESTMOD; // 1:logical 0:physical 71 | tbl |= IO_APIC_DELMOD_FIX; // send INTR to destination cpu 72 | 73 | 74 | // Interrupt vector 0x0~0x1F is reserved for processor exceptions. 75 | // Therefore vector of external devices must be larger than 0x20. 76 | // Local APIC will occur error handling interrupt if vector 0x0~0x1F is sent. 77 | tbl |= IRQ_TO_VECTOR(irq);// IRQ vector 78 | 79 | io_apic_write(IO_APIC_REDTBL_BASE + irq*2, tbl); 80 | 81 | return CAOS_SUCCESS; 82 | } 83 | 84 | 85 | 86 | void io_apic_init(void) 87 | { 88 | 89 | volatile int delay; 90 | 91 | // write IMCR with 0x1 to enable IO APIC 92 | // This sets IO APIC as Symmetric I/O Mode (introduced at MP Spcification) 93 | outb(0x22, 0x70); // select register 94 | for (delay = 0; delay != 0x100000; delay++) 95 | continue; 96 | outb(0x23, 0x1); // write command 97 | 98 | 99 | caos_printf("IO APIC ID=%x\n", (io_apic_read(0x0)>>24) & 0xF); 100 | caos_printf("IO APIC VER=%x ", GET_IO_APIC_VERSION(io_apic_read(IO_APIC_VERSION)) ); 101 | caos_printf("IO APIC Entry=%d\n", (GET_IO_APIC_ENTRY(io_apic_read(0x1))) ); 102 | 103 | // activating IRQs are done by device's driver with calling 104 | // io_apic_enable_irq 105 | #if 0 106 | // moved to io_apic_enable_irq() 107 | for (i = 0; i <= entry; i++) { 108 | 109 | tbl = io_apic_read(IO_APIC_REDTBL_BASE + i*2); 110 | 111 | tbl |= SET_IO_APIC_DEST(0x0UL); // destination cpu has #0 APIC ID 112 | tbl |= IO_APIC_IRQ_MASK; // mask all, it will be enabled when register device 113 | tbl |= IO_APIC_TRIG_MODE;//&= ~IO_APIC_TRIG_MODE; // edge 114 | tbl |= IO_APIC_INTPOL;//&= ~IO_APIC_INTPOL; // high active 115 | 116 | tbl &= ~IO_APIC_DESTMOD; // physical mode + APIC ID // |= IO_APIC_DESTMOD; //loginal mode + set of processors 117 | tbl |= IO_APIC_DELMOD_FIX; //ExtINT; // ExtINT 118 | 119 | 120 | // vector values range from 0x10 to 0xEF 121 | // example) keyboard IRQ#1 -> cpu accepts IRQ #(1+VECTOR_BASE) 122 | tbl |= IRQ_TO_VECTOR(i);// + CPU_IRQ_BASE; // vector 123 | 124 | io_apic_write(IO_APIC_REDTBL_BASE + i*2, tbl); 125 | } 126 | #endif 127 | } 128 | 129 | 130 | -------------------------------------------------------------------------------- /src/irq_entry.asm: -------------------------------------------------------------------------------- 1 | 2 | [bits 64] 3 | [CPU X64] 4 | [DEFAULT REL] 5 | 6 | 7 | 8 | 9 | extern ignore_isr_handler 10 | extern handle_irq 11 | 12 | 13 | 14 | 15 | ; every general register is 16 | %macro SAVE_ALL 0 17 | 18 | push rax 19 | push rbx 20 | push rcx 21 | push rdx 22 | 23 | push rsi 24 | push rdi 25 | push rbp 26 | 27 | push r8 28 | push r9 29 | push r10 30 | push r11 31 | push r12 32 | push r13 33 | push r14 34 | push r15 35 | 36 | push fs 37 | push gs 38 | 39 | %endmacro 40 | 41 | 42 | ; SAVE_ALL is referred to linux-kernel 43 | %macro RESTORE_ALL 0 44 | 45 | pop fs 46 | pop gs 47 | 48 | pop r15 49 | pop r14 50 | pop r13 51 | pop r12 52 | pop r11 53 | pop r10 54 | pop r9 55 | pop r8 56 | 57 | ;pop rsp 58 | pop rbp 59 | pop rdi 60 | pop rsi 61 | 62 | pop rdx 63 | pop rcx 64 | pop rbx 65 | pop rax 66 | 67 | 68 | %endmacro 69 | 70 | 71 | 72 | 73 | 74 | 75 | %macro IRQ_ENTRY 2 76 | align 8 77 | global %1 78 | %1: 79 | SAVE_ALL 80 | 81 | mov rdi, %2 82 | call handle_irq 83 | 84 | RESTORE_ALL 85 | 86 | iretq 87 | %endmacro 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | section .text 99 | 100 | 101 | 102 | 103 | 104 | ;----------------------------------------------------- 105 | 106 | IRQ_ENTRY _irq_0, 0 107 | IRQ_ENTRY _irq_1, 1 108 | IRQ_ENTRY _irq_2, 2 109 | IRQ_ENTRY _irq_3, 3 110 | IRQ_ENTRY _irq_4, 4 111 | IRQ_ENTRY _irq_5, 5 112 | IRQ_ENTRY _irq_6, 6 113 | IRQ_ENTRY _irq_7, 7 114 | IRQ_ENTRY _irq_8, 8 115 | IRQ_ENTRY _irq_9, 9 116 | IRQ_ENTRY _irq_10, 10 117 | IRQ_ENTRY _irq_11, 11 118 | IRQ_ENTRY _irq_12, 12 119 | IRQ_ENTRY _irq_13, 13 120 | IRQ_ENTRY _irq_14, 14 121 | IRQ_ENTRY _irq_15, 15 122 | IRQ_ENTRY _irq_16, 16 123 | IRQ_ENTRY _irq_17, 17 124 | IRQ_ENTRY _irq_18, 18 125 | IRQ_ENTRY _irq_19, 19 126 | IRQ_ENTRY _irq_20, 20 127 | IRQ_ENTRY _irq_21, 21 128 | IRQ_ENTRY _irq_22, 22 129 | IRQ_ENTRY _irq_23, 23 130 | IRQ_ENTRY _irq_24, 24 131 | IRQ_ENTRY _irq_25, 25 132 | IRQ_ENTRY _irq_26, 26 133 | IRQ_ENTRY _irq_27, 27 134 | IRQ_ENTRY _irq_28, 28 135 | IRQ_ENTRY _irq_29, 29 136 | IRQ_ENTRY _irq_30, 30 137 | IRQ_ENTRY _irq_31, 31 138 | 139 | 140 | 141 | 142 | ;----------------------------- 143 | ; Common ISR for unused interrupt 144 | ;----------------------------- 145 | align 8 146 | global _ignore_isr 147 | _ignore_isr: 148 | 149 | SAVE_ALL 150 | 151 | mov rdi, 0xff 152 | call ignore_isr_handler 153 | ;call handle_irq 154 | 155 | 156 | RESTORE_ALL 157 | 158 | 159 | 160 | ;================================================= 161 | ; !! VERY IMPORTANT !!! 162 | ; Interrupt handlers must be end with 'iretq'!! 163 | ;================================================= 164 | iretq 165 | 166 | 167 | 168 | -------------------------------------------------------------------------------- /src/irq_handler.c: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include // _ignore_isr 9 | #include // irq_handler[] 10 | #include // ack_pic8259 11 | #include 12 | #include 13 | 14 | #define DEBUG 15 | #undef DEBUG 16 | 17 | 18 | irq_handler_t irq_handler[MAX_IRQ]; 19 | 20 | 21 | 22 | 23 | // 24 | // set IDT descriptors (0x20~0x2F) to irq_handler table (0x0~0xF). 25 | // Actual handlers are registered into irq_handler table, not IDT. 26 | // 27 | void irq_init(void) 28 | { 29 | ssize_t i; 30 | 31 | for (i = 0; i\n", num); 74 | 75 | } 76 | 77 | 78 | 79 | // 80 | // Register irq handler into irq_handler table. 81 | // @irq: irq number 82 | // @handler: handler function 83 | // 84 | int register_irq(size_t irq, irq_handler_t handler) 85 | { 86 | 87 | // external device's irq 88 | /* if (irq < CPU_IRQ_BASE) */ 89 | /* enable_pic8259(irq); */ 90 | 91 | irq_handler[irq] = handler; 92 | 93 | #ifdef DEBUG 94 | caos_printf("Register irq#%d Handler=%x\n", irq, irq_handler[irq]); 95 | #endif 96 | 97 | return io_apic_enable_irq(irq); 98 | } 99 | 100 | 101 | 102 | // 103 | // ack PIC and enable next IRQ 104 | // 105 | void end_irq(size_t irq) 106 | { 107 | 108 | /* if (irq < CPU_IRQ_BASE) */ 109 | /* ack_pic8259(); */ 110 | /* else */ 111 | 112 | irq = irq; // ignore irq 113 | ack_APIC(); 114 | } 115 | 116 | 117 | 118 | // 119 | // Every irq-entry function calls handle_irq 120 | // and then handle_irq call irq handlers. 121 | // IRQs can be request from peripherals and even processors, 122 | // so that republish function like this is needed to treat irq-resources. 123 | // @irq: irq number 124 | // 125 | void handle_irq(size_t irq) 126 | { 127 | u32 task_pri; 128 | 129 | 130 | // 131 | // prevent lower priority IRQ 132 | // 133 | // The task priority register indicates 134 | // current processor's priority, 135 | // so that this has interrupt masked 136 | // if new irq has lower priority than current irq 137 | // 138 | task_pri = apic_read(APIC_TASKPRI); 139 | apic_write(APIC_TASKPRI, IRQ_TO_VECTOR(irq)); 140 | 141 | 142 | #ifdef DEBUG 143 | // ignore IRQ#16 that is BSP local-timer IRQ 144 | // because it makes screen dirty 145 | if (irq != 16) caos_printf("IRQ[0x%x] occured\n", irq); 146 | #endif 147 | 148 | // call irq's own handler 149 | if (irq_handler[irq] != NULL) 150 | irq_handler[irq](irq); 151 | 152 | 153 | #ifdef DEBUG 154 | // ignore IRQ#16 that is BSP local-timer IRQ 155 | // because it makes screen dirty 156 | if (irq != 16) caos_printf("end IRQ[0x%x]\n", irq); 157 | #endif 158 | 159 | // external device's irq, ack PIC8259 160 | end_irq(irq); 161 | 162 | // restore masking prioriry 163 | apic_write(APIC_TASKPRI, task_pri); 164 | 165 | } 166 | 167 | 168 | -------------------------------------------------------------------------------- /src/keyboard.c: -------------------------------------------------------------------------------- 1 | 2 | // 3 | // SHIFT, ALT, CAPS-LOCK functions are implemented - 2008.12.25 4 | // 5 | // 6 | 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | 16 | #define DEBUG 17 | #undef DEBUG 18 | 19 | 20 | 21 | #define TABLE_NORMAL 0 22 | #define TABLE_CAPSLOCK 1 23 | #define TABLE_SHIFT 2 24 | #define TABLE_CAPS_N_SHIFT 3 25 | #define TABLE_CTRL 4 26 | 27 | static unsigned char scan_to_ascii[5][128] = { 28 | { /* ascii table */ 29 | 0x00, 0x1b, '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '-', '=', 0x08, 0x09, 30 | 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p', '[', ']', 0x0d, 0x00, 'a', 's', 31 | 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';', 0x27, '`', 0x00, 0x5c, 'z', 'x', 'c', 'v', 32 | 'b', 'n', 'm', ',', '.', '/', 0x00, '*', 0x00, ' ', 0x00, 0x03, 0x03, 0x03, 0x03, 0x08, 33 | 0x03, 0x03, 0x03, 0x03, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, '-', 0x00, 0x00, 0x00, '+', 0x00, 34 | 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x5c, 0x03, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 35 | 0x0d, 0x00, '/', 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 36 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, '/', 0x00, 0x00, 0x00, 0x00, 0x00, 37 | }, 38 | { /* ascii table with capslock */ 39 | 0x00, 0x1b, '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '-', '=', 0x08, 0x09, 40 | 'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I', 'O', 'P', '[', ']', 0x0d, 0x00, 'A', 'S', 41 | 'D', 'F', 'G', 'H', 'J', 'K', 'L', ';', 0x27, '`', 0x00, 0x5c, 'Z', 'X', 'C', 'V', 42 | 'B', 'N', 'M', ',', '.', '/', 0x00, '*', 0x00, ' ', 0x00, 0x03, 0x03, 0x03, 0x03, 0x08, 43 | 0x03, 0x03, 0x03, 0x03, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, '-', 0x00, 0x00, 0x00, '+', 0x00, 44 | 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x5c, 0x03, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 45 | 0x0d, 0x00, '/', 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 46 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, '/', 0x00, 0x00, 0x00, 0x00, 0x00, 47 | }, 48 | { /* ascii with shift */ 49 | 0x00, 0x1b, '!', '@', '#', '$', '%', '^', '&', '*', '(', ')', '_', '+', 0x7e, 0x7e, 50 | 'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I', 'O', 'P', '{', '}', 0x7e, 0x00, 'A', 'S', 51 | 'D', 'F', 'G', 'H', 'J', 'K', 'L', ':', 0x27, '~', 0x00, '|', 'Z', 'X', 'C', 'V', 52 | 'B', 'N', 'M', '<', '>', '?', 0x00, '*', 0x00, 0x01, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 53 | 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, '-', 0x00, 0x00, 0x00, '+', 0x00, 54 | 0x00, 0x00, 0x01, 0x7f, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 55 | 0x0d, 0x00, '/', 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 56 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, '/', 0x00, 0x00, 0x00, 0x00, 0x00, 57 | }, 58 | { /* ascii with capslock & shift */ 59 | 0x00, 0x1b, '!', '@', '#', '$', '%', '^', '&', '*', '(', ')', '_', '+', 0x7e, 0x7e, 60 | 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p', '{', '}', 0x7e, 0x00, 'a', 's', 61 | 'd', 'f', 'g', 'h', 'j', 'k', 'l', ':', 0x27, '~', 0x00, '|', 'z', 'x', 'c', 'v', 62 | 'b', 'n', 'm', '<', '>', '?', 0x00, '*', 0x00, 0x01, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 63 | 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, '-', 0x00, 0x00, 0x00, '+', 0x00, 64 | 0x00, 0x00, 0x01, 0x7f, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 65 | 0x0d, 0x00, '/', 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 66 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, '/', 0x00, 0x00, 0x00, 0x00, 0x00, 67 | }, 68 | { /* ascii with control */ 69 | 0x00, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x00, 0x7f, 0x7f, 70 | 0x11, 0x17, 0x05, 0x12, 0x14, 0x19, 0x15, 0x09, 0x0f, 0x10, 0x02, 0x02, 0x0a, 0x00, 0x01, 0x13, 71 | 0x04, 0x06, 0x07, 0x08, 0x0a, 0x0b, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1a, 0x18, 0x03, 0x16, 72 | 0x02, 0x0e, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 73 | 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 74 | 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 75 | 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 76 | 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 77 | } 78 | }; 79 | 80 | 81 | struct key_tag_t key; 82 | 83 | 84 | 85 | ssize_t keyboard_init(void) 86 | { 87 | 88 | caos_printf("Initialize keyboard.."); 89 | 90 | // activate keyboard's IRQ 91 | if (register_irq(KEYBOARD_IRQ, keyboard_isr) == CAOS_SUCCESS) { 92 | caos_printf("OK\n"); 93 | } else { 94 | caos_printf("ERROR\n"); 95 | return -1; 96 | } 97 | 98 | return CAOS_SUCCESS; 99 | } 100 | 101 | 102 | 103 | // 104 | // 105 | // @num: IRQ index 106 | // 107 | void keyboard_isr(size_t num) 108 | { 109 | unsigned char scan=0; 110 | static ssize_t prefix=0; 111 | ssize_t tmp; 112 | ssize_t change_flag = 0; 113 | 114 | num = num; /* remove compiler warning */ 115 | 116 | scan = inb(0x60); 117 | 118 | 119 | #ifdef DEBUG 120 | caos_printf("KEYBOARD [%x]\n", scan); 121 | #endif 122 | 123 | // keyboard error 124 | if ( (scan == 0) || (scan == 0xff) ) 125 | return; 126 | 127 | if (scan == 0xe0 || scan == 0xe1) { 128 | prefix = 1; 129 | return; 130 | } 131 | 132 | if (scan == SCAN_NUMLOCK) { 133 | #ifdef DEBUG 134 | caos_printf("numlock pressed\n"); 135 | #endif 136 | tmp = MK_NUMLOCK; 137 | key.status ^= tmp; 138 | change_flag = 1; 139 | } else if (scan == SCAN_CAPSLOCK) { 140 | #ifdef DEBUG 141 | caos_printf("capslock pressed\n"); 142 | #endif 143 | tmp = MK_CAPSLOCK; 144 | key.status ^= tmp; 145 | change_flag = 1; 146 | } else if (scan == SCAN_SCROLLLOCK) { 147 | #ifdef DEBUG 148 | caos_printf("scroll-lock pressed\n"); 149 | #endif 150 | tmp = MK_SCROLLLOCK; 151 | key.status ^= tmp; 152 | change_flag = 1; 153 | } else if (scan == SCAN_LEFTSHIFT) { 154 | #ifdef DEBUG 155 | caos_printf("left_shift pressed\n"); 156 | #endif 157 | tmp = MK_SHIFT; 158 | key.status |= tmp; 159 | change_flag = 1; 160 | } else if (scan == (SCAN_LEFTSHIFT|0x80)) { 161 | #ifdef DEBUG 162 | caos_printf("left-shift released\n"); 163 | #endif 164 | tmp = MK_SHIFT; 165 | key.status &= ~tmp; 166 | change_flag = 1; 167 | #ifdef DEBUG 168 | /*} else if (scan == SCAN_RIGHTSHIFT) { 169 | //caos_printf("right-shift pressed\n"); 170 | tmp = MK_SHIFT; 171 | key.status |= tmp; 172 | change_flag = 1; 173 | } else if (scan == (SCAN_RIGHTSHIFT|0x80)) { 174 | //caos_printf("right-shift released\n"); 175 | tmp = MK_SHIFT; 176 | key.status &= ~tmp; 177 | change_flag = 1;*/ 178 | #endif 179 | } else if (scan == SCAN_LEFTCTRL) { 180 | #ifdef DEBUG 181 | caos_printf("left-ctrl pressed\n"); 182 | #endif 183 | tmp = MK_CTRL; 184 | key.status |= tmp; 185 | change_flag = 1; 186 | } else if (scan == (SCAN_LEFTCTRL|0x80)) { 187 | #ifdef DEBUG 188 | caos_printf("left-ctrl released\n"); 189 | #endif 190 | tmp = MK_CTRL; 191 | key.status &= ~tmp; 192 | change_flag = 1; 193 | } else if (scan == SCAN_LEFTALT) { 194 | #ifdef DEBUG 195 | caos_printf("alt pressed\n"); 196 | #endif 197 | tmp = MK_ALT; 198 | key.status |= tmp; 199 | change_flag = 1; 200 | } else if (scan == (SCAN_LEFTALT|0x80)) { 201 | #ifdef DEBUG 202 | caos_printf("alt released\n"); 203 | #endif 204 | tmp = MK_ALT; 205 | key.status &= ~tmp; 206 | change_flag = 1; 207 | } 208 | 209 | if (change_flag != 0) { 210 | // change keyboard LED 211 | // 212 | return; 213 | } 214 | 215 | // 216 | // Don't process key-releasing 217 | if (scan & 0x80) 218 | return; 219 | 220 | 221 | /* 222 | * if no status, scan_to_ascii[0][scan] 223 | * if capslock, scan_to_ascii[1][scan] 224 | * ... ... 225 | */ 226 | if ( (key.status & MK_CAPSLOCK) && (key.status & MK_SHIFT) ) 227 | key.code = scan_to_ascii[TABLE_CAPS_N_SHIFT][scan]; 228 | else if (key.status == 0) 229 | key.code = scan_to_ascii[TABLE_NORMAL][scan]; 230 | else if (key.status & MK_CAPSLOCK) 231 | key.code = scan_to_ascii[TABLE_CAPSLOCK][scan]; 232 | else if (key.status & MK_SHIFT) 233 | key.code = scan_to_ascii[TABLE_SHIFT][scan]; 234 | else if (key.status & MK_CTRL) 235 | key.code = scan_to_ascii[TABLE_CTRL][scan]; 236 | else 237 | key.code = 0xff; // 0xff is error code 238 | 239 | 240 | if (scan == SCAN_ENTER) { 241 | caos_printf("\n"); 242 | return; 243 | } else if (scan == SCAN_BACKSPACE) { 244 | caos_delchar(1); 245 | return; 246 | } 247 | 248 | 249 | caos_printf("%c", key.code); 250 | 251 | 252 | prefix = 0; 253 | 254 | 255 | } 256 | 257 | 258 | 259 | 260 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 | 270 | -------------------------------------------------------------------------------- /src/ld-script.ld: -------------------------------------------------------------------------------- 1 | OUTPUT_FORMAT(elf64-x86-64) 2 | ENTRY(start_kernel) 3 | SECTIONS 4 | { 5 | . = KERNEL_VMA; 6 | 7 | . = ALIGN(4096); 8 | .text : AT(ADDR(.text) - KERNEL_VMA) 9 | { 10 | _code_start = .; 11 | *(.text) 12 | *(.rodata*) 13 | } 14 | 15 | _code_end = .; 16 | 17 | . = ALIGN(4096); 18 | .data : AT(ADDR(.data) - KERNEL_VMA) 19 | { 20 | _data_start = .; 21 | *(.data) 22 | 23 | _per_cpu_start = .; 24 | *(.data.percpu) 25 | _per_cpu_end = .; 26 | } 27 | 28 | _data_end = .; 29 | 30 | 31 | 32 | . = ALIGN(4096); 33 | .bss : AT(ADDR(.bss) - KERNEL_VMA) 34 | { 35 | _bss_start = .; 36 | *(.bss) 37 | } 38 | 39 | _bss_end = .; 40 | 41 | _kernel_end = .; 42 | 43 | /DISCARD/ : 44 | { 45 | *(.comment) 46 | } 47 | 48 | . = KERNEL_STACK_START; 49 | } 50 | -------------------------------------------------------------------------------- /src/main.c: -------------------------------------------------------------------------------- 1 | 2 | 3 | #include 4 | #include 5 | #include // setup_arch() 6 | #include // cli() 7 | #include 8 | #include // contig_page_data 9 | #include // alloc_pages() 10 | #include // kmem_cache_init(), kmalloc 11 | #include // init_bsp_APIC, wake_ap 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include // mm_struct 17 | #include // 18 | #include // irq_init 19 | #include // pic8259_init 20 | #include // io_apic_init 21 | 22 | void start_kernel(size_t index) 23 | { 24 | 25 | // 26 | // step 1. disable interrupts for system initialization 27 | // 28 | cli(); 29 | 30 | 31 | // checking CPU working 32 | if (index == 0) { 33 | init_screen(); 34 | caos_printf("Hello! I am BSP!!\n"); 35 | } else { 36 | caos_printf("Hello!! I am AP!! I am running??\n"); 37 | while (1) { 38 | screen_info.video_mem[79]++; 39 | 40 | } 41 | } 42 | 43 | 44 | // 6 arguments are stored in register, 45 | // and others are stored in stack memory. 46 | // Therefore if there is not type-specifier, 47 | // compiler cannot know how many byte is valid data in stack. 48 | // If arguments 6UL, 7UL is 6, 7 without type-specifier, 49 | // output data is the thrash data from stack with 6 at al or dl register. 50 | caos_printf("Hello, CaOS. Test printf <%d,%d,%d,%d,%d,%d,0x%x>\n", 0, 1, -3U, -4L, -5, 6UL, 0xaUL); // variable list 51 | 52 | caos_printf("size int=%d, long=%d, long long=%d\n", sizeof(int), sizeof(long), sizeof(long long)); 53 | 54 | 55 | { 56 | u64 *entry = (u64 *)0xFFFF800000090000; 57 | 58 | caos_printf("PML4[0]=%x, PDP[0]=%x\n PDE[0]=%x, PTE[0]=%x\n", 59 | *entry, *(entry+512), *(entry+1024), *(entry+1536)); 60 | } 61 | 62 | 63 | // 64 | // step 2. processor 65 | // 66 | 67 | // 68 | // Booting parameters 69 | // GDT, IDT 70 | // Paging-Tables 71 | // memory layout, page management 72 | // 73 | // Linear address is enabled after setup_arch() 74 | // 75 | setup_arch(); 76 | 77 | 78 | // 79 | // step 3. memory management 80 | // 81 | 82 | // setup zones/nodes of system 83 | // Now page allocator is available. 84 | memory_init(phy_mem_size); 85 | 86 | // 87 | // setup memory allocator 88 | // 89 | kmem_cache_init(); 90 | 91 | 92 | 93 | // 94 | // step 4. interrupt 95 | // 96 | 97 | // 98 | // external IRQs 99 | // current IRQs are accepted via 8259A, 100 | // but I/O APIC will be used instead. 101 | // 102 | 103 | // init local APIC of BSP processor 104 | init_bsp_APIC(); 105 | 106 | //pic8259_init(); 107 | io_apic_init(); // not implemented yet 108 | 109 | irq_init(); 110 | 111 | 112 | 113 | 114 | 115 | 116 | // 117 | // step 5. multi-processor 118 | // 119 | 120 | // prepare smp execution 121 | smp_init(); 122 | 123 | // BSP's local timer 124 | init_bsp_timer(); 125 | 126 | // wake AP (second processor) 127 | wake_ap(); 128 | 129 | 130 | 131 | // 132 | // step 6. process management 133 | // 134 | caos_printf("\n### MAKE PROCESS MANAGEMENT!! ###\n"); 135 | 136 | 137 | 138 | // 139 | // step 7. devices, shell 140 | // 141 | 142 | keyboard_init(); 143 | 144 | 145 | // kernel booting ends...ready to run init-thread 146 | sti(); 147 | 148 | 149 | while(1) ; 150 | } 151 | 152 | 153 | 154 | 155 | -------------------------------------------------------------------------------- /src/memory.c: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | #include 5 | 6 | #include // struct list_head 7 | #include 8 | 9 | 10 | 11 | #define DEBUG 1 12 | //#undef DEBUG 13 | 14 | #define ONE_MB (1024*1024) 15 | 16 | static char *zone_names[MAX_NR_ZONES] = {"NORMAL"}; 17 | 18 | 19 | // x86 has only one node 20 | pg_data_t contig_page_data; 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | // 29 | // setup memory node & zone 30 | // @phy_mem_size: physical memory size 31 | // 32 | void memory_init(size_t phy_mem_size) 33 | { 34 | struct zone *z; 35 | size_t l; 36 | 37 | struct list_head *head; 38 | struct page *pg; 39 | 40 | // 41 | // system node setup 42 | // 43 | 44 | contig_page_data.nr_zones = MAX_NR_ZONES; 45 | contig_page_data.node_mem_map = mem_map; 46 | contig_page_data.node_start_paddr = 0; 47 | contig_page_data.node_size = phy_mem_size*ONE_MB; 48 | 49 | // nodes are for NUMA & SMP system. 50 | // These are reserved for future. 51 | contig_page_data.node_id = 0; 52 | contig_page_data.node_next = NULL; // only node 53 | 54 | 55 | // 56 | // zone setup 57 | // 58 | 59 | z = &contig_page_data.node_zones[ZONE_NORMAL]; 60 | 61 | z->size = contig_page_data.node_size; // size 62 | z->zone_pgdat = &contig_page_data; // including node 63 | z->zone_start_paddr = contig_page_data.node_start_paddr; // physical memory address 64 | z->name = zone_names[ZONE_NORMAL]; // name 65 | 66 | z->pages = contig_page_data.node_size / PAGE_SIZE; // included page count 67 | 68 | // the first page index 69 | z->zone_start_pfn = (size_t)(contig_page_data.node_mem_map - mem_map); 70 | 71 | // descriptor of the first page belongs to the zone 72 | z->zone_mem_map = &mem_map[z->zone_start_pfn]; 73 | 74 | // 75 | // Pages in the same zone is linked together 76 | // 77 | for (l=z->zone_start_pfn; lpages; l++) { 78 | list_add_tail(&mem_map[l].list, &(z->zone_mem_map->list) ); 79 | mem_map[l].page_zone = z; 80 | 81 | // what is this for?? 82 | //if (mem_map[l].count != 0) { 83 | // mem_map[l].private = -1; 84 | //} 85 | } 86 | 87 | // count free pages in the zone 88 | head = &contig_page_data.node_mem_map[0].list; 89 | list_for_each_entry(pg, head, list) { 90 | if (pg->count == 0) 91 | (z->free_pages)++; 92 | } 93 | 94 | 95 | #ifdef DEBUG 96 | caos_printf("zone[%s] size=%d, mem_map=%x, free=%d\n", 97 | z->name, z->size, z->zone_mem_map, z->free_pages); 98 | #endif 99 | 100 | 101 | 102 | } 103 | 104 | 105 | 106 | 107 | -------------------------------------------------------------------------------- /src/page_alloc.c: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | 9 | #include 10 | 11 | #define DEBUG 1 12 | #undef DEBUG 13 | 14 | 15 | 16 | 17 | // 18 | // allocate pages in order-number and return page-descriptor of the first free-page 19 | // @gfp_mask: page attributes 20 | // @order: power of two of allocation size in pages, 21 | // 0 is a single page, 3 is 2^3=8 pages 22 | // 23 | struct page *alloc_pages(flag_t gfp_mask, size_t order) 24 | { 25 | if (order > MAX_PAGE_ORDER) 26 | return NULL; 27 | 28 | // 29 | // gfp_mask processing should be here 30 | // According to the gfp_mask, node is selected if there are several nodes. 31 | // 32 | 33 | // only one node is considered yet. 34 | return __alloc_pages(gfp_mask, order, contig_page_data.node_zones); 35 | 36 | } 37 | 38 | 39 | 40 | // 41 | // heart of alloc_pages 42 | // @gfp_mask: page attributes 43 | // @order: power of two of allocation size in pages, 44 | // @zonelist: a list memory zone which has free pages 45 | // 46 | struct page *__alloc_pages(flag_t gfp_mask, size_t order, struct zone *zonelist) 47 | { 48 | struct page *map; 49 | struct zone *zone; 50 | 51 | size_t first, last; 52 | size_t count = (1UL< count) { 63 | zone = &zonelist[i]; 64 | map = zone->zone_mem_map; 65 | break; 66 | } 67 | } 68 | 69 | // not enough pages 70 | if (i >= MAX_NR_ZONES) return NULL; 71 | 72 | 73 | 74 | // 75 | // Here should come critical-section processing!!! 76 | // 77 | 78 | 79 | // find sequence of free pages in the zone 80 | for (first = 0; first < zone->pages; first++) { 81 | // find a free page 82 | if (map[first].count != 0) { 83 | continue; 84 | } 85 | 86 | 87 | // map[first]~map[first+count] are free? 88 | for (last=0; last 0) { 91 | first += last; 92 | break; 93 | } 94 | } 95 | 96 | 97 | // found enough space 98 | if (last == count) { 99 | #ifdef DEBUG 100 | caos_printf("alloc_pages(%x~%x) ", first, first+last-1); 101 | #endif 102 | // increase usage-counter of every allocated pages 103 | for (last=0; lastfree_pages = zone->free_pages - count; 109 | 110 | // number of pages which are allocated together 111 | map[first].private = order; 112 | 113 | #ifdef DEBUG 114 | caos_printf("[%x]private=%d\n", map+first, map[first].private); 115 | #endif 116 | 117 | 118 | 119 | // following pages are free, return page pointer 120 | return map + first; 121 | } // if(last==count) 122 | 123 | 124 | } 125 | 126 | // the number of free-pages is enough 127 | // but free-pages in the zone is not sequential. 128 | // go to next zone 129 | if (i < MAX_NR_ZONES) { 130 | i++; 131 | goto FIND_ZONE; 132 | } 133 | 134 | // it never come to here! 135 | return NULL; 136 | } 137 | 138 | 139 | // 140 | // allocate pages in order-number and return linear address of the first free-page 141 | // @gfp_mask: page attributes 142 | // @order: power of two of allocation size in pages, 143 | // 144 | u64 __get_free_pages(flag_t gfp_mask, size_t order) 145 | { 146 | struct page *pg; 147 | 148 | 149 | if (order > MAX_PAGE_ORDER) 150 | return (u64)NULL; 151 | 152 | pg = __alloc_pages(gfp_mask, order, contig_page_data.node_zones); 153 | 154 | #ifdef DEBUG 155 | caos_printf("get_free_pages : %x..OK\n", (size_t)pg->index); 156 | #endif 157 | 158 | return page_to_virt(pg); 159 | } 160 | 161 | 162 | 163 | // 164 | // free pages in order-number, linear address is necessary 165 | // @addr: linear address of the first page 166 | // @order: power of two of pages to be free 167 | // 168 | void free_pages(u64 addr, size_t order) 169 | { 170 | 171 | if (order > MAX_PAGE_ORDER) 172 | return; 173 | 174 | 175 | __free_pages(virt_to_page(addr), order); 176 | 177 | } 178 | 179 | 180 | 181 | 182 | // 183 | // free pages in order-number 184 | // @page: page descriptor of the first page 185 | // @order: power of two of pages to be free 186 | // 187 | void __free_pages(struct page *page, size_t order) 188 | { 189 | 190 | size_t i; 191 | size_t pg_count = 1< MAX_PAGE_ORDER) 196 | return; 197 | 198 | if (page->count <= 0) { 199 | caos_printf("free-pages fail. page[%x] is not allocated pages.\n", page); 200 | return; 201 | } 202 | 203 | if (page->private != order) { 204 | caos_printf("allocate-order is not same to free-order for page[%d]!!\n", page-mem_map); 205 | return; 206 | } 207 | 208 | 209 | zone = page->page_zone; 210 | 211 | #ifdef DEBUG 212 | 213 | do { 214 | size_t first = (size_t)(page - zone->zone_mem_map); 215 | size_t last = first+(1< at page[%d]\n", page-mem_map); 234 | } 235 | 236 | page[i].count--; 237 | 238 | if (page[i].count == 0) { 239 | zone->free_pages++; 240 | } 241 | 242 | } 243 | 244 | // page-bulk are freed 245 | if (page->count == 0) { 246 | page->private = -1; 247 | } 248 | 249 | 250 | } 251 | 252 | -------------------------------------------------------------------------------- /src/percpu.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include 6 | #include // init_mm 7 | #include // PAGE_SIZE 8 | #include // alloc_ages 9 | #include // memcpy 10 | #include // NR_CPUS 11 | 12 | 13 | 14 | #define DEBUG 1 15 | #undef DEBUG 16 | 17 | 18 | // 19 | // !! This must be moved to the CPU-descriptor 20 | // 21 | size_t cpu_offset[5]; 22 | 23 | 24 | // 25 | // The address of per-cpu array. 26 | // The per-cpu array is the NR_CPUS-copies of the .data.percpu section of kernel-image 27 | // If 5 cores are there, 5 copies of .data.percpu are there in per-cpu array. 28 | // 29 | static char *percpu_buf; 30 | 31 | 32 | 33 | 34 | 35 | /* 36 | * implementation of linux-2.6.29 37 | * 38 | #define RELOC_HIDE(ptr, off) \ 39 | ({ ssize_t __ptr;\ 40 | __ptr = (ssize_t)(ptr);\ 41 | (typeof(ptr))(__ptr + (off)); }) 42 | 43 | #define per_cpu(var, cpu) (*(RELOC_HIDE(&per_cpu__##var, per_cpu_offset(cpu)))) 44 | */ 45 | 46 | 47 | 48 | // 49 | // return cpu-offset 50 | // !! this must be modified to get cpu-offset from the CPU-descriptor 51 | #define per_cpu_offset(cpu) cpu_offset[cpu] 52 | 53 | // 54 | // get the address of per-cpu data in per-cpu array 55 | // by adding cpu-offset to the original address of per-cpu data 56 | // 57 | #define per_cpu(var, cpu) (*((typeof(&per_cpu__##var))((u64)&per_cpu__##var + per_cpu_offset(cpu)))) 58 | 59 | 60 | // 61 | // test data 62 | DEFINE_PER_CPU(long, cpu_id1) = 5; 63 | DEFINE_PER_CPU(long, cpu_id2) = 6; 64 | DEFINE_PER_CPU(long, cpu_id3) = 7; 65 | DEFINE_PER_CPU(long, cpu_id4) = 8; 66 | DEFINE_PER_CPU(long, cpu_id5) = 9; 67 | 68 | 69 | // 70 | // setup per-cpu array. 71 | // This copies .data.percpu section of the kernel-image NR_CPU times, 72 | // so that per-cpu array has NR_CPUS entries of per-cpu data. 73 | // 74 | void setup_per_cpu_areas(void) 75 | { 76 | u64 *p = (u64 *)init_mm.start_percpu; 77 | size_t percpu_size = init_mm.end_percpu - init_mm.start_percpu; 78 | struct page *percpu_page; 79 | ssize_t i; 80 | 81 | 82 | // test: .data.percpu section is OK? 83 | caos_printf("per-cpu section: %x ~ %x (%d-bytes)\n", 84 | init_mm.start_percpu, init_mm.end_percpu, 85 | init_mm.end_percpu-init_mm.start_percpu); 86 | caos_printf("TEST PER-CPU SECTION: 5 == %d?\n", *p); 87 | 88 | 89 | 90 | // buffer for per-cpu array 91 | percpu_page = alloc_pages(0, PAGE_ORDER((percpu_size/PAGE_SIZE) * NR_CPUS)); 92 | percpu_buf = (char *)page_to_virt(percpu_page); 93 | 94 | #if defined(DEBUG) 95 | // test: per-cpu buffer is OK? 96 | caos_printf("order->%d\n", PAGE_ORDER((percpu_size/PAGE_SIZE) * NR_CPUS)); 97 | caos_printf("%d-pages at %x\n", percpu_page->private, percpu_buf); 98 | #endif 99 | 100 | // 101 | // copy .data.percpu section NR_CPUS-times 102 | // 103 | 104 | //for (i=0; i>> %x\n", (u64)&per_cpu__cpu_id1 + cpu_offset[0]); 122 | caos_printf("cpu0 id1 5=%x, %x\n", per_cpu(cpu_id1, 0), &per_cpu(cpu_id1, 0)); 123 | caos_printf("cpu0 id2 6=%x, %x\n", per_cpu(cpu_id2, 0), &per_cpu(cpu_id2, 0)); 124 | caos_printf("cpu0 id3 7=%x, %x\n", per_cpu(cpu_id3, 0), &per_cpu(cpu_id3, 0)); 125 | caos_printf("cpu0 id4 8=%x, %x\n", per_cpu(cpu_id4, 0), &per_cpu(cpu_id4, 0)); 126 | caos_printf("cpu0 id5 9=%x, %x\n", per_cpu(cpu_id5, 0), &per_cpu(cpu_id5, 0)); 127 | caos_printf("cpu1 id1 5=%x, %x\n", per_cpu(cpu_id1, 1), &per_cpu(cpu_id1, 1)); 128 | caos_printf("cpu2 id1 5=%x, %x\n", per_cpu(cpu_id1, 2), &per_cpu(cpu_id1, 2)); 129 | #endif 130 | 131 | 132 | } 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | -------------------------------------------------------------------------------- /src/pic8259.c: -------------------------------------------------------------------------------- 1 | 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #include 8 | 9 | 10 | // 2nd chnnel of 8259a which is connected to 1st 8259a 11 | // should be unmasked initially. 12 | u16 irq_mask = 0xfffb; 13 | 14 | #define irq_mask0_7 (unsigned char)(irq_mask&0xff) 15 | #define irq_mask8_15 (unsigned char)((irq_mask>>8)&0xff) 16 | 17 | 18 | 19 | // 20 | // activate PIC8259A 21 | // IRQ base vector is 0x20 and 16 IRQs are supported. 22 | // 23 | void pic8259_init(void) 24 | { 25 | 26 | //--------- 8259A initialization starts -------------- 27 | 28 | /* COMMAND: initialize hardware interrupt base vector... */ 29 | outb( 0x20, 0x11 ); // you are master mode 30 | outb( 0xa0, 0x11 ); // you are slave mode 31 | 32 | // VALUE: base vector number 33 | outb( 0x21, VECTOR_BASE ); // vector 0x20~0x27 34 | outb( 0xa1, VECTOR_BASE ); // vector 0x28~0x2F 35 | 36 | // COMMAND: cascade mode 37 | outb( 0x21, 0x04 ); // master's IRQ#2 is connected to slave 38 | outb( 0xa1, 0x02 ); // slave is connected to master's IRQ#2 39 | 40 | // COMMAND: working mode 41 | outb( 0x21, 0x01 ); // 8086 mode 42 | outb( 0xa1, 0x01 ); // 8086 mode 43 | 44 | //--------- 8259A initialization is over -------------- 45 | 46 | // mask all IRQs now 47 | outb( 0x21, irq_mask0_7 ); // mask 0~1,3~7 IRQs 48 | outb( 0xa1, irq_mask8_15 ); // mask 8~15 IRQs 49 | 50 | 51 | } 52 | 53 | 54 | /* 55 | * enable specified IRQ by store mask bit. 56 | * @irq: irq number 57 | */ 58 | void enable_pic8259(size_t irq) 59 | { 60 | irq_mask = irq_mask & ~(1<= 8 ) 63 | outb( 0xa1, irq_mask8_15 ); 64 | else 65 | outb( 0x21, irq_mask0_7 ); 66 | } 67 | 68 | /* 69 | * disable specified irq by set mask bit 70 | * @irq: irq number 71 | */ 72 | void disable_pic8259(size_t irq) 73 | { 74 | irq_mask = irq_mask | (1<= 8 ) 77 | outb( 0xa1, irq_mask8_15 ); 78 | else 79 | outb( 0x21, irq_mask0_7 ); 80 | } 81 | 82 | 83 | // 84 | // acknowledge PIC8259 to accept following IRQs 85 | // 86 | void ack_pic8259(void) 87 | { 88 | outb(0x20, 0x20); // EOI to master 89 | outb(0xa0, 0x20); // EOI to slave 90 | } 91 | 92 | 93 | 94 | 95 | -------------------------------------------------------------------------------- /src/printf.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include // test_bit 7 | 8 | 9 | 10 | 11 | // 12 | // Print one character on screen, only black-on-white color is supported. 13 | // Then cursor move forward by a column 14 | // @A_byteChar: ascii code 15 | // 16 | void caos_putchar(char A_byteChar) 17 | { 18 | screen_info.video_mem[screen_info.cursor_offset] = (unsigned short)(BG_BLACK|A_byteChar); 19 | screen_info.cursor_offset++; 20 | set_cursor(screen_info.cursor_offset); 21 | } 22 | 23 | 24 | // 25 | // Delete cnt-characters on screen and move cursor backward by a column 26 | // @cnt: number of characters to be deleted. 27 | // 28 | void caos_delchar(ssize_t cnt) 29 | { 30 | 31 | for ( ; cnt > 0; cnt--) { 32 | screen_info.cursor_offset--; 33 | set_cursor(screen_info.cursor_offset); 34 | screen_info.video_mem[screen_info.cursor_offset] = (unsigned short)(BG_BLACK); 35 | } 36 | 37 | 38 | } 39 | 40 | 41 | /* 42 | * printf implementation refers to http://wiki.osdev.org/Printing_to_Screen 43 | */ 44 | 45 | 46 | // 47 | // memory buffer, printable string is stored by vsprintf. 48 | // 49 | static char sz[128]; 50 | 51 | // 52 | // asmlinkage keyword is useless for x86_64 53 | // because every parameter is passed in register 54 | // Every parameter is 64bit long type. 55 | // @format: format string includes format-specifier and escape-sequences. 56 | // return: the number of printed character 57 | // 58 | ssize_t caos_printf(const char *format, ...) 59 | { 60 | va_list ap; 61 | ssize_t i = 0; 62 | 63 | 64 | /* 65 | // 66 | // < test code > 67 | // 68 | // function arguments are passed as long type? 69 | // 70 | // case : caos_printf("%x\n", 0x123456789abcdef1UL) 71 | // rsi <= 0x123456789abcdef1UL 72 | // therefore, arguments are long type 73 | // 74 | do { 75 | unsigned long rsi; 76 | __asm__ __volatile__ ("movq %%rsi, %0": :"a"(rsi)); 77 | i = print_hex(sz, rsi); 78 | sz[i] = '\0'; 79 | } while (0); 80 | */ 81 | 82 | 83 | va_start(ap, format); 84 | 85 | // format specifier (%d,%c,%s,%x) 86 | // Every format-specifier is translated 87 | // and printable string is stored at sz. 88 | caos_vsprintf(sz, format, ap); 89 | va_end(ap); 90 | 91 | i = 0; 92 | 93 | // escape character is printed now. 94 | while (sz[i] != '\0') { 95 | if (sz[i] == '\n') { 96 | // move to next line 97 | set_cursor( ((size_t)(screen_info.cursor_offset/SCREEN_COL) + 1)*SCREEN_COL ); 98 | i++; 99 | continue; 100 | } else if (sz[i] == '\b') { 101 | // delete one character 102 | caos_delchar(1); 103 | i++; 104 | continue; 105 | } 106 | 107 | caos_putchar(sz[i++]); 108 | } 109 | 110 | return i; 111 | } 112 | 113 | 114 | // 115 | // translate hexadecimal value to string 116 | // @buf: buffer to store translated string 117 | // @a: hexadecimal value to be translated 118 | // return: the length of output string 119 | // 120 | ssize_t print_hex(char *buf, ssize_t a) 121 | { 122 | unsigned char *p; 123 | unsigned char v[32]; 124 | ssize_t i=0, j=0; 125 | ssize_t count=0; 126 | 127 | // zero 128 | if (a == 0) { 129 | *buf = 0x30; 130 | return 1; 131 | } 132 | 133 | p = (unsigned char *)&a; 134 | 135 | for (i = sizeof(ssize_t); i > 0; i--) { 136 | if ( (p[i-1] >> 4) <= 9) 137 | v[count] = (p[i-1] >> 4) + 0x30; 138 | else 139 | v[count] = (p[i-1] >> 4) + 0x37; 140 | count++; 141 | 142 | if ( (p[i-1] & 0x0f) <= 9) 143 | v[count] = (p[i-1] & 0x0f) + 0x30; 144 | else 145 | v[count] = (p[i-1] & 0x0f) + 0x37; 146 | count++; 147 | } 148 | 149 | 150 | i=0; 151 | while (v[i] == '0') // skip initial zeros 152 | i++; 153 | 154 | count = sizeof(ssize_t)*2 - i; // how many digits 155 | for (j=0; j 0) { 243 | v[i++] = a % 10; 244 | a /= 10; 245 | } 246 | 247 | for (--i; i >= 0; i--) { 248 | *A_szBuffer++ = v[i]+(char)'0'; 249 | count++; 250 | } 251 | 252 | 253 | return count; 254 | } 255 | 256 | 257 | 258 | // 259 | // caos_sprintf do not print message on display 260 | // and store message in memory buffer. 261 | // 262 | ssize_t caos_sprintf(char *outbuf, const char *format, ...) 263 | { 264 | va_list ap; 265 | ssize_t i = 0; 266 | 267 | 268 | va_start(ap, format); 269 | caos_vsprintf(outbuf, format, ap); 270 | va_end(ap); 271 | 272 | return i; 273 | } 274 | 275 | 276 | -------------------------------------------------------------------------------- /src/process.c: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | /* 5 | * 6 | * process management 7 | * 8 | * 1. How the processor manages threads. 9 | * - TSS or something? 10 | * 11 | * 2. How the switching between kernel-stack 12 | * and user-stack works? 13 | * - register restoring 14 | * - Where is the kernel-stack address? 15 | * 16 | * 3. Make a user-thread and executes it. 17 | * 18 | * 4. Make context-switching 19 | * 20 | * 5. Make multi-threads 21 | * 22 | */ 23 | 24 | 25 | #include 26 | 27 | 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /src/screen.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | 6 | 7 | 8 | struct screen_info screen_info; 9 | 10 | 11 | 12 | /* 13 | * scroll screen by line-lines 14 | * @line: number of lines to scroll 15 | */ 16 | void scroll_screen(ssize_t line) 17 | { 18 | ssize_t i; 19 | volatile u16 *src = &screen_info.video_mem[line*SCREEN_COL]; 20 | 21 | if (line > SCREEN_ROW-1) 22 | return; 23 | 24 | // scroll X line => remove 0 ~ (X-1) lines 25 | // and move X ~ SCREEN_ROW lines to 0 ~ (X-1) lines 26 | for (i = 0; i < (SCREEN_ROW-line)*SCREEN_COL; i++) 27 | screen_info.video_mem[i] = src[i]; 28 | 29 | // remain area is removed 30 | for (; i < SCREEN_ROW*SCREEN_COL; i++) 31 | screen_info.video_mem[i] = BG_BLACK; 32 | 33 | } 34 | 35 | 36 | 37 | /* 38 | * clear entire screen 39 | */ 40 | void clear_screen(void) 41 | { 42 | ssize_t i; 43 | 44 | // copy 4 byte per one loop 45 | for (i=0; i= SCREEN_ROW) { 82 | scroll_screen(1); 83 | screen_info.cursor_offset -= SCREEN_COL; 84 | } 85 | 86 | // CRT port: 0x3d4 & 0x3d5 87 | dwTemp = (u8)(screen_info.cursor_offset >> 8); 88 | __outb((unsigned short)0x3d4, (unsigned char)0x0e); // high byte 89 | __outb((unsigned short)0x3d5, (unsigned char)dwTemp); 90 | 91 | dwTemp = (u8)(screen_info.cursor_offset & (u8)0xff); 92 | __outb((unsigned short)0x3d4, 0x0f); // low byte 93 | __outb((unsigned short)0x3d5, (u8)dwTemp); 94 | 95 | } 96 | 97 | 98 | -------------------------------------------------------------------------------- /src/setup.c: -------------------------------------------------------------------------------- 1 | 2 | 3 | /* 4 | * The boot-time setup-routine, setup.asm, build boot-parameter for HW architecture. 5 | * 6 | * This file then handles the architecture-dependent parts of initialization. 7 | * 8 | */ 9 | 10 | 11 | #include 12 | #include 13 | 14 | #include // struct cpuinfo_x86 15 | #include // cpuid() 16 | 17 | #include // bootmem_init() 18 | #include // node_init() 19 | 20 | #include // PAGE_OFFSET 21 | 22 | 23 | #include 24 | #include 25 | 26 | #include 27 | #include // phys_to_virt 28 | #include 29 | 30 | #include // apic_init 31 | #include // irq_init 32 | #include // pic8259_init 33 | #include // wake_ap 34 | 35 | 36 | 37 | 38 | #define DEBUG 1 39 | #undef DEBUG 40 | 41 | 42 | 43 | 44 | // 45 | // memory status of #0 process, swapper 46 | // The swapper process is the kernel itself. 47 | // 48 | struct mm_struct init_mm; 49 | 50 | 51 | struct cpuinfo_x86 boot_cpu_data; 52 | 53 | size_t phy_mem_size; 54 | u64 boot_gdt; 55 | 56 | 57 | 58 | // 59 | // processor-dependent initializations for x86_64 60 | // 61 | void setup_arch(void) 62 | { 63 | u64 *boot_params = BOOT_PARAMS; 64 | 65 | 66 | 67 | 68 | // booting-parameter 69 | phy_mem_size = boot_params[PARAMS_OFFSET_PHYMEM_SIZE]; 70 | boot_gdt = boot_params[PARAMS_OFFSET_BOOT_GDT]; 71 | 72 | 73 | 74 | // init_mm initialization 75 | 76 | // BIOS/ISA video area - this will be manages as resource in future 77 | init_mm.start_reserved = boot_params[PARAMS_OFFSET_START_VIDEO]; 78 | init_mm.end_reserved = boot_params[PARAMS_OFFSET_END_VIDEO]; 79 | 80 | // kernel-image map 81 | init_mm.start_code = boot_params[PARAMS_OFFSET_START_CODE]; 82 | init_mm.end_code = boot_params[PARAMS_OFFSET_END_CODE]; 83 | init_mm.start_data = boot_params[PARAMS_OFFSET_START_DATA]; 84 | init_mm.end_data = boot_params[PARAMS_OFFSET_END_DATA]; 85 | init_mm.start_bss = boot_params[PARAMS_OFFSET_START_BSS]; 86 | init_mm.end_bss = boot_params[PARAMS_OFFSET_END_BSS]; 87 | init_mm.start_brk = boot_params[PARAMS_OFFSET_END_KERNEL]; // end of kernel image 88 | 89 | // per-cpu data section 90 | init_mm.start_percpu = boot_params[PARAMS_OFFSET_START_PERCPU]; 91 | init_mm.end_percpu = boot_params[PARAMS_OFFSET_END_PERCPU]; 92 | 93 | // for BSP's initialization, such as building paging tables, mem_map... 94 | init_mm.start_stack = KERNEL_STACK_START; 95 | init_mm.start_heap = KERNEL_STACK_START; 96 | init_mm.end_heap = (u64)phys_to_virt(boot_params[PARAMS_OFFSET_BOOT_SIZE]*0x100000); 97 | 98 | 99 | 100 | #ifdef DEBUG 101 | caos_printf("%x %x %x %x\n", init_mm.start_code, init_mm.start_data, init_mm.start_bss, init_mm.start_brk); 102 | caos_printf("%x %x\n", init_mm.start_heap, init_mm.end_heap); 103 | #endif 104 | 105 | 106 | // struct resource code_resource, data_resource 107 | 108 | 109 | 110 | 111 | // early_identify_cpu() - boot CPU information at struct cpuinfo_x86 boot_cpu_data 112 | early_identify_cpu(&boot_cpu_data); 113 | 114 | 115 | 116 | // e820 handling comes here in future 117 | 118 | 119 | 120 | 121 | // booting memory allocator - reserved or occufied memory for kernel and initial data 122 | bootmem_init(); 123 | 124 | 125 | // build GDT, IDT 126 | gdt_init(boot_gdt); 127 | idt_init(); 128 | 129 | // rebuild paging-tables, PGD/PUD/PMD/PTEs 130 | paging_init(phy_mem_size); // build paging-tables 131 | 132 | 133 | 134 | 135 | // 136 | // current page status if memory size is 128MB 137 | // 138 | // 0x9F ~ 0xFF: BIOS 139 | // 0x100 ~ 0x1FF: KERNEL 140 | // 0x200: GDT 141 | // 0x201: TSS 142 | // 0x202: IDT 143 | // 0x203: PGD 144 | // 0x204: PUD 145 | // 0x205: PMD 146 | // 0x206 ~ 0x245: PTE (128MB) 147 | // 0x246: PMD_reserv 148 | // 0x247 ~ 0x250: PTE_reserv 149 | // 0x251 ~ 0x491: mem_map (128MB) 150 | // 151 | 152 | 153 | 154 | // ACPI/SMP/E820 map handling - not implemented yet 155 | 156 | 157 | 158 | // SMP initialization 159 | mp_spec_init(); 160 | 161 | 162 | // build mem_map - page descriptor table 163 | // mem_map_init must be placed at the end of booting memory users 164 | mem_map_init(); 165 | 166 | // 167 | // Now, booting memory allocator is disabled 168 | // 169 | 170 | 171 | } 172 | 173 | 174 | 175 | 176 | // 177 | // identify CPU vendor. 178 | // Detail processor identification will be implemented 179 | // in identify_cpu() function in future. 180 | // 181 | void early_identify_cpu(struct cpuinfo_x86 *cpu) 182 | { 183 | 184 | cpu->x86_cache_size = -1; 185 | cpu->x86_vendor = X86_VENDOR_UNKNOWN; // unknown yet 186 | //cpu->x86_model = 0; 187 | cpu->x86_vendor_id[0] = '\0'; 188 | //cpu->x86_model_id[0] = '\0'; 189 | cpu->x86_cache_alignment = 64; // hard-coding, bad! 190 | cpu->x86_max_cores = 4; // more than 4-core is not considered. 191 | 192 | 193 | 194 | // cpuid instruction, refer to CPUID manual 195 | cpuid(0x00000000, (unsigned int *)&cpu->cpuid_level, 196 | (unsigned int *)&cpu->x86_vendor_id[0], 197 | (unsigned int *)&cpu->x86_vendor_id[8], 198 | (unsigned int *)&cpu->x86_vendor_id[4]); 199 | 200 | if (cpu->x86_vendor_id[9] == 'A' && \ 201 | cpu->x86_vendor_id[10] == 'M' && \ 202 | cpu->x86_vendor_id[11] == 'D') 203 | cpu->x86_vendor = X86_VENDOR_AMD; 204 | else if (cpu->x86_vendor_id[7] == 'I' && \ 205 | cpu->x86_vendor_id[8] == 'n' && \ 206 | cpu->x86_vendor_id[9] == 't' && \ 207 | cpu->x86_vendor_id[10] == 'e' && \ 208 | cpu->x86_vendor_id[11] == 'l') 209 | cpu->x86_vendor = X86_VENDOR_INTEL; 210 | 211 | caos_printf("CPU VENDOR=%s\n", cpu->x86_vendor_id); 212 | 213 | 214 | } 215 | 216 | 217 | 218 | 219 | -------------------------------------------------------------------------------- /src/smp.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | 8 | ssize_t preempt_count; 9 | 10 | 11 | 12 | // 13 | // clock estimation will be implemented later.. 14 | // This delay does just delay-loop 15 | // 16 | static void delay(size_t count) 17 | { 18 | volatile s64 a = -1; 19 | 20 | for (; count > 0; count--) { 21 | for (; a > 0; a--) 22 | continue; 23 | } 24 | 25 | 26 | } 27 | 28 | 29 | 30 | 31 | // 32 | // send Startup IPIs to AP 33 | // refer to INTEL PROCESSOR MANUAL vol.2 & MP specification 34 | // 35 | void wake_ap(void) 36 | { 37 | 38 | 39 | // 40 | // Interrupt Command Register 41 | // send interprocessor interrupts(IPIs) to other processors. 42 | // 43 | // [63:56]: destination 44 | // [19:18]: destination shorthand 45 | // [15] : trigger mode, 0:edge, 1:level 46 | // [14] : level, 0:de-assert, 1:assert 47 | // [12] : delivery status (RO), 0:idle, 1:send pending 48 | // [11] : destination mode, 0:physical, 1:logical 49 | // [10:8] : delivery mode, 101:INIT, 110:STARTUP 50 | // [7:0] : vector, address of a 4KByte page in the real-address 51 | 52 | 53 | // destination shorthand = 11:all excluding self 54 | // (send to all processors except sending-processor 55 | // trigger mode = 0:edge 56 | // level = 1:assert 57 | // destination mode = 0:physical 58 | // delivery mode = 101:INIT 59 | apic_write(APIC_ICR, APIC_DEST_ALLBUT|APIC_INT_ASSERT|APIC_DM_INIT); 60 | 61 | 62 | // 10ms delay 63 | delay(1000000); 64 | delay(1000000); 65 | 66 | // delivery mode = 111:STARTUP 67 | // Because base address of AP initialization code is 0x9000 (setup.asm) 68 | // vector is 0x9 69 | apic_write(APIC_ICR, APIC_DEST_ALLBUT|APIC_INT_ASSERT|APIC_DM_STARTUP|(AP_INIT_ADDRESS>>12)); 70 | 71 | // 100us delay 72 | delay(1000000); 73 | 74 | 75 | // delivery mode = 111:STARTUP 76 | apic_write(APIC_ICR, APIC_DEST_ALLBUT|APIC_INT_ASSERT|APIC_DM_STARTUP|(AP_INIT_ADDRESS>>12)); 77 | 78 | // 100us delay 79 | delay(1000000); 80 | 81 | 82 | // signal sent? 83 | if ((apic_read(APIC_ICR) & APIC_ICR_BUSY) != 0) { 84 | caos_printf("AP-WAKENING FAIL!\n"); 85 | halt(); 86 | } 87 | 88 | 89 | return; 90 | } 91 | 92 | 93 | void smp_init(void) 94 | { 95 | 96 | preempt_count() = 0; 97 | 98 | caos_printf("preempt-count=> %d\n", preempt_count()); 99 | 100 | 101 | // per-cpu data setup 102 | setup_per_cpu_areas(); 103 | 104 | } 105 | 106 | 107 | -------------------------------------------------------------------------------- /src/spinlock.c: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include // set_bit 4 | #include // smp_mb() 5 | 6 | 7 | #define DEBUG 8 | #undef DEBUG 9 | 10 | // 11 | // If spin-lock is free, it locks spin-lock and returns 1. 12 | // If spin-lock is locked, it returns 0. 13 | // 14 | size_t raw_spin_trylock(spinlock_t *lock) 15 | { 16 | size_t tmp = 0; 17 | 18 | 19 | asm volatile ( 20 | "movb $0, %b0\n\t" 21 | "lock;xchgb %b0, %1\n\t" 22 | : "=&a" (tmp), "+m" (lock->slock) 23 | : 24 | : "memory"); 25 | 26 | 27 | return tmp; 28 | } 29 | 30 | 31 | 32 | 33 | 34 | void spin_lock(spinlock_t *lock) 35 | { 36 | 37 | preempt_disable(); 38 | 39 | #ifdef DEBUG 40 | caos_printf("PREEMPT=%d\n", preempt_count()); 41 | #endif 42 | 43 | while (!raw_spin_trylock(lock)) { 44 | preempt_enable(); 45 | while (spin_is_locked(lock)) 46 | cpu_relax(); 47 | preempt_disable(); 48 | } 49 | 50 | 51 | } 52 | 53 | 54 | void spin_unlock(spinlock_t *lock) 55 | { 56 | 57 | set_bit(0, &lock->slock); 58 | smp_mb(); 59 | 60 | preempt_enable(); 61 | #ifdef DEBUG 62 | caos_printf("PREEMPT=%d\n", preempt_count()); 63 | #endif 64 | } 65 | 66 | 67 | 68 | 69 | 70 | -------------------------------------------------------------------------------- /src/string.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | 5 | size_t caos_memcmp(const void *cs, const void *ct, size_t count) 6 | { 7 | const unsigned char *su1, *su2; 8 | size_t res = 0; 9 | 10 | for (su1 = cs, su2 = ct; 0 < count; ++su1, ++su2, count--) 11 | if ((res = *su1 - *su2) != 0) 12 | break; 13 | return res; 14 | } 15 | 16 | 17 | size_t caos_strcmp(const char *src, const char *dst) 18 | { 19 | char t = 0; 20 | 21 | while (1) { 22 | if ((t = *src - *dst++) != 0 || !*src++) 23 | break; 24 | } 25 | 26 | return (size_t)t; 27 | 28 | } 29 | 30 | 31 | 32 | 33 | size_t caos_strcat(char *A_szDest, char *A_szSrc) 34 | { 35 | char *p = A_szSrc; 36 | while (*A_szSrc != '\0') 37 | *A_szDest++ = *A_szSrc++; 38 | return A_szSrc-p; 39 | } 40 | 41 | 42 | size_t caos_strlen(const char *s) 43 | { 44 | int i = 0; 45 | while (s[i] != '\0') 46 | i++; 47 | 48 | return i; 49 | } 50 | 51 | void *caos_memcpy(void *dst, void *src, size_t len) 52 | { 53 | long *pldst = (long *)dst; 54 | long const *plsrc = (long const *)src; 55 | char *pcdst; 56 | char const *pcsrc; 57 | 58 | // 59 | // If address is aligned by // 4-bytes, 60 | // memory is copied by 4-bytes size 61 | // 62 | if ( (((unsigned long)src & -4UL) == 0) && \ 63 | (((unsigned long)dst & -4UL) == 0) ) { 64 | while (len >= sizeof(long)) { 65 | *pldst++ = *plsrc++; 66 | len -= sizeof(long); 67 | } 68 | } 69 | 70 | // 71 | // copy extra bytes 72 | // 73 | pcdst = (char *)pldst; 74 | pcsrc = (char const *)plsrc; 75 | 76 | while (len--) 77 | *pcdst++ = *pcsrc++; 78 | 79 | // GNU memcpy returns target address 80 | return dst; 81 | } 82 | 83 | 84 | void *caos_memset(void *dst, size_t c, size_t len) 85 | { 86 | volatile char *p = (volatile char *)dst; 87 | 88 | 89 | while (len-- > 0) { 90 | *p = (char)c; 91 | p++; 92 | } 93 | 94 | // GNU memcpy returns target address 95 | return dst; 96 | } 97 | -------------------------------------------------------------------------------- /unittest/Makefile: -------------------------------------------------------------------------------- 1 | include ../config.mk 2 | 3 | 4 | CFLAGS=-Wall -Winline -O2 5 | 6 | 7 | C_SRCS = test_atomic.c 8 | 9 | C_EXEC = $(C_SRCS:.c=) 10 | 11 | 12 | all:$(C_EXEC) EXEC_TEST 13 | 14 | 15 | $(C_EXEC):$(C_SRCS) 16 | $(GCC64) $(CFLAGS) -o $@ $< 17 | 18 | 19 | EXEC_TEST:$(C_EXEC) 20 | echo "UNITTEST<"$(C_EXEC)">" 21 | ./$< 22 | -------------------------------------------------------------------------------- /unittest/test_atomic.c: -------------------------------------------------------------------------------- 1 | 2 | #include "../src/include/atomic.h" 3 | 4 | int main(void) 5 | { 6 | size_t val = 0x12345678ABCDEF00; 7 | size_t old_val; 8 | int i; 9 | 10 | for (i = 0; i < 0x1ff; i++) 11 | { 12 | old_val = atomic_cmpxchg(&val, val, val+i); 13 | if (val != old_val + i) 14 | printf("atomic_cmpxchg fails\n"); 15 | } 16 | 17 | return 0; 18 | } 19 | -------------------------------------------------------------------------------- /utils/Makefile: -------------------------------------------------------------------------------- 1 | 2 | CFLAGS=-Wall -O2 3 | 4 | 5 | TARGETS = gen_section test_utils 6 | 7 | 8 | 9 | all: $(TARGETS) 10 | 11 | gen_section: gen_section.c 12 | gcc $(CFLAGS) -o $@ $< 13 | 14 | test_utils: test_utils.c 15 | gcc $(CFLAGS) -o $@ $< 16 | 17 | 18 | 19 | clean: 20 | rm -f *.o $(TARGETS) 21 | -------------------------------------------------------------------------------- /utils/gen_section.c: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | /* 5 | * read system.map and generate header file, section.h 6 | * 7 | * which informs linear-address of symbols in kernel. 8 | * 9 | */ 10 | 11 | 12 | #include 13 | #include 14 | 15 | 16 | char line_buf[128]; 17 | 18 | char address[20]; 19 | char symbol[64]; 20 | char flag; 21 | 22 | 23 | int main(int argc, char *argv[]) 24 | { 25 | FILE *symfile; 26 | FILE *headfile; 27 | 28 | if (argc != 3) { 29 | printf("USAGE: sym_gen system.map header.h\n"); 30 | return 1; 31 | } 32 | 33 | 34 | symfile = fopen(argv[1], "r"); 35 | headfile = fopen(argv[2], "w"); 36 | 37 | if (headfile == NULL || symfile == NULL) { 38 | perror("file error?"); 39 | return 1; 40 | } 41 | 42 | 43 | fprintf(headfile, ";*******************************************************************\n"); 44 | fprintf(headfile, "; This file is generated automatically by utils/gen_section program\n"); 45 | fprintf(headfile, ";*******************************************************************\n"); 46 | 47 | while (fgets(line_buf, 127, symfile) != NULL) { 48 | sscanf(line_buf, "%s %c %s", address, &flag, symbol); 49 | 50 | fprintf(headfile, "%-20s equ 0x%s\n", symbol, address); 51 | } 52 | 53 | 54 | 55 | fclose(symfile); 56 | fclose(headfile); 57 | 58 | 59 | 60 | return 0; 61 | } 62 | 63 | 64 | -------------------------------------------------------------------------------- /utils/test_utils.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | 4 | int main(void) 5 | { 6 | printf("\nStart Build Utility Programs in utils directory\n\n"); 7 | printf("/* *** */ \n"); 8 | 9 | return 0; 10 | } 11 | --------------------------------------------------------------------------------