├── 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 |
--------------------------------------------------------------------------------