├── Makefile ├── Makefile_nasm_bin ├── README.md ├── bootloader ├── .rid ├── Makefile ├── bootloader.asm ├── bootloader.lds └── bootloader2.asm ├── kernel ├── .rid ├── Makefile ├── asm.h ├── bitmanip.h ├── gdt.c ├── gdt.h ├── gdt.s ├── io.c ├── io.h ├── io.s ├── irq.c ├── irq.h ├── irq.s ├── kernel ├── kernel.c ├── kernel.lds ├── kernel.o ├── kernel.s ├── lapic.c ├── lapic.h ├── lapic.s ├── task.c ├── task.h ├── task.s ├── task1.c ├── task1.h ├── task1.s ├── task2.h └── test │ ├── .rid │ ├── Makefile │ ├── greatest.h │ ├── main │ ├── test │ ├── test.c │ └── test.o └── qemu.log /Makefile: -------------------------------------------------------------------------------- 1 | BUILD_DIR=build 2 | BOOTLOADER=$(BUILD_DIR)/boot/bootloader 3 | KERNEL=$(BUILD_DIR)/kern/kernel 4 | DISK_IMG=disk.img 5 | QEMU_DEBUG=-d int,mmu,pcall,guest_errors,cpu_reset 6 | QEMU_STDIO= -monitor stdio 7 | 8 | all: build_dir disk 9 | 10 | build_dir: 11 | [ -d build/ ] || mkdir build 12 | [ -d build/kern ] || mkdir build/kern 13 | [ -d build/boot ] || mkdir build/boot 14 | 15 | .PHONY: 16 | $(BOOTLOADER): 17 | make -C bootloader 18 | 19 | .PHONY: 20 | $(KERNEL): 21 | make -C kernel 22 | 23 | .PHONY: 24 | disk: $(BOOTLOADER) $(KERNEL) 25 | make -C bootloader 26 | make -C kernel 27 | dd if=/dev/zero of=$(DISK_IMG) bs=512 count=2880 28 | dd if=$(BOOTLOADER) of=$(DISK_IMG) bs=512 count=1 seek=0 29 | dd if=$(KERNEL) of=$(DISK_IMG) bs=512 count=30 seek=1 30 | 31 | qemu-gdb: 32 | qemu-system-i386 $(QEMU_DEBUG) $(QEMU_STDIO) -machine q35 -fda $(DISK_IMG) -gdb tcp::26000 -D qemu.log -S 33 | 34 | .PHONY: 35 | clean: 36 | killall qemu-system-i386 || true 37 | killall gdb || true 38 | rm -rf build $(DISK_IMG) 39 | -------------------------------------------------------------------------------- /Makefile_nasm_bin: -------------------------------------------------------------------------------- 1 | BUILD_DIR=../build/boot 2 | BOOTLOADER=$(BUILD_DIR)/bootloader 3 | 4 | BOOTLOADER_OBJS_TARGET := $(BUILD_DIR)/%.o 5 | 6 | BOOTLOADER_SRCS := $(wildcard *.asm) 7 | BOOTLOADER_OBJS := $(patsubst %.asm, $(BOOTLOADER_OBJS_TARGET), $(BOOTLOADER_SRCS)) 8 | 9 | all: $(BUILD_DIR)/bootloader 10 | 11 | $(BOOTLOADER_OBJS_TARGET): %.asm 12 | nasm -f bin $< -o $@ 13 | 14 | $(BUILD_DIR)/bootloader: $(BOOTLOADER_OBJS) 15 | # ld -m elf_i386 -T bootloader.lds $< -o $@.bin 16 | # objcopy -O binary $@.o $@ 17 | cp $@.o $@ 18 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Sample Operating System 2 | A sample OS as demonstrated in the book Operating System: From 0 to 1 3 | 4 | This is the initial OS version I wrote for demonstration of the book "Operating System: From 0 to 1". Not the most stellar C code, but you can refer to it for checking the correctness of your code. That's also the reason why I want you to write your own code using guidelines from the book, and it is also one important goal of the book. 5 | 6 | The code covers 10 chapters of the "System Programming Guide" (Intel Manual Volume 3), along with a simple keyboard and video driver for input and output. However, at the moment, only the following features are implmeneted: 7 | 8 | - Protected mode. 9 | - Creating and managing processes with TSS (Task State Structure). 10 | - Interrupts 11 | - LAPIC. 12 | 13 | Paging and I/O are not yet implemented. I will try to implement it as the book progresses. 14 | -------------------------------------------------------------------------------- /bootloader/.rid: -------------------------------------------------------------------------------- 1 | 60eb17320cc25d9bd05be1a53195cf36 -------------------------------------------------------------------------------- /bootloader/Makefile: -------------------------------------------------------------------------------- 1 | BUILD_DIR=../build/boot 2 | BOOTLOADER=$(BUILD_DIR)/bootloader 3 | 4 | BOOTLOADER_OBJS_TARGET := $(BUILD_DIR)/%.o 5 | 6 | BOOTLOADER_SRCS := $(wildcard *.asm) 7 | BOOTLOADER_OBJS := $(patsubst %.asm, $(BOOTLOADER_OBJS_TARGET), $(BOOTLOADER_SRCS)) 8 | 9 | all: $(BUILD_DIR)/bootloader 10 | 11 | $(BOOTLOADER_OBJS_TARGET): %.asm 12 | nasm -f elf -F dwarf -g $< -o $@ 13 | 14 | $(BUILD_DIR)/bootloader: $(BOOTLOADER_OBJS) 15 | ld -m elf_i386 -T bootloader.lds $< -o $@.bin 16 | objcopy -O binary $@.bin $@ 17 | -------------------------------------------------------------------------------- /bootloader/bootloader.asm: -------------------------------------------------------------------------------- 1 | ;********************************************* 2 | ; Boot1.asm 3 | ; - A Simple Bootloader 4 | ; 5 | ; Operating Systems Development Tutorial 6 | ;********************************************* 7 | bits 16 8 | 9 | start: jmp boot 10 | 11 | %define num_of_sectors al 12 | %define track_num ch 13 | %define sector_num cl 14 | %define head_num dh 15 | %define drive_num dl 16 | 17 | %define LOAD_ADDRESS 1000h 18 | %define LOAD_SEGMENT 100h 19 | 20 | struc tss 21 | link: resw 1 22 | link_h: resw 1 23 | esp0: resd 1 24 | ss0: resw 1 25 | ss0_h: resw 1 26 | esp1: resd 1 27 | ss1: resw 1 28 | ss1_h: resw 1 29 | esp2: resd 1 30 | ss2: resw 1 31 | ss2_h: resw 1 32 | cr3_r: resd 1 33 | eip_r: resd 1 34 | eflags_r: resd 1 35 | eax_r: resd 1 36 | ecx_r: resd 1 37 | edx_r: resd 1 38 | ebx_r: resd 1 39 | esp_r: resd 1 40 | ebp_r: resd 1 41 | esi_r: resd 1 42 | edi_r: resd 1 43 | es_r: resw 1 44 | es_h: resw 1 45 | cs_r: resw 1 46 | cs_h: resw 1 47 | ss_r: resw 1 48 | ss_h: resw 1 49 | ds_r: resw 1 50 | ds_h: resw 1 51 | fs_r: resw 1 52 | fs_h: resw 1 53 | gs_r: resw 1 54 | gs_h: resw 1 55 | ldt_r: resw 1 56 | ldt_h: resw 1 57 | trap_r: resw 1 58 | io_base: resw 1 59 | endstruc 60 | 61 | msg db "Welcome to My Operating System!", 0ah, 0dh, 0h ; the string to print 62 | _CurX db 0 63 | _CurY db 0 64 | 65 | boot: 66 | cli ; no interrupts 67 | cld ; all that we need to init 68 | ; we will fill more code here later 69 | ;; xor ax, ax 70 | ;; mov ds, ax 71 | ;; mov es, ax 72 | 73 | ;; call ClrScr 74 | 75 | mov si, msg 76 | call Print 77 | 78 | mov ah, 0 ; reset floppy disk function 79 | mov dl, 0 ; drive 0 is floppy drive 80 | int 0x13 ; call BIOS 81 | jc boot ; If Carry Flag (CF) is set, there was an error. Try resetting again 82 | 83 | ;; we are going to read sector to into address 0x50:0 84 | ;; do not read the sector into somewhere that exceeds beyond the address 85 | ;; 0x10000, since we are in 16 bit mode, the data beyond won't be 86 | ;; accessible and is wrapped around when we try to address them i.e. 87 | ;; if we try to access 0x10047, it becomes 0x47. 88 | mov ax, LOAD_SEGMENT 89 | mov es, ax 90 | xor bx, bx 91 | 92 | mov num_of_sectors, 17 ; read 17 sector 93 | mov track_num, 0 ; we are reading the 2nd sector past us, so its still on track 0 94 | mov sector_num, 2 ; sector to read (The 2nth sector) 95 | mov head_num, 0 ; head number 96 | mov drive_num, 0 ; drive number. Remember Drive 0 is floppy drive. 97 | mov ah, 0x02 ; read floppy sector function 98 | int 0x13 ; call BIOS - Read the sector 99 | 100 | mov ax, LOAD_SEGMENT 101 | mov es, ax 102 | mov bx, 512*17 103 | 104 | mov num_of_sectors, 18 ; read 18 sector 105 | mov track_num, 0 ; we are reading the 19th sector past us, so its on track 1 106 | mov sector_num, 1 ; sector to read (The 19th sector, which is first sector on track 1) 107 | mov head_num, 1 ; head number 108 | mov drive_num, 0 ; drive number. Remember Drive 0 is floppy drive. 109 | mov ah, 0x02 ; read floppy sector function 110 | int 0x13 ; call BIOS - Read the sector 111 | 112 | ;; Install GDT 113 | call InstallGDT 114 | 115 | mov eax, cr0 ; set bit 0 in cr0 -- enter pmode 116 | or eax, 1 117 | mov cr0, eax 118 | jmp clear_cache 119 | 120 | clear_cache: 121 | mov eax, 0x10 ; set data segments to data selector (0x10) 122 | ;; mov ds, ax 123 | ;; mov ss, ax 124 | ;; mov es, ax 125 | ;; mov esp, 10000h ; stack begins from 10000h 126 | 127 | mov eax, cr3 128 | mov [init_tss + cr3_r], eax 129 | pushf 130 | pop ax 131 | mov [init_tss + eflags_r], eax 132 | 133 | xor edx, edx 134 | xor eax, eax 135 | mov es, eax 136 | mov edx, [es:LOAD_ADDRESS + 0x18] 137 | mov [init_tss + eip_r], edx 138 | 139 | ;; mov eax, 0x18 140 | ;; ltr ax 141 | ;; push word 0x8 142 | ;; push word 0x45 143 | ;; retf 144 | mov eax, 0x3 << 3 145 | mov bx, gdt_data 146 | ;; ltr ax 147 | mov ss, [init_tss + ss_r] 148 | mov esp, [init_tss + esp0] 149 | push dword [init_tss + eflags_r] 150 | push dword [init_tss + cs_r] 151 | push dword [init_tss + eip_r] 152 | ;; iretd 153 | call 0x18:00 154 | 155 | cli ; Clear all Interrupts 156 | hlt ; halt the system 157 | 158 | MovCur: 159 | mov bh, 0 160 | mov ah, 2 161 | int 10h 162 | 163 | mov [_CurX], dl 164 | mov [_CurY], dh 165 | ret 166 | 167 | ;**************************************************; 168 | ; ClrScr () 169 | ; - Clears screen 170 | ;**************************************************; 171 | ClrScr: 172 | mov dl, 0 173 | mov dh, 0 174 | call MovCur 175 | mov al, ' ' 176 | mov bl, 0 177 | mov cx, 80*25 178 | call PutChar 179 | mov dl, 0 180 | mov dh, 0 181 | call MovCur 182 | ret 183 | 184 | ;***************************************; 185 | ; Prints a string 186 | ; DS:SI: 0 terminated string 187 | ;***************************************; 188 | Print: 189 | .loop: 190 | lodsb ; load next byte from string from SI to AL 191 | or al, al ; Does AL=0? 192 | jz .done ; Yep, null terminator found-bail out 193 | mov cx, 1 194 | call PutChar 195 | jmp .loop ; Repeat until null terminator found 196 | .done: 197 | ret ; we are done, so return 198 | 199 | 200 | ;**************************************************; 201 | ; PutChar () 202 | ; - Prints a character to screen 203 | ; AL = Character to print 204 | ; BL = text color 205 | ; CX = number of times character is display 206 | ;**************************************************; 207 | PutChar: 208 | mov bh, 0 209 | mov ah, 0ah 210 | int 10h 211 | 212 | add [_CurX], cx 213 | mov dl, [_CurX] 214 | mov dh, [_CurY] 215 | call MovCur 216 | 217 | ret 218 | 219 | InstallGDT: 220 | cli ; clear interrupts 221 | pusha ; save registers 222 | lgdt [toc] ; load GDT into GDTR 223 | sti ; enable interrupts 224 | popa ; restore registers 225 | ret ; All done! 226 | 227 | ;; Task State Segment (TSS) data structure 228 | init_tss: 229 | istruc tss 230 | at link, dw 0 231 | at link_h, dw 0 232 | at esp0, dd 0x10000 233 | at ss0, dd 0x10 234 | at esp1, dd 0x10000 235 | at ss1, dd 0x10 236 | at esp2, dd 0x10000 237 | at ss2, dd 0x10 238 | at cr3_r, dd 0x2000 239 | at eip_r, dd 0x45 240 | at esp_r, dd 0x10000 241 | at es_r, dd 0x10 242 | at cs_r, dd 0x8 243 | at ss_r, dd 0x10 244 | at ds_r, dd 0x10 245 | at fs_r, dd 0x10 246 | at gs_r, dd 0x10 247 | at ldt_r, dw 0x00 248 | at trap_r, dw 0x00 249 | at io_base, dw 0x00 250 | iend 251 | ;******************************************* 252 | ; Global Descriptor Table (GDT) 253 | ;******************************************* 254 | 255 | gdt_data: 256 | ;; ID: 0 257 | ;; null descriptor 258 | dd 0 259 | dd 0 260 | 261 | ;; ID: 1 262 | ;; code descriptor 263 | dw 0FFFFh ; limit low 264 | dw 0x0000 265 | ;; dw 0x3045 ; base low 266 | db 0x00 ; base middle 267 | db 10011110b ; access 268 | db 11001111b ; granularity 269 | db 0x00 ; base high 270 | 271 | ;; ID: 2 272 | ;; gdt data: ; data descriptor 273 | dw 0FFFFh ; limit low (Same as code) 274 | dw 0x0000 ; base low 275 | db 0x00 ; base middle 276 | db 10010010b ; access 277 | db 11001111b ; granularity 278 | db 0 ; base high 279 | 280 | ;; ID: 3 281 | ;; TSS descriptor 282 | dw 0x067 ; limit low 283 | dw init_tss ; base low 284 | db 0x00 ; base middle 285 | ;; db 10011010b ; access 286 | ;; db 11001111b ; granularity 287 | db 10001001b 288 | ;; db 10001001n 289 | db 00010000b ; granularity 290 | db 0x00 ; base 31:24 291 | end_of_gdt: 292 | 293 | toc: 294 | ; according to lgdt description, the instruction accepts a 6-bytes 295 | ; operand, with the lowest 2 bytes size of GDT, and the remaining 296 | ; 4 bytes the base address of GDT 297 | dw end_of_gdt - gdt_data - 1 ; limit (Size of GDT) 298 | dd gdt_data ; base of GDT 299 | 300 | times 510 - ($-$$) db 0 ; We have to be 512 bytes. Clear the rest of the bytes with 0 301 | 302 | dw 0xAA55 ; Boot Signiture 303 | -------------------------------------------------------------------------------- /bootloader/bootloader.lds: -------------------------------------------------------------------------------- 1 | OUTPUT(bootloader); 2 | 3 | SECTIONS 4 | { 5 | .text 0x7c00: 6 | { 7 | *(.text) 8 | } 9 | .data : 10 | { 11 | *(.data) 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /bootloader/bootloader2.asm: -------------------------------------------------------------------------------- 1 | ;********************************************* 2 | ; Boot1.asm 3 | ; - A Simple Bootloader 4 | ; 5 | ; Operating Systems Development Tutorial 6 | ;********************************************* 7 | bits 16 8 | 9 | start: jmp boot 10 | 11 | %define num_of_sectors al 12 | %define track_num ch 13 | %define sector_num cl 14 | %define head_num dh 15 | %define drive_num dl 16 | 17 | %define LOAD_ADDRESS 1000h 18 | %define LOAD_SEGMENT 100h 19 | 20 | msg db "Welcome to My Operating System!", 0ah, 0dh, 0h ; the string to print 21 | _CurX db 0 22 | _CurY db 0 23 | 24 | boot: 25 | cli ; no interrupts 26 | cld ; all that we need to init 27 | ; we will fill more code here later 28 | ;; xor ax, ax 29 | ;; mov ds, ax 30 | ;; mov es, ax 31 | 32 | ;; call ClrScr 33 | 34 | mov si, msg 35 | call Print 36 | 37 | mov ah, 0 ; reset floppy disk function 38 | mov dl, 0 ; drive 0 is floppy drive 39 | int 0x13 ; call BIOS 40 | jc boot ; If Carry Flag (CF) is set, there was an error. Try resetting again 41 | 42 | ;; we are going to read sector to into address 0x50:0 43 | ;; do not read the sector into somewhere that exceeds beyond the address 44 | ;; 0x10000, since we are in 16 bit mode, the data beyond won't be 45 | ;; accessible and is wrapped around when we try to address them i.e. 46 | ;; if we try to access 0x10047, it becomes 0x47. 47 | mov ax, LOAD_SEGMENT 48 | mov es, ax 49 | xor bx, bx 50 | 51 | mov num_of_sectors, 17 ; read 17 sector 52 | mov track_num, 0 ; we are reading the 2nd sector past us, so its still on track 0 53 | mov sector_num, 2 ; sector to read (The 2nth sector) 54 | mov head_num, 0 ; head number 55 | mov drive_num, 0 ; drive number. Remember Drive 0 is floppy drive. 56 | mov ah, 0x02 ; read floppy sector function 57 | int 0x13 ; call BIOS - Read the sector 58 | 59 | mov ax, LOAD_SEGMENT 60 | mov es, ax 61 | mov bx, 512*17 62 | 63 | mov num_of_sectors, 18 ; read 18 sector 64 | mov track_num, 0 ; we are reading the 19th sector past us, so its on track 1 65 | mov sector_num, 1 ; sector to read (The 19th sector, which is first sector on track 1) 66 | mov head_num, 1 ; head number 67 | mov drive_num, 0 ; drive number. Remember Drive 0 is floppy drive. 68 | mov ah, 0x02 ; read floppy sector function 69 | int 0x13 ; call BIOS - Read the sector 70 | 71 | ;; Install GDT 72 | call InstallGDT 73 | 74 | mov ax, 0x10 ; set data segments to data selector (0x10) 75 | mov ds, ax 76 | ;; mov ss, ax 77 | mov es, ax 78 | 79 | mov eax, cr0 ; set bit 0 in cr0 -- enter pmode 80 | or eax, 1 81 | mov cr0, eax 82 | 83 | mov esp, 0xf000 ; stack begins from 10000h 84 | 85 | xor edx, edx 86 | xor eax, eax 87 | mov es, eax 88 | mov edx, [es:LOAD_ADDRESS + 0x18] 89 | 90 | jmp edx 91 | 92 | cli ; Clear all Interrupts 93 | hlt ; halt the system 94 | 95 | MovCur: 96 | mov bh, 0 97 | mov ah, 2 98 | int 10h 99 | 100 | mov [_CurX], dl 101 | mov [_CurY], dh 102 | ret 103 | 104 | ;**************************************************; 105 | ; ClrScr () 106 | ; - Clears screen 107 | ;**************************************************; 108 | ClrScr: 109 | mov dl, 0 110 | mov dh, 0 111 | call MovCur 112 | mov al, ' ' 113 | mov bl, 0 114 | mov cx, 80*25 115 | call PutChar 116 | mov dl, 0 117 | mov dh, 0 118 | call MovCur 119 | ret 120 | 121 | ;***************************************; 122 | ; Prints a string 123 | ; DS:SI: 0 terminated string 124 | ;***************************************; 125 | Print: 126 | .loop: 127 | lodsb ; load next byte from string from SI to AL 128 | or al, al ; Does AL=0? 129 | jz .done ; Yep, null terminator found-bail out 130 | mov cx, 1 131 | call PutChar 132 | jmp .loop ; Repeat until null terminator found 133 | .done: 134 | ret ; we are done, so return 135 | 136 | 137 | ;**************************************************; 138 | ; PutChar () 139 | ; - Prints a character to screen 140 | ; AL = Character to print 141 | ; BL = text color 142 | ; CX = number of times character is display 143 | ;**************************************************; 144 | PutChar: 145 | mov bh, 0 146 | mov ah, 0ah 147 | int 10h 148 | 149 | add [_CurX], cx 150 | mov dl, [_CurX] 151 | mov dh, [_CurY] 152 | call MovCur 153 | 154 | ret 155 | 156 | ; esi: pointer to source memory address 157 | ; edi: pointer to destination memory address to copy to 158 | ; edx: length 159 | MemCopy: 160 | .loop: 161 | cmp edx, 0 162 | je .done 163 | mov al, [esi] 164 | mov [edi], al 165 | inc edi 166 | inc esi 167 | sub edx, 1 168 | jmp .loop 169 | .done: 170 | ret 171 | 172 | 173 | InstallGDT: 174 | cli ; clear interrupts 175 | pusha ; save registers 176 | lgdt [toc] ; load GDT into GDTR 177 | sti ; enable interrupts 178 | popa ; restore registers 179 | ret ; All done! 180 | 181 | ;******************************************* 182 | ; Global Descriptor Table (GDT) 183 | ;******************************************* 184 | 185 | gdt_data: 186 | dd 0 ; null descriptor 187 | dd 0 188 | 189 | ; gdt code: ; code descriptor 190 | dw 0FFFFh ; limit low 191 | dw 0x00 ; base low 192 | db 0x00 ; base middle 193 | db 10011010b ; access 194 | db 11001111b ; granularity 195 | db 0x00 ; base high 196 | 197 | ; gdt data: ; data descriptor 198 | dw 0FFFFh ; limit low (Same as code) 199 | dw 0x0000 ; base low 200 | db 0x00 ; base middle 201 | db 10010010b ; access 202 | db 11001111b ; granularity 203 | db 0 ; base high 204 | end_of_gdt: 205 | 206 | toc: 207 | ; according to lgdt description, the instruction accepts a 6-bytes 208 | ; operand, with the lowest 2 bytes size of GDT, and the remaining 209 | ; 4 bytes the base address of GDT 210 | dw end_of_gdt - gdt_data - 1 ; limit (Size of GDT) 211 | dd gdt_data ; base of GDT 212 | 213 | times 510 - ($-$$) db 0 ; We have to be 512 bytes. Clear the rest of the bytes with 0 214 | 215 | dw 0xAA55 ; Boot Signiture 216 | -------------------------------------------------------------------------------- /kernel/.rid: -------------------------------------------------------------------------------- 1 | 9ff440f8ea5616221741a850ecb4d8b2 -------------------------------------------------------------------------------- /kernel/Makefile: -------------------------------------------------------------------------------- 1 | BUILD_DIR=../build 2 | KERNEL=$(BUILD_DIR)/kern/kernel 3 | 4 | CFLAGS=-Wall -Wno-format 5 | CFLAGS+=-fno-stack-protector -fno-omit-frame-pointer -fno-asynchronous-unwind-tables 6 | CFLAGS+=-fno-builtin -masm=intel -m32 -nostdlib -gdwarf-2 -ggdb3 -save-temps 7 | 8 | KERN_SRCS := gdt.c io.c irq.c task.c lapic.c task1.c kernel.c 9 | KERN_OBJS := $(patsubst %.c, $(BUILD_DIR)/kern/%.o, $(KERN_SRCS)) 10 | 11 | all: $(KERNEL) 12 | @echo $(KERN_SRCS) 13 | @echo $(KERN_OBJS) 14 | 15 | $(BUILD_DIR)/kern/%.o: %.c 16 | gcc $(CFLAGS) -m32 -c $< -o $@ 17 | 18 | $(KERNEL): $(KERN_OBJS) 19 | ld --trace -m elf_i386 -Tkernel.lds $(KERN_OBJS) -o $@ 20 | # objcopy --only-keep-debug $(KERNEL) $(KERNEL).dbg 21 | # objcopy --strip-debug $(KERNEL) 22 | # objcopy --add-gnu-debuglink=$(KERNEL).dbg $(KERNEL) 23 | -------------------------------------------------------------------------------- /kernel/asm.h: -------------------------------------------------------------------------------- 1 | #define lidt(idt) asm("lidt "#idt) 2 | #define lgdt(gdt) asm("lgdt "#gdt) 3 | #define iret() \ 4 | asm("add esp, 0x4"); \ 5 | asm("leave"); \ 6 | asm("pop eax"); \ 7 | asm("iret") 8 | 9 | #define set_es(var) \ 10 | asm("mov edx, "#var"\n\t" \ 11 | "mov es, dx" :: "r"(var)) 12 | 13 | #define set_cs(var) \ 14 | asm("mov edx, "#var"\n\t" \ 15 | "mov cs, dx") 16 | 17 | #define set_ds(var) \ 18 | asm("mov edx, "#var"\n\t" \ 19 | "mov ds, dx") 20 | 21 | #define set_ss(var) \ 22 | asm("mov edx, "#var"\n\t" \ 23 | "mov ss, dx") 24 | 25 | #define set_gs(var) \ 26 | asm("mov edx, "#var"\n\t" \ 27 | "mov gs, dx") 28 | 29 | #define write_mem_es(offset, value) \ 30 | asm("mov edx, "#value"\n\t" \ 31 | "mov word [es:"#offset"], edx") \ 32 | 33 | #define ltr(gdt_index) \ 34 | asm("mov edx, "#gdt_index"\n\t" \ 35 | "ltr dx") 36 | -------------------------------------------------------------------------------- /kernel/bitmanip.h: -------------------------------------------------------------------------------- 1 | #define bit_mask(start, end) ((~(~0 << (end - start + 1))) << start) 2 | #define bit_value(v, start, end) ((bit_mask(start, end) & v) >> start) 3 | -------------------------------------------------------------------------------- /kernel/gdt.c: -------------------------------------------------------------------------------- 1 | #include "gdt.h" 2 | 3 | static segment_descriptor segments[GDT_SIZE]; 4 | 5 | gdt_t gdt = { 6 | .base = segments, 7 | .size = (DESCRIPTOR_SIZE * GDT_SIZE) - 1, 8 | .free_id = 0 9 | }; 10 | 11 | /* Add a new descriptor into GDT. Currently scanning for the entire table to retrieve the current max PID 12 | * to obtain the next PID. This must be optimized later, with randomization for O(1) performance. 13 | */ 14 | uint16_t add_segment(descriptor_table* t, uint32_t base, uint32_t limit, uint32_t access, uint16_t id, uint8_t auto_id) { 15 | segment_descriptor *s; 16 | 17 | if (auto_id) { 18 | if (t->free_id > GDT_SIZE) 19 | t->free_id = 1; 20 | } 21 | else 22 | t->free_id = id; 23 | 24 | do { 25 | s = get_segment(t, t->free_id); 26 | 27 | if (auto_id) 28 | t->free_id++; 29 | else 30 | break; 31 | 32 | if (null_segment_p(s)) break; 33 | } while (t->free_id < GDT_SIZE); 34 | 35 | s->first = SEG_BASE_0_15(base) | SEG_LIMIT_0_15(limit); 36 | s->second = SEG_BASE_24_31(base) | access | SEG_BASE_16_23(base); 37 | 38 | return auto_id ? (t->free_id - 1) : id; 39 | } 40 | 41 | inline int8_t null_segment_p(segment_descriptor* s) { 42 | return (s->raw == 0); 43 | } 44 | 45 | segment_descriptor* get_segment(descriptor_table *table , uint16_t index) { 46 | if (index >= GDT_SIZE) return 0; 47 | 48 | return &table->base[index]; 49 | } 50 | 51 | void setup_gdt(struct tss* init_tss) { 52 | gdt_add_segment(0x0, 0x0 , 0x0); 53 | 54 | gdt_add_segment(0x0000, 0xFFFF, 55 | SEG4K | SEG32 | SEG64_0 | SEG_LIMIT_16_19(0xf) | 56 | SEG_PRESENT | SEG_RING0 | SEG_CODE_DATA | SEG_XR); 57 | 58 | gdt_add_segment(0x0000, 0xFFFF, 59 | SEG4K | SEG32 | SEG64_0 | SEG_LIMIT_16_19(0xf) | 60 | SEG_PRESENT | SEG_RING0 | SEG_CODE_DATA | SEG_RWE); 61 | 62 | gdt_add_segment((uintptr_t) init_tss, 0x067, 63 | SEG1B | SEG_AVAILABLE_1 | SEG_LIMIT_16_19(0x0) | 64 | SEG_PRESENT | SEG_RING0 | SEG_SYSTEM | SEG_TSS32_AVAILABLE); 65 | 66 | gdt_add_segment(0xB8000, 0x7FFF, 67 | SEG4K | SEG32 | SEG64_0 | SEG_LIMIT_16_19(0xf) | 68 | SEG_PRESENT | SEG_RING0 | SEG_CODE_DATA | SEG_RW); 69 | 70 | gdt_add_segment((uintptr_t) &segments, GDT_SIZE, 71 | SEG4K | SEG32 | SEG64_0 | SEG_LIMIT_16_19(0xf) | 72 | SEG_PRESENT | SEG_RING0 | SEG_CODE_DATA | SEG_RW); 73 | 74 | /* for (int i = 5; i < GDT_SIZE; ++i) */ 75 | /* segments[i].raw = 0; */ 76 | 77 | /* gdt_add_segment((uintptr_t) &task1_tss, 0x0100, */ 78 | /* SEG1B | SEG16 | SEG64_0 | SEG_LIMIT_16_19(0x0) | */ 79 | /* SEG_PRESENT | SEG_RING0 | SEG_SYSTEM | SEG_TSS32_AVAILABLE); */ 80 | 81 | lgdt(gdt); 82 | ltr(0x3 << 3); 83 | } 84 | -------------------------------------------------------------------------------- /kernel/gdt.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include "bitmanip.h" 3 | #include "asm.h" 4 | 5 | #pragma once 6 | 7 | #define DESCRIPTOR_SIZE 8 8 | 9 | #define SEG_LIMIT_0_15(limit) bit_value(limit, 0, 15) 10 | #define SEG_BASE_0_15(base) (bit_value(base, 0, 15) << 16) 11 | #define SEG_BASE_16_23(base) bit_value(base, 16, 23) 12 | #define SEG_BASE_24_31(base) (bit_value(base, 24, 31) << 24) 13 | 14 | /* Segment access permission, only used for code and data descriptors */ 15 | #define SEG_R (0x0 << 8) 16 | #define SEG_RA (0x1 << 8) 17 | #define SEG_RW (0x2 << 8) 18 | #define SEG_RWA (0x3 << 8) 19 | #define SEG_RE (0x4 << 8) 20 | #define SEG_REA (0x5 << 8) 21 | #define SEG_RWE (0x6 << 8) 22 | #define SEG_RWEA (0x7 << 8) 23 | #define SEG_X (0x8 << 8) 24 | #define SEG_XA (0x9 << 8) 25 | #define SEG_XR (0xA << 8) 26 | #define SEG_XRA (0xB << 8) 27 | #define SEG_XC (0xC << 8) 28 | #define SEG_XCA (0xD << 8) 29 | #define SEG_XRC (0xE << 8) 30 | #define SEG_XRCA (0xF << 8) 31 | 32 | 33 | /* Segment types, only used for system descriptors */ 34 | #define SEG_TSS16_AVAILABLE (0x1 << 8) 35 | #define SEG_LDT (0x2 << 8) 36 | #define SEG_TSS16_BUSY (0x3 << 8) 37 | #define SEG_CALLGATE16 (0x4 << 8) 38 | #define SEG_TASKGATE (0x5 << 8) 39 | #define SEG_INTGATE16 (0x6 << 8) 40 | #define SEG_TRAPGATE16 (0x7 << 8) 41 | #define SEG_TSS32_AVAILABLE (0x9 << 8) 42 | #define SEG_TSS32_BUSY (0xB << 8) 43 | #define SEG_CALLGATE32 (0xC << 8) 44 | #define SEG_INTGATE32 (0xE << 8) 45 | #define SEG_TRAPGATE32 (0xF << 8) 46 | 47 | /* Segment is code/data or reserved for system */ 48 | #define SEG_SYSTEM 0 49 | #define SEG_CODE_DATA (0x1 << 12) 50 | 51 | /* Segment DPL */ 52 | #define SEG_RING0 (0x0 << 13) 53 | #define SEG_RING1 (0x1 << 13) 54 | #define SEG_RING2 (0x2 << 13) 55 | #define SEG_RING3 (0x3 << 13) 56 | 57 | /* Segment present or not */ 58 | #define SEG_NOT_PRESENT 0 59 | #define SEG_PRESENT (1 << 15) 60 | 61 | /* Segment limit 16-19 */ 62 | #define SEG_LIMIT_16_19(lim) (lim << 16) 63 | 64 | /* Segment available */ 65 | #define SEG_AVAILABLE_0 0 66 | #define SEG_AVAILABLE_1 (1 << 20) 67 | 68 | /* Segement 64-bit, default operation size must set to SEG16, which is 0 */ 69 | #define SEG64_0 0 70 | #define SEG64_1 (1 << 21) 71 | 72 | /* Segment default operation sizes, D-flag for code segment and B-flag for data/stack segments */ 73 | #define SEG16 0 74 | #define SEG32 (1 << 22) 75 | 76 | /* Granularity */ 77 | #define SEG1B 0 78 | #define SEG4K (1 << 23) 79 | 80 | #define SEG_AVAILABLE 0 81 | 82 | #define GDT_ENTRY_SIZE 8 83 | #define GDT_SIZE 8192 84 | 85 | #define CODE_SELECTOR (0x1 << 3) 86 | #define DATA_SELECTOR ((0x2 << 3)) 87 | #define VIDEO_SELECTOR ((0x4 << 3)) 88 | 89 | // #define segment_descriptor uint64_t 90 | 91 | #define GDT_OFFSET(index) (index * 8) 92 | 93 | typedef union _segment_descriptor { 94 | uint64_t raw; 95 | 96 | struct { 97 | uint32_t first; 98 | uint32_t second; 99 | }; 100 | 101 | struct { 102 | uint16_t limit_0_15; 103 | uint16_t base_0_15; 104 | uint8_t base_16_23; 105 | uint8_t type; 106 | uint8_t granularity; 107 | uint8_t base_24_31; 108 | }; 109 | } segment_descriptor; 110 | 111 | typedef union _segment_selector { 112 | uint16_t raw; 113 | 114 | struct { 115 | uint16_t rpl : 2; 116 | uint16_t ti : 1; 117 | uint16_t index : 13; 118 | }; 119 | } segment_selector; 120 | 121 | // 6 bytes struct is required by lgdt 122 | // we must always remember compiler's automatic alignment when writing low level code 123 | typedef struct __attribute__((__packed__)) gdt { 124 | /* 125 | * the size of the table in bytes 126 | * BEWARE: the table can carry 8192 entries, which means at most 0xFFFF bytes, not 0x10000 bytes = 8192 * 8. The reason is that the table starts at index 0, and byte 0 is included. Thus, the maximimum boundary is 0 + 0xFFFFh. */ 127 | uint16_t size; 128 | segment_descriptor *base; 129 | uint16_t free_id; 130 | } descriptor_table; 131 | 132 | typedef descriptor_table gdt_t; 133 | typedef descriptor_table ldt_t; 134 | 135 | extern gdt_t gdt; 136 | 137 | // #define get_segment(table, index) table.base[index] 138 | #define gdt_get_segment(index) get_segment(gdt, index) 139 | #define remove_segment(index) (gdt.base[index].raw = 0) 140 | #define gdt_add_segment(base, limit, access) add_segment(&gdt, base, limit, access, 0x0, 1) 141 | 142 | uint16_t add_segment(descriptor_table *t, uint32_t base, uint32_t limit, uint32_t access, uint16_t id, uint8_t auto_id); 143 | segment_descriptor* get_segment(descriptor_table *table, uint16_t index); 144 | int8_t null_segment_p(segment_descriptor* s); 145 | void setup_gdt(); 146 | -------------------------------------------------------------------------------- /kernel/io.c: -------------------------------------------------------------------------------- 1 | #include "io.h" 2 | #include "gdt.h" 3 | #include "asm.h" 4 | /* #include */ 5 | 6 | void putc(char c, char attr) { 7 | set_es(0x20); 8 | /* int data = (c << 8) | attr; */ 9 | write_mem_es(0x0, (0x30 << 8) | 'a'); 10 | } 11 | -------------------------------------------------------------------------------- /kernel/io.h: -------------------------------------------------------------------------------- 1 | #include "asm.h" 2 | 3 | void putc(char c, char attr); 4 | 5 | -------------------------------------------------------------------------------- /kernel/irq.c: -------------------------------------------------------------------------------- 1 | #include "irq.h" 2 | #include "task.h" 3 | #include "lapic.h" 4 | 5 | static segment_descriptor irq_gates[256]; 6 | 7 | idt_t idt = { 8 | .base = irq_gates, 9 | .size = DESCRIPTOR_SIZE * IDT_SIZE, 10 | .free_id = 0 11 | }; 12 | 13 | void setup_irq() { 14 | init_irq(irq0, 0); 15 | init_irq(irq1, 1); 16 | init_irq(irq8, 8); 17 | init_irq(irq10, 10); 18 | init_irq(irq11, 11); 19 | init_irq(irq13, 13); 20 | init_irq(irq32, 32); 21 | 22 | /* INIT_TASK(irq8); \ */ 23 | /* id = idt_add_gate(TASK_SELECTOR(irq8), 0x85, 8); */ 24 | 25 | lidt(idt); 26 | } 27 | 28 | TASK_START(irq0, divide_by_zero_handler); 29 | void divide_by_zero_handler() { 30 | iret(); 31 | /* __builtin_unreachable (); */ 32 | divide_by_zero_handler(); 33 | } 34 | TASK_END(irq0); 35 | 36 | TASK_START(irq1, debug_exception); 37 | void debug_exception() { 38 | asm("int 8"); 39 | /* iret(); */ 40 | } 41 | TASK_END(irq1); 42 | 43 | TASK_START(irq8, double_fault_handler); 44 | void double_fault_handler(uint32_t error_code) { 45 | int i = error_code; 46 | iret(); 47 | __builtin_unreachable (); 48 | } 49 | TASK_END(irq8); 50 | 51 | TASK_START(irq10, invalid_tss_handler); 52 | void invalid_tss_handler() { 53 | asm("mov eax, [ebp + 4]"); 54 | int error_code = 0; 55 | asm("mov %0, eax":"=r"(error_code)::); 56 | iret(); 57 | } 58 | TASK_END(irq10); 59 | 60 | TASK_START(irq11, segment_not_present); 61 | void segment_not_present(uint32_t error_code) { 62 | iret(); 63 | } 64 | TASK_END(irq11); 65 | 66 | TASK_START(irq13, general_protection_exception); 67 | void general_protection_exception() { 68 | _start: 69 | asm("mov eax, [ebp + 4]"); 70 | int error_code = 0; 71 | asm("mov %0, eax":"=r"(error_code)::); 72 | 73 | iret(); 74 | /* asm("mov %0, %1":"=r"(irq13_tss.esp):"r"(irq13_tss.esp0):); */ 75 | asm("mov ebp, esp"); 76 | asm("sub ebp, 4"); 77 | goto _start; 78 | } 79 | TASK_END(irq13); 80 | 81 | TASK_START(irq32, lapic_timer_handler); 82 | int current_task_id = 1; 83 | void lapic_timer_handler() { 84 | _start: 85 | /* asm("mov eax, [ebp + 4]"); */ 86 | /* int error_code = 0; */ 87 | /* asm("mov %0, eax":"=r"(error_code)::); */ 88 | /* asm("mov %0, %1":"=r"(irq13_tss.esp):"r"(irq13_tss.esp0):); */ 89 | /* asm("mov ebp, esp"); */ 90 | /* asm("sub ebp, 4"); */ 91 | if (current_task_id == 1) 92 | current_task_id = 2; 93 | else 94 | current_task_id = 1; 95 | 96 | lapic_isr_complete(); 97 | iret(); 98 | asm("mov ebp, esp"); 99 | asm("sub ebp, 4"); 100 | goto _start; 101 | } 102 | TASK_END(irq32); 103 | 104 | TASK_START(irq20, double_fault_handler2); 105 | void double_fault_handler2(uint32_t error_code) { 106 | iret(); 107 | } 108 | TASK_END(irq20); 109 | -------------------------------------------------------------------------------- /kernel/irq.h: -------------------------------------------------------------------------------- 1 | #include "gdt.h" 2 | #include "asm.h" 3 | #include "task.h" 4 | #include "lapic.h" 5 | 6 | #define IDT_SIZE 256 7 | #define IDT_ENTRY_SIZE GDT_ENTRY_SIZE 8 | 9 | typedef descriptor_table idt_t; 10 | 11 | extern idt_t idt; 12 | 13 | #define ISEG_ACCESS(access) (access << 8) 14 | /* t = TSS segment selector 15 | */ 16 | #define idt_add_gate(t, access, id) \ 17 | add_segment(&idt, t, 0x0000, ISEG_ACCESS(access), id, 0) 18 | 19 | #define init_irq(irq_name, id) \ 20 | INIT_TASK(irq_name); \ 21 | idt_add_gate(TASK_SELECTOR(irq_name), 0x85, id) 22 | 23 | typedef void (*irq_handler)(uint32_t error_code); 24 | void setup_irq(); 25 | 26 | TASK_REGISTER(irq0); 27 | void divide_by_zero_handler(); 28 | 29 | TASK_REGISTER(irq1); 30 | void debug_exception(); 31 | 32 | TASK_REGISTER(irq8); 33 | void double_fault_handler(uint32_t error_code); 34 | 35 | TASK_REGISTER(irq10); 36 | void invalid_tss_handler(); 37 | 38 | TASK_REGISTER(irq11); 39 | void segment_not_present(uint32_t error_code); 40 | 41 | TASK_REGISTER(irq13); 42 | void general_protection_exception(); 43 | 44 | TASK_REGISTER(irq20); 45 | void double_fault_handler2(uint32_t error_code); 46 | 47 | TASK_REGISTER(irq32); 48 | void lapic_timer_handler(); 49 | -------------------------------------------------------------------------------- /kernel/kernel: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tuhdo/sample-os/09e25a85e2588bbcf68d935f76a2b4a7402a941e/kernel/kernel -------------------------------------------------------------------------------- /kernel/kernel.c: -------------------------------------------------------------------------------- 1 | #include "io.h" 2 | #include "irq.h" 3 | #include "gdt.h" 4 | #include "asm.h" 5 | #include "task.h" 6 | #include "task1.h" 7 | #include "lapic.h" 8 | 9 | void _start(); 10 | 11 | struct tss init_tss ={ 12 | .esp0 = 0x10000, 13 | .ss0_r = DATA_SELECTOR, 14 | .ss1_r = DATA_SELECTOR, 15 | .esp1 = 0x10000, 16 | .ss2_r = DATA_SELECTOR, 17 | .eip = 0x0, 18 | .esp2 = 0x10000, 19 | .esp = 0x10000, 20 | .eflags = 0x87, 21 | .es_r = VIDEO_SELECTOR, 22 | .cs_r = CODE_SELECTOR, 23 | .ds_r = DATA_SELECTOR, 24 | .ss_r = DATA_SELECTOR, 25 | .fs_r = DATA_SELECTOR, 26 | .gs_r = DATA_SELECTOR, 27 | }; 28 | 29 | void _start() { 30 | setup_gdt(&init_tss); 31 | setup_irq(); 32 | set_ds(0x10); 33 | set_ss(0x10); 34 | set_gs(0x28); 35 | putc('c', 15); 36 | /* int a = 3/0; */ 37 | /* asm("push 0x28"); */ 38 | /* asm("int 10"); */ 39 | /* asm("les ebx, es:0x12345678"); */ 40 | /* int a = 1/0; */ 41 | lapic_enable_timer(TIMER_PERIODIC, 0x100,TIMER_DIV_128, 32); 42 | 43 | /* Create an infinite loop for testing LAPIC. If the LAPIC timer handler is actually 44 | * called, it will return to the address after the loop and start task 1. It works so far. 45 | */ 46 | for (;;) {} 47 | INIT_TASK(task1); 48 | RUN_TASK(task1); 49 | 50 | /* ltr(0x28); */ 51 | /* asm("jmp 0x28:00"); */ 52 | } 53 | -------------------------------------------------------------------------------- /kernel/kernel.lds: -------------------------------------------------------------------------------- 1 | /* OUTPUT_FORMAT(elf32-i386); */ 2 | /* OUTPUT_ARCH(i386); */ 3 | 4 | ENTRY(_start); 5 | 6 | SECTIONS 7 | { 8 | .text 0x2000: ALIGN(0x1000) 9 | { 10 | . = 0x0; 11 | *(.text) 12 | } 13 | .data : 14 | { 15 | *(.data) 16 | } 17 | .bss 0x20000: 18 | { 19 | *(.bss) 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /kernel/kernel.o: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tuhdo/sample-os/09e25a85e2588bbcf68d935f76a2b4a7402a941e/kernel/kernel.o -------------------------------------------------------------------------------- /kernel/lapic.c: -------------------------------------------------------------------------------- 1 | #include "lapic.h" 2 | 3 | void lapic_enable_timer(uint8_t mode, uint32_t init_count, uint32_t div_config, uint32_t vec_num) { 4 | defpointer(uint32_t, timer_reg, TIMER_REG); 5 | defpointer(uint32_t, lapic_base, 0x1b); 6 | 7 | asm("mov ecx, 0x1b"); 8 | asm("rdmsr"); 9 | uint32_t lapic_version = lapic_get_version(); 10 | lapic_set_timer_initial_count(init_count); 11 | lapic_set_divide_config(div_config); 12 | *timer_reg = TIMER_MODE(TIMER_PERIODIC) | VECTOR(vec_num); 13 | uint32_t lapic_cur_count = lapic_get_current_timer_count(); 14 | uint32_t lapic_err_status = lapic_get_error_status(); 15 | uint32_t timer_r = lapic_get_timer_setting(); 16 | /* *lapic_base &= 0xFFFFFFFF00000FFF; */ 17 | /* *lapic_base |= (0x8000 << 11); */ 18 | } 19 | 20 | uint32_t lapic_get_version() { 21 | defpointer(uint32_t, ver, LAPIC_VERSION_REG); 22 | return *ver; 23 | } 24 | 25 | uint32_t lapic_get_timer_setting() { 26 | defpointer(uint32_t, timer_reg, TIMER_REG); 27 | return *timer_reg; 28 | } 29 | 30 | uint32_t lapic_get_current_timer_count() { 31 | defpointer(uint32_t, count, TIMER_CURRENT_COUNT_REG); 32 | return *count; 33 | } 34 | 35 | uint32_t lapic_get_error_status() { 36 | defpointer(uint32_t, status, LAPIC_ERROR_REG); 37 | return *status; 38 | } 39 | 40 | void lapic_set_timer_initial_count(uint32_t count) { 41 | defpointer(uint32_t, timer_init_count_reg, TIMER_INIT_COUNT_REG); 42 | *timer_init_count_reg = count; 43 | } 44 | 45 | void lapic_set_divide_config(uint32_t d) { 46 | defpointer(uint32_t, div_reg, TIMER_DIVIDE_CONFIG_REG); 47 | *div_reg = d; 48 | } 49 | -------------------------------------------------------------------------------- /kernel/lapic.h: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #define LAPIC_BASE 0xfee00000 4 | #define LAPIC_VERSION_REG LAPIC_BASE + 0x0030 5 | #define CMICI_REG LAPIC_BASE + 0x02F0 6 | #define THERMAL_MONITOR_REG LAPIC_BASE + 0x0330 7 | 8 | #define TIMER_REG LAPIC_BASE + 0x0320 9 | #define TIMER_INIT_COUNT_REG LAPIC_BASE + 0x0380 10 | #define TIMER_CURRENT_COUNT_REG LAPIC_BASE + 0x0390 11 | #define TIMER_DIVIDE_CONFIG_REG LAPIC_BASE + 0x03E0 12 | 13 | #define LAPIC_ISR_BASE LAPIC_BASE + 0x0100 14 | // #define LAPIC_ISR_32_63 LAPIC_BASE + 0x0110 15 | // #define LAPIC_ISR_64_95 LAPIC_BASE + 0x0120 16 | // #define LAPIC_ISR_96_127 LAPIC_BASE + 0x0130 17 | // #define LAPIC_ISR_128_159 LAPIC_BASE + 0x0140 18 | // #define LAPIC_ISR_160_191 LAPIC_BASE + 0x0150 19 | // #define LAPIC_ISR_192_223 LAPIC_BASE + 0x0160 20 | // #define LAPIC_ISR_224_255 LAPIC_BASE + 0x0170 21 | 22 | #define LAPIC_EIO_REG LAPIC_BASE + 0x00b0 23 | 24 | #define LAPIC_ERROR_REG LAPIC_BASE + 0x0280 25 | 26 | #define TIMER_ONE_SHOT 0x0 27 | #define TIMER_PERIODIC 0x1 28 | #define TIMER_TSC_DEADLINE 0x2 29 | 30 | #define TIMER_DIV_2 0x0 31 | #define TIMER_DIV_4 0x1 32 | #define TIMER_DIV_8 0x2 33 | #define TIMER_DIV_16 0x3 34 | #define TIMER_DIV_32 0x8 35 | #define TIMER_DIV_64 0x9 36 | #define TIMER_DIV_128 0xA 37 | #define TIMER_DIV_1 0xB 38 | 39 | #define TIMER_MODE(mode) (mode << 17) 40 | #define MASK(m) (m << 16) 41 | #define DELIVERY_STATUS(s) (s << 12) 42 | #define DELIVERY_MODE(s) (s << 8) 43 | #define VECTOR(v) v 44 | 45 | #define CONCATENATE_DETAILS(x,y) x ## y 46 | #define CONCATENATE(x,y) CONCATENATE_DETAILS(x, y) 47 | #define MAKE_UNIQE(x) CONCATENATE(x,__COUNTER__) 48 | 49 | 50 | #define defpointer(type, name, address) \ 51 | type* name = (type *)((uintptr_t) address); 52 | 53 | #define lapic_isr_complete(num) \ 54 | ; \ 55 | defpointer(uint32_t, eoi, LAPIC_EIO_REG); \ 56 | *eoi = 1; \ 57 | 58 | void lapic_enable_timer(uint8_t mode, uint32_t init_count, uint32_t div_config, uint32_t vec_num); 59 | uint32_t lapic_get_version(); 60 | uint32_t lapic_get_current_timer_count(); 61 | uint32_t lapic_get_error_status(); 62 | void lapic_set_timer_initial_count(uint32_t count); 63 | void lapic_set_divide_config(uint32_t d); 64 | uint32_t lapic_get_timer_setting(); 65 | -------------------------------------------------------------------------------- /kernel/task.c: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tuhdo/sample-os/09e25a85e2588bbcf68d935f76a2b4a7402a941e/kernel/task.c -------------------------------------------------------------------------------- /kernel/task.h: -------------------------------------------------------------------------------- 1 | #include "gdt.h" 2 | #include "asm.h" 3 | #include 4 | 5 | #pragma once 6 | 7 | /* Task State Structure records the machine state of a process */ 8 | struct tss { 9 | uint16_t link_r; 10 | uint16_t link_h; 11 | uint32_t esp0; 12 | uint16_t ss0_r; 13 | uint16_t ss0_h; 14 | uint32_t esp1; 15 | uint16_t ss1_r; 16 | uint16_t ss1_h; 17 | uint32_t esp2; 18 | uint16_t ss2_r; 19 | uint16_t ss2_h; 20 | uint32_t cr3; 21 | uint32_t eip; 22 | uint32_t eflags; 23 | uint32_t eax; 24 | uint32_t ecx; 25 | uint32_t edx; 26 | uint32_t ebx; 27 | uint32_t esp; 28 | uint32_t ebp; 29 | uint32_t esi; 30 | uint32_t edi; 31 | uint16_t es_r; 32 | uint16_t es_h; 33 | uint16_t cs_r; 34 | uint16_t cs_h; 35 | uint16_t ss_r; 36 | uint16_t ss_h; 37 | uint16_t ds_r; 38 | uint16_t ds_h; 39 | uint16_t fs_r; 40 | uint16_t fs_h; 41 | uint16_t gs_r; 42 | uint16_t gs_h; 43 | uint16_t ldt_r; 44 | uint16_t ldt_h; 45 | uint16_t trap_r; 46 | uint16_t io_base; 47 | }; 48 | 49 | extern struct tss init_tss; 50 | 51 | /* Add a descriptor entry to the Local Descriptor Table of a process */ 52 | #define ldt_add_segment(name, base, limit, access) \ 53 | add_segment(name, base, limit, access, 0x0, 1) 54 | 55 | /* Statically allocate a task/process image right inside the kernel */ 56 | #define TASK_REGISTER(name) \ 57 | void name ## _start(); \ 58 | void name ## _init(); \ 59 | extern uint16_t task_id_##name \ 60 | 61 | /* Shift 3 bits to put the task selector value in the variable into the proper location in the Task Register */ 62 | #define TASK_SELECTOR(name) (task_id_##name << 3) 63 | 64 | /* 0x35000 is the currently chosen starting address for process storage. */ 65 | #define TASK_DATA_ADDRESS(id) 0x35000 + id * 0x1000 66 | 67 | /* 68 | * Generate init data and functions for every registered process (using TASK_REGISTER above) 69 | * Currently, the kernel records the start and end of a process code segment by wrapping the code around the 2 calls: 70 | * TAKS_START() and TASK_END(). Here is how to use the 2 macros accurately: 71 | * 72 | * TASK_START(task_name, init_func) 73 | * ..... task code ..... 74 | * TASK_END() 75 | * 76 | * - TASK_START marks the start of a code segment and TASK_END marks the end. The code length is calculated 77 | * from the difference between the two points. 78 | * 79 | * For example usage, see irq.c. 80 | */ 81 | #define TASK_START(name, init_func) \ 82 | void __TASK_END_##name(); \ 83 | void __TASK_START_##name(){} \ 84 | \ 85 | segment_descriptor name##_ldt_segments[3]; \ 86 | ldt_t ldt_##name; \ 87 | uint16_t task_id_##name; \ 88 | struct tss name##_tss = { \ 89 | .link_r = 0x3 << 3, \ 90 | .ss0_r = DATA_SELECTOR, \ 91 | .eip = (uintptr_t) init_func, \ 92 | .esp = 0x3000, \ 93 | .eflags = 0x87, \ 94 | .cr3 = 0x2000, \ 95 | .es_r = VIDEO_SELECTOR, \ 96 | .cs_r = CODE_SELECTOR, \ 97 | .ds_r = DATA_SELECTOR, \ 98 | .ss_r = DATA_SELECTOR, \ 99 | .fs_r = DATA_SELECTOR, \ 100 | .gs_r = DATA_SELECTOR, \ 101 | }; \ 102 | \ 103 | void name##_init() { \ 104 | uint16_t ldt_id; \ 105 | ldt_##name.base = name##_ldt_segments; \ 106 | ldt_##name.size = DESCRIPTOR_SIZE * 3; \ 107 | ldt_##name.free_id = 0; \ 108 | \ 109 | task_id_##name = gdt_add_segment((uintptr_t) &name##_tss, 0x067, \ 110 | SEG1B | SEG_AVAILABLE_1 | SEG_LIMIT_16_19(0x0) | \ 111 | SEG_PRESENT | SEG_RING0 | SEG_SYSTEM | SEG_TSS32_AVAILABLE); \ 112 | ldt_id = gdt_add_segment((uintptr_t) &name##_ldt_segments, ldt_##name.size, \ 113 | SEG1B | SEG32 | SEG64_0 | SEG_LIMIT_16_19(0x0) | \ 114 | SEG_PRESENT | SEG_RING0 | SEG_SYSTEM | SEG_LDT); \ 115 | \ 116 | name##_tss.esp0 = TASK_DATA_ADDRESS(task_id_##name); \ 117 | name##_tss.esp = TASK_DATA_ADDRESS(task_id_##name); \ 118 | name##_tss.ldt_r = ldt_id << 3; \ 119 | \ 120 | ldt_add_segment(&ldt_##name, 0, 0, 0); \ 121 | ldt_add_segment(&ldt_##name, (uintptr_t) __TASK_START_##name, \ 122 | __TASK_END_##name - __TASK_START_##name, \ 123 | SEG4K | SEG_AVAILABLE_1 | SEG32 | SEG64_0 | \ 124 | SEG_LIMIT_16_19(0xf) | SEG_PRESENT | SEG_RING0 | \ 125 | SEG_CODE_DATA | SEG_XR); \ 126 | \ 127 | ldt_add_segment(&ldt_##name, TASK_DATA_ADDRESS(task_id_##name), \ 128 | 0xFFFF, \ 129 | SEG4K | SEG_AVAILABLE_1 | SEG32 | SEG64_0 | SEG_LIMIT_16_19(0xf) | \ 130 | SEG_PRESENT | SEG_RING0 | SEG_CODE_DATA | SEG_RWE); \ 131 | } \ 132 | /* 0xa0 is the ID of the first task descriptor in the GDT table. \ 133 | At the moment, there are 20 descriptors in GDT, 8 bytes each. \ 134 | So, the first task descriptor offset is at 0xa0. \ 135 | Currently hardcoded for testing. */ \ 136 | void name##_start() { \ 137 | asm("pushw 0xa0"); \ 138 | asm("pushd 0x0"); \ 139 | asm("jmp FAR PTR [esp]"); \ 140 | } 141 | 142 | #define INIT_TASK(name) name ## _init() 143 | #define RUN_TASK(name) name ## _start() 144 | #define TASK_END(name) void __TASK_END_##name() {} 145 | #define TASK_START_ADDRESS(name) (uintptr_t) &name##_start 146 | 147 | // asm("call 0x98:0x0":::); 148 | -------------------------------------------------------------------------------- /kernel/task.s: -------------------------------------------------------------------------------- 1 | .file "task.c" 2 | .intel_syntax noprefix 3 | .text 4 | .Ltext0: 5 | .cfi_sections .debug_frame 6 | .Letext0: 7 | .section .debug_info,"",@progbits 8 | .Ldebug_info0: 9 | .long 0x1d 10 | .value 0x2 11 | .long .Ldebug_abbrev0 12 | .byte 0x4 13 | .uleb128 0x1 14 | .long .LASF239 15 | .byte 0xc 16 | .long .LASF240 17 | .long .LASF241 18 | .long .Ldebug_line0 19 | .long .Ldebug_macro0 20 | .section .debug_abbrev,"",@progbits 21 | .Ldebug_abbrev0: 22 | .uleb128 0x1 23 | .uleb128 0x11 24 | .byte 0 25 | .uleb128 0x25 26 | .uleb128 0xe 27 | .uleb128 0x13 28 | .uleb128 0xb 29 | .uleb128 0x3 30 | .uleb128 0xe 31 | .uleb128 0x1b 32 | .uleb128 0xe 33 | .uleb128 0x10 34 | .uleb128 0x6 35 | .uleb128 0x2119 36 | .uleb128 0x6 37 | .byte 0 38 | .byte 0 39 | .byte 0 40 | .section .debug_aranges,"",@progbits 41 | .long 0x14 42 | .value 0x2 43 | .long .Ldebug_info0 44 | .byte 0x4 45 | .byte 0 46 | .value 0 47 | .value 0 48 | .long 0 49 | .long 0 50 | .section .debug_macro,"",@progbits 51 | .Ldebug_macro0: 52 | .value 0x4 53 | .byte 0x2 54 | .long .Ldebug_line0 55 | .file 1 "task.c" 56 | .byte 0x3 57 | .uleb128 0 58 | .uleb128 0x1 59 | .byte 0x5 60 | .uleb128 0x1 61 | .long .LASF0 62 | .byte 0x5 63 | .uleb128 0x2 64 | .long .LASF1 65 | .byte 0x5 66 | .uleb128 0x3 67 | .long .LASF2 68 | .byte 0x5 69 | .uleb128 0x4 70 | .long .LASF3 71 | .byte 0x5 72 | .uleb128 0x5 73 | .long .LASF4 74 | .byte 0x5 75 | .uleb128 0x6 76 | .long .LASF5 77 | .byte 0x5 78 | .uleb128 0x7 79 | .long .LASF6 80 | .byte 0x5 81 | .uleb128 0x8 82 | .long .LASF7 83 | .byte 0x5 84 | .uleb128 0x9 85 | .long .LASF8 86 | .byte 0x5 87 | .uleb128 0xa 88 | .long .LASF9 89 | .byte 0x5 90 | .uleb128 0xb 91 | .long .LASF10 92 | .byte 0x5 93 | .uleb128 0xc 94 | .long .LASF11 95 | .byte 0x5 96 | .uleb128 0xd 97 | .long .LASF12 98 | .byte 0x5 99 | .uleb128 0xe 100 | .long .LASF13 101 | .byte 0x5 102 | .uleb128 0xf 103 | .long .LASF14 104 | .byte 0x5 105 | .uleb128 0x10 106 | .long .LASF15 107 | .byte 0x5 108 | .uleb128 0x11 109 | .long .LASF16 110 | .byte 0x5 111 | .uleb128 0x12 112 | .long .LASF17 113 | .byte 0x5 114 | .uleb128 0x13 115 | .long .LASF18 116 | .byte 0x5 117 | .uleb128 0x14 118 | .long .LASF19 119 | .byte 0x5 120 | .uleb128 0x15 121 | .long .LASF20 122 | .byte 0x5 123 | .uleb128 0x16 124 | .long .LASF21 125 | .byte 0x5 126 | .uleb128 0x17 127 | .long .LASF22 128 | .byte 0x5 129 | .uleb128 0x18 130 | .long .LASF23 131 | .byte 0x5 132 | .uleb128 0x19 133 | .long .LASF24 134 | .byte 0x5 135 | .uleb128 0x1a 136 | .long .LASF25 137 | .byte 0x5 138 | .uleb128 0x1b 139 | .long .LASF26 140 | .byte 0x5 141 | .uleb128 0x1c 142 | .long .LASF27 143 | .byte 0x5 144 | .uleb128 0x1d 145 | .long .LASF28 146 | .byte 0x5 147 | .uleb128 0x1e 148 | .long .LASF29 149 | .byte 0x5 150 | .uleb128 0x1f 151 | .long .LASF30 152 | .byte 0x5 153 | .uleb128 0x20 154 | .long .LASF31 155 | .byte 0x5 156 | .uleb128 0x21 157 | .long .LASF32 158 | .byte 0x5 159 | .uleb128 0x22 160 | .long .LASF33 161 | .byte 0x5 162 | .uleb128 0x23 163 | .long .LASF34 164 | .byte 0x5 165 | .uleb128 0x24 166 | .long .LASF35 167 | .byte 0x5 168 | .uleb128 0x25 169 | .long .LASF36 170 | .byte 0x5 171 | .uleb128 0x26 172 | .long .LASF37 173 | .byte 0x5 174 | .uleb128 0x27 175 | .long .LASF38 176 | .byte 0x5 177 | .uleb128 0x28 178 | .long .LASF39 179 | .byte 0x5 180 | .uleb128 0x29 181 | .long .LASF40 182 | .byte 0x5 183 | .uleb128 0x2a 184 | .long .LASF41 185 | .byte 0x5 186 | .uleb128 0x2b 187 | .long .LASF42 188 | .byte 0x5 189 | .uleb128 0x2c 190 | .long .LASF43 191 | .byte 0x5 192 | .uleb128 0x2d 193 | .long .LASF44 194 | .byte 0x5 195 | .uleb128 0x2e 196 | .long .LASF45 197 | .byte 0x5 198 | .uleb128 0x2f 199 | .long .LASF46 200 | .byte 0x5 201 | .uleb128 0x30 202 | .long .LASF47 203 | .byte 0x5 204 | .uleb128 0x31 205 | .long .LASF48 206 | .byte 0x5 207 | .uleb128 0x32 208 | .long .LASF49 209 | .byte 0x5 210 | .uleb128 0x33 211 | .long .LASF50 212 | .byte 0x5 213 | .uleb128 0x34 214 | .long .LASF51 215 | .byte 0x5 216 | .uleb128 0x35 217 | .long .LASF52 218 | .byte 0x5 219 | .uleb128 0x36 220 | .long .LASF53 221 | .byte 0x5 222 | .uleb128 0x37 223 | .long .LASF54 224 | .byte 0x5 225 | .uleb128 0x38 226 | .long .LASF55 227 | .byte 0x5 228 | .uleb128 0x39 229 | .long .LASF56 230 | .byte 0x5 231 | .uleb128 0x3a 232 | .long .LASF57 233 | .byte 0x5 234 | .uleb128 0x3b 235 | .long .LASF58 236 | .byte 0x5 237 | .uleb128 0x3c 238 | .long .LASF59 239 | .byte 0x5 240 | .uleb128 0x3d 241 | .long .LASF60 242 | .byte 0x5 243 | .uleb128 0x3e 244 | .long .LASF61 245 | .byte 0x5 246 | .uleb128 0x3f 247 | .long .LASF62 248 | .byte 0x5 249 | .uleb128 0x40 250 | .long .LASF63 251 | .byte 0x5 252 | .uleb128 0x41 253 | .long .LASF64 254 | .byte 0x5 255 | .uleb128 0x42 256 | .long .LASF65 257 | .byte 0x5 258 | .uleb128 0x43 259 | .long .LASF66 260 | .byte 0x5 261 | .uleb128 0x44 262 | .long .LASF67 263 | .byte 0x5 264 | .uleb128 0x45 265 | .long .LASF68 266 | .byte 0x5 267 | .uleb128 0x46 268 | .long .LASF69 269 | .byte 0x5 270 | .uleb128 0x47 271 | .long .LASF70 272 | .byte 0x5 273 | .uleb128 0x48 274 | .long .LASF71 275 | .byte 0x5 276 | .uleb128 0x49 277 | .long .LASF72 278 | .byte 0x5 279 | .uleb128 0x4a 280 | .long .LASF73 281 | .byte 0x5 282 | .uleb128 0x4b 283 | .long .LASF74 284 | .byte 0x5 285 | .uleb128 0x4c 286 | .long .LASF75 287 | .byte 0x5 288 | .uleb128 0x4d 289 | .long .LASF76 290 | .byte 0x5 291 | .uleb128 0x4e 292 | .long .LASF77 293 | .byte 0x5 294 | .uleb128 0x4f 295 | .long .LASF78 296 | .byte 0x5 297 | .uleb128 0x50 298 | .long .LASF79 299 | .byte 0x5 300 | .uleb128 0x51 301 | .long .LASF80 302 | .byte 0x5 303 | .uleb128 0x52 304 | .long .LASF81 305 | .byte 0x5 306 | .uleb128 0x53 307 | .long .LASF82 308 | .byte 0x5 309 | .uleb128 0x54 310 | .long .LASF83 311 | .byte 0x5 312 | .uleb128 0x55 313 | .long .LASF84 314 | .byte 0x5 315 | .uleb128 0x56 316 | .long .LASF85 317 | .byte 0x5 318 | .uleb128 0x57 319 | .long .LASF86 320 | .byte 0x5 321 | .uleb128 0x58 322 | .long .LASF87 323 | .byte 0x5 324 | .uleb128 0x59 325 | .long .LASF88 326 | .byte 0x5 327 | .uleb128 0x5a 328 | .long .LASF89 329 | .byte 0x5 330 | .uleb128 0x5b 331 | .long .LASF90 332 | .byte 0x5 333 | .uleb128 0x5c 334 | .long .LASF91 335 | .byte 0x5 336 | .uleb128 0x5d 337 | .long .LASF92 338 | .byte 0x5 339 | .uleb128 0x5e 340 | .long .LASF93 341 | .byte 0x5 342 | .uleb128 0x5f 343 | .long .LASF94 344 | .byte 0x5 345 | .uleb128 0x60 346 | .long .LASF95 347 | .byte 0x5 348 | .uleb128 0x61 349 | .long .LASF96 350 | .byte 0x5 351 | .uleb128 0x62 352 | .long .LASF97 353 | .byte 0x5 354 | .uleb128 0x63 355 | .long .LASF98 356 | .byte 0x5 357 | .uleb128 0x64 358 | .long .LASF99 359 | .byte 0x5 360 | .uleb128 0x65 361 | .long .LASF100 362 | .byte 0x5 363 | .uleb128 0x66 364 | .long .LASF101 365 | .byte 0x5 366 | .uleb128 0x67 367 | .long .LASF102 368 | .byte 0x5 369 | .uleb128 0x68 370 | .long .LASF103 371 | .byte 0x5 372 | .uleb128 0x69 373 | .long .LASF104 374 | .byte 0x5 375 | .uleb128 0x6a 376 | .long .LASF105 377 | .byte 0x5 378 | .uleb128 0x6b 379 | .long .LASF106 380 | .byte 0x5 381 | .uleb128 0x6c 382 | .long .LASF107 383 | .byte 0x5 384 | .uleb128 0x6d 385 | .long .LASF108 386 | .byte 0x5 387 | .uleb128 0x6e 388 | .long .LASF109 389 | .byte 0x5 390 | .uleb128 0x6f 391 | .long .LASF110 392 | .byte 0x5 393 | .uleb128 0x70 394 | .long .LASF111 395 | .byte 0x5 396 | .uleb128 0x71 397 | .long .LASF112 398 | .byte 0x5 399 | .uleb128 0x72 400 | .long .LASF113 401 | .byte 0x5 402 | .uleb128 0x73 403 | .long .LASF114 404 | .byte 0x5 405 | .uleb128 0x74 406 | .long .LASF115 407 | .byte 0x5 408 | .uleb128 0x75 409 | .long .LASF116 410 | .byte 0x5 411 | .uleb128 0x76 412 | .long .LASF117 413 | .byte 0x5 414 | .uleb128 0x77 415 | .long .LASF118 416 | .byte 0x5 417 | .uleb128 0x78 418 | .long .LASF119 419 | .byte 0x5 420 | .uleb128 0x79 421 | .long .LASF120 422 | .byte 0x5 423 | .uleb128 0x7a 424 | .long .LASF121 425 | .byte 0x5 426 | .uleb128 0x7b 427 | .long .LASF122 428 | .byte 0x5 429 | .uleb128 0x7c 430 | .long .LASF123 431 | .byte 0x5 432 | .uleb128 0x7d 433 | .long .LASF124 434 | .byte 0x5 435 | .uleb128 0x7e 436 | .long .LASF125 437 | .byte 0x5 438 | .uleb128 0x7f 439 | .long .LASF126 440 | .byte 0x5 441 | .uleb128 0x80 442 | .long .LASF127 443 | .byte 0x5 444 | .uleb128 0x81 445 | .long .LASF128 446 | .byte 0x5 447 | .uleb128 0x82 448 | .long .LASF129 449 | .byte 0x5 450 | .uleb128 0x83 451 | .long .LASF130 452 | .byte 0x5 453 | .uleb128 0x84 454 | .long .LASF131 455 | .byte 0x5 456 | .uleb128 0x85 457 | .long .LASF132 458 | .byte 0x5 459 | .uleb128 0x86 460 | .long .LASF133 461 | .byte 0x5 462 | .uleb128 0x87 463 | .long .LASF134 464 | .byte 0x5 465 | .uleb128 0x88 466 | .long .LASF135 467 | .byte 0x5 468 | .uleb128 0x89 469 | .long .LASF136 470 | .byte 0x5 471 | .uleb128 0x8a 472 | .long .LASF137 473 | .byte 0x5 474 | .uleb128 0x8b 475 | .long .LASF138 476 | .byte 0x5 477 | .uleb128 0x8c 478 | .long .LASF139 479 | .byte 0x5 480 | .uleb128 0x8d 481 | .long .LASF140 482 | .byte 0x5 483 | .uleb128 0x8e 484 | .long .LASF141 485 | .byte 0x5 486 | .uleb128 0x8f 487 | .long .LASF142 488 | .byte 0x5 489 | .uleb128 0x90 490 | .long .LASF143 491 | .byte 0x5 492 | .uleb128 0x91 493 | .long .LASF144 494 | .byte 0x5 495 | .uleb128 0x92 496 | .long .LASF145 497 | .byte 0x5 498 | .uleb128 0x93 499 | .long .LASF146 500 | .byte 0x5 501 | .uleb128 0x94 502 | .long .LASF147 503 | .byte 0x5 504 | .uleb128 0x95 505 | .long .LASF148 506 | .byte 0x5 507 | .uleb128 0x96 508 | .long .LASF149 509 | .byte 0x5 510 | .uleb128 0x97 511 | .long .LASF150 512 | .byte 0x5 513 | .uleb128 0x98 514 | .long .LASF151 515 | .byte 0x5 516 | .uleb128 0x99 517 | .long .LASF152 518 | .byte 0x5 519 | .uleb128 0x9a 520 | .long .LASF153 521 | .byte 0x5 522 | .uleb128 0x9b 523 | .long .LASF154 524 | .byte 0x5 525 | .uleb128 0x9c 526 | .long .LASF155 527 | .byte 0x5 528 | .uleb128 0x9d 529 | .long .LASF156 530 | .byte 0x5 531 | .uleb128 0x9e 532 | .long .LASF157 533 | .byte 0x5 534 | .uleb128 0x9f 535 | .long .LASF158 536 | .byte 0x5 537 | .uleb128 0xa0 538 | .long .LASF159 539 | .byte 0x5 540 | .uleb128 0xa1 541 | .long .LASF160 542 | .byte 0x5 543 | .uleb128 0xa2 544 | .long .LASF161 545 | .byte 0x5 546 | .uleb128 0xa3 547 | .long .LASF162 548 | .byte 0x5 549 | .uleb128 0xa4 550 | .long .LASF163 551 | .byte 0x5 552 | .uleb128 0xa5 553 | .long .LASF164 554 | .byte 0x5 555 | .uleb128 0xa6 556 | .long .LASF165 557 | .byte 0x5 558 | .uleb128 0xa7 559 | .long .LASF166 560 | .byte 0x5 561 | .uleb128 0xa8 562 | .long .LASF167 563 | .byte 0x5 564 | .uleb128 0xa9 565 | .long .LASF168 566 | .byte 0x5 567 | .uleb128 0xaa 568 | .long .LASF169 569 | .byte 0x5 570 | .uleb128 0xab 571 | .long .LASF170 572 | .byte 0x5 573 | .uleb128 0xac 574 | .long .LASF171 575 | .byte 0x5 576 | .uleb128 0xad 577 | .long .LASF172 578 | .byte 0x5 579 | .uleb128 0xae 580 | .long .LASF173 581 | .byte 0x5 582 | .uleb128 0xaf 583 | .long .LASF174 584 | .byte 0x5 585 | .uleb128 0xb0 586 | .long .LASF175 587 | .byte 0x5 588 | .uleb128 0xb1 589 | .long .LASF176 590 | .byte 0x5 591 | .uleb128 0xb2 592 | .long .LASF177 593 | .byte 0x5 594 | .uleb128 0xb3 595 | .long .LASF178 596 | .byte 0x5 597 | .uleb128 0xb4 598 | .long .LASF179 599 | .byte 0x5 600 | .uleb128 0xb5 601 | .long .LASF180 602 | .byte 0x5 603 | .uleb128 0xb6 604 | .long .LASF181 605 | .byte 0x5 606 | .uleb128 0xb7 607 | .long .LASF182 608 | .byte 0x5 609 | .uleb128 0xb8 610 | .long .LASF183 611 | .byte 0x5 612 | .uleb128 0xb9 613 | .long .LASF184 614 | .byte 0x5 615 | .uleb128 0xba 616 | .long .LASF185 617 | .byte 0x5 618 | .uleb128 0xbb 619 | .long .LASF186 620 | .byte 0x5 621 | .uleb128 0xbc 622 | .long .LASF187 623 | .byte 0x5 624 | .uleb128 0xbd 625 | .long .LASF188 626 | .byte 0x5 627 | .uleb128 0xbe 628 | .long .LASF189 629 | .byte 0x5 630 | .uleb128 0xbf 631 | .long .LASF190 632 | .byte 0x5 633 | .uleb128 0xc0 634 | .long .LASF191 635 | .byte 0x5 636 | .uleb128 0xc1 637 | .long .LASF192 638 | .byte 0x5 639 | .uleb128 0xc2 640 | .long .LASF193 641 | .byte 0x5 642 | .uleb128 0xc3 643 | .long .LASF194 644 | .byte 0x5 645 | .uleb128 0xc4 646 | .long .LASF195 647 | .byte 0x5 648 | .uleb128 0xc5 649 | .long .LASF196 650 | .byte 0x5 651 | .uleb128 0xc6 652 | .long .LASF197 653 | .byte 0x5 654 | .uleb128 0xc7 655 | .long .LASF198 656 | .byte 0x5 657 | .uleb128 0xc8 658 | .long .LASF199 659 | .byte 0x5 660 | .uleb128 0xc9 661 | .long .LASF200 662 | .byte 0x5 663 | .uleb128 0xca 664 | .long .LASF201 665 | .byte 0x5 666 | .uleb128 0xcb 667 | .long .LASF202 668 | .byte 0x5 669 | .uleb128 0xcc 670 | .long .LASF203 671 | .byte 0x5 672 | .uleb128 0xcd 673 | .long .LASF204 674 | .byte 0x5 675 | .uleb128 0xce 676 | .long .LASF205 677 | .byte 0x5 678 | .uleb128 0xcf 679 | .long .LASF206 680 | .byte 0x5 681 | .uleb128 0xd0 682 | .long .LASF207 683 | .byte 0x5 684 | .uleb128 0xd1 685 | .long .LASF208 686 | .byte 0x5 687 | .uleb128 0xd2 688 | .long .LASF209 689 | .byte 0x5 690 | .uleb128 0xd3 691 | .long .LASF210 692 | .byte 0x5 693 | .uleb128 0xd4 694 | .long .LASF211 695 | .byte 0x5 696 | .uleb128 0xd5 697 | .long .LASF212 698 | .byte 0x5 699 | .uleb128 0xd6 700 | .long .LASF213 701 | .byte 0x5 702 | .uleb128 0xd7 703 | .long .LASF214 704 | .byte 0x5 705 | .uleb128 0xd8 706 | .long .LASF215 707 | .byte 0x5 708 | .uleb128 0xd9 709 | .long .LASF216 710 | .byte 0x5 711 | .uleb128 0xda 712 | .long .LASF217 713 | .byte 0x5 714 | .uleb128 0xdb 715 | .long .LASF218 716 | .byte 0x5 717 | .uleb128 0xdc 718 | .long .LASF219 719 | .byte 0x5 720 | .uleb128 0xdd 721 | .long .LASF220 722 | .byte 0x5 723 | .uleb128 0xde 724 | .long .LASF221 725 | .byte 0x5 726 | .uleb128 0xdf 727 | .long .LASF222 728 | .byte 0x5 729 | .uleb128 0xe0 730 | .long .LASF223 731 | .byte 0x5 732 | .uleb128 0xe1 733 | .long .LASF224 734 | .byte 0x5 735 | .uleb128 0xe2 736 | .long .LASF225 737 | .byte 0x5 738 | .uleb128 0xe3 739 | .long .LASF226 740 | .byte 0x5 741 | .uleb128 0xe4 742 | .long .LASF227 743 | .byte 0x5 744 | .uleb128 0xe5 745 | .long .LASF228 746 | .byte 0x5 747 | .uleb128 0xe6 748 | .long .LASF229 749 | .byte 0x5 750 | .uleb128 0xe7 751 | .long .LASF230 752 | .byte 0x5 753 | .uleb128 0xe8 754 | .long .LASF231 755 | .byte 0x5 756 | .uleb128 0xe9 757 | .long .LASF232 758 | .byte 0x5 759 | .uleb128 0xea 760 | .long .LASF233 761 | .file 2 "/usr/include/stdc-predef.h" 762 | .byte 0x3 763 | .uleb128 0x1 764 | .uleb128 0x2 765 | .byte 0x7 766 | .long .Ldebug_macro1 767 | .byte 0x4 768 | .byte 0x4 769 | .byte 0 770 | .section .debug_macro,"G",@progbits,wm4.stdcpredef.h.19.bf2bf6c5fb087dfb5ef2d2297c2795de,comdat 771 | .Ldebug_macro1: 772 | .value 0x4 773 | .byte 0 774 | .byte 0x5 775 | .uleb128 0x13 776 | .long .LASF234 777 | .byte 0x5 778 | .uleb128 0x26 779 | .long .LASF235 780 | .byte 0x5 781 | .uleb128 0x2e 782 | .long .LASF236 783 | .byte 0x5 784 | .uleb128 0x37 785 | .long .LASF237 786 | .byte 0x5 787 | .uleb128 0x3a 788 | .long .LASF238 789 | .byte 0 790 | .section .debug_line,"",@progbits 791 | .Ldebug_line0: 792 | .section .debug_str,"MS",@progbits,1 793 | .LASF103: 794 | .string "__UINT_LEAST8_MAX__ 0xff" 795 | .LASF150: 796 | .string "__DBL_DENORM_MIN__ ((double)4.94065645841246544177e-324L)" 797 | .LASF110: 798 | .string "__UINT64_C(c) c ## ULL" 799 | .LASF23: 800 | .string "__SIZEOF_SIZE_T__ 4" 801 | .LASF226: 802 | .string "__linux 1" 803 | .LASF107: 804 | .string "__UINT_LEAST32_MAX__ 0xffffffffU" 805 | .LASF102: 806 | .string "__INT64_C(c) c ## LL" 807 | .LASF31: 808 | .string "__SIZEOF_POINTER__ 4" 809 | .LASF1: 810 | .string "__STDC_VERSION__ 201112L" 811 | .LASF183: 812 | .string "__DEC128_MIN_EXP__ (-6142)" 813 | .LASF175: 814 | .string "__DEC64_MANT_DIG__ 16" 815 | .LASF125: 816 | .string "__FLT_RADIX__ 2" 817 | .LASF84: 818 | .string "__UINTMAX_C(c) c ## ULL" 819 | .LASF171: 820 | .string "__DEC32_MIN__ 1E-95DF" 821 | .LASF48: 822 | .string "__UINT64_TYPE__ long long unsigned int" 823 | .LASF230: 824 | .string "__unix__ 1" 825 | .LASF159: 826 | .string "__LDBL_MAX_10_EXP__ 4932" 827 | .LASF10: 828 | .string "__ATOMIC_SEQ_CST 5" 829 | .LASF211: 830 | .string "__SIZEOF_WINT_T__ 4" 831 | .LASF162: 832 | .string "__LDBL_MIN__ 3.36210314311209350626e-4932L" 833 | .LASF202: 834 | .string "__GCC_ATOMIC_SHORT_LOCK_FREE 2" 835 | .LASF229: 836 | .string "__unix 1" 837 | .LASF24: 838 | .string "__CHAR_BIT__ 8" 839 | .LASF152: 840 | .string "__DBL_HAS_INFINITY__ 1" 841 | .LASF47: 842 | .string "__UINT32_TYPE__ unsigned int" 843 | .LASF227: 844 | .string "__linux__ 1" 845 | .LASF223: 846 | .string "__pentiumpro__ 1" 847 | .LASF4: 848 | .string "__STDC_HOSTED__ 1" 849 | .LASF80: 850 | .string "__SIZE_MAX__ 0xffffffffU" 851 | .LASF217: 852 | .string "__SIZEOF_FLOAT128__ 16" 853 | .LASF77: 854 | .string "__WINT_MAX__ 0xffffffffU" 855 | .LASF32: 856 | .string "__SIZE_TYPE__ unsigned int" 857 | .LASF181: 858 | .string "__DEC64_SUBNORMAL_MIN__ 0.000000000000001E-383DD" 859 | .LASF133: 860 | .string "__FLT_MAX__ 3.40282346638528859812e+38F" 861 | .LASF140: 862 | .string "__DBL_MANT_DIG__ 53" 863 | .LASF56: 864 | .string "__UINT_LEAST64_TYPE__ long long unsigned int" 865 | .LASF111: 866 | .string "__INT_FAST8_MAX__ 0x7f" 867 | .LASF153: 868 | .string "__DBL_HAS_QUIET_NAN__ 1" 869 | .LASF101: 870 | .string "__INT_LEAST64_MAX__ 0x7fffffffffffffffLL" 871 | .LASF45: 872 | .string "__UINT8_TYPE__ unsigned char" 873 | .LASF170: 874 | .string "__DEC32_MAX_EXP__ 97" 875 | .LASF43: 876 | .string "__INT32_TYPE__ int" 877 | .LASF40: 878 | .string "__SIG_ATOMIC_TYPE__ int" 879 | .LASF17: 880 | .string "__SIZEOF_LONG__ 4" 881 | .LASF166: 882 | .string "__LDBL_HAS_INFINITY__ 1" 883 | .LASF137: 884 | .string "__FLT_HAS_DENORM__ 1" 885 | .LASF212: 886 | .string "__SIZEOF_PTRDIFF_T__ 4" 887 | .LASF116: 888 | .string "__UINT_FAST16_MAX__ 0xffffffffU" 889 | .LASF119: 890 | .string "__INTPTR_MAX__ 0x7fffffff" 891 | .LASF92: 892 | .string "__UINT16_MAX__ 0xffff" 893 | .LASF201: 894 | .string "__GCC_ATOMIC_WCHAR_T_LOCK_FREE 2" 895 | .LASF41: 896 | .string "__INT8_TYPE__ signed char" 897 | .LASF29: 898 | .string "__BYTE_ORDER__ __ORDER_LITTLE_ENDIAN__" 899 | .LASF90: 900 | .string "__INT64_MAX__ 0x7fffffffffffffffLL" 901 | .LASF30: 902 | .string "__FLOAT_WORD_ORDER__ __ORDER_LITTLE_ENDIAN__" 903 | .LASF105: 904 | .string "__UINT_LEAST16_MAX__ 0xffff" 905 | .LASF209: 906 | .string "__PRAGMA_REDEFINE_EXTNAME 1" 907 | .LASF50: 908 | .string "__INT_LEAST16_TYPE__ short int" 909 | .LASF58: 910 | .string "__INT_FAST16_TYPE__ int" 911 | .LASF160: 912 | .string "__DECIMAL_DIG__ 21" 913 | .LASF68: 914 | .string "__has_include_next(STR) __has_include_next__(STR)" 915 | .LASF81: 916 | .string "__INTMAX_MAX__ 0x7fffffffffffffffLL" 917 | .LASF213: 918 | .string "__i386 1" 919 | .LASF147: 920 | .string "__DBL_MAX__ ((double)1.79769313486231570815e+308L)" 921 | .LASF42: 922 | .string "__INT16_TYPE__ short int" 923 | .LASF167: 924 | .string "__LDBL_HAS_QUIET_NAN__ 1" 925 | .LASF21: 926 | .string "__SIZEOF_DOUBLE__ 8" 927 | .LASF91: 928 | .string "__UINT8_MAX__ 0xff" 929 | .LASF96: 930 | .string "__INT8_C(c) c" 931 | .LASF51: 932 | .string "__INT_LEAST32_TYPE__ int" 933 | .LASF219: 934 | .string "__ATOMIC_HLE_RELEASE 131072" 935 | .LASF215: 936 | .string "i386 1" 937 | .LASF89: 938 | .string "__INT32_MAX__ 0x7fffffff" 939 | .LASF233: 940 | .string "__DECIMAL_BID_FORMAT__ 1" 941 | .LASF200: 942 | .string "__GCC_ATOMIC_CHAR32_T_LOCK_FREE 2" 943 | .LASF220: 944 | .string "__i686 1" 945 | .LASF65: 946 | .string "__INTPTR_TYPE__ int" 947 | .LASF37: 948 | .string "__UINTMAX_TYPE__ long long unsigned int" 949 | .LASF118: 950 | .string "__UINT_FAST64_MAX__ 0xffffffffffffffffULL" 951 | .LASF156: 952 | .string "__LDBL_MIN_EXP__ (-16381)" 953 | .LASF18: 954 | .string "__SIZEOF_LONG_LONG__ 8" 955 | .LASF127: 956 | .string "__FLT_DIG__ 6" 957 | .LASF210: 958 | .string "__SIZEOF_WCHAR_T__ 4" 959 | .LASF12: 960 | .string "__ATOMIC_RELEASE 3" 961 | .LASF240: 962 | .string "task.c" 963 | .LASF134: 964 | .string "__FLT_MIN__ 1.17549435082228750797e-38F" 965 | .LASF78: 966 | .string "__WINT_MIN__ 0U" 967 | .LASF70: 968 | .string "__SCHAR_MAX__ 0x7f" 969 | .LASF94: 970 | .string "__UINT64_MAX__ 0xffffffffffffffffULL" 971 | .LASF6: 972 | .string "__GNUC_MINOR__ 4" 973 | .LASF124: 974 | .string "__DEC_EVAL_METHOD__ 2" 975 | .LASF172: 976 | .string "__DEC32_MAX__ 9.999999E96DF" 977 | .LASF74: 978 | .string "__LONG_LONG_MAX__ 0x7fffffffffffffffLL" 979 | .LASF197: 980 | .string "__GCC_ATOMIC_BOOL_LOCK_FREE 2" 981 | .LASF122: 982 | .string "__GCC_IEC_559_COMPLEX 2" 983 | .LASF139: 984 | .string "__FLT_HAS_QUIET_NAN__ 1" 985 | .LASF149: 986 | .string "__DBL_EPSILON__ ((double)2.22044604925031308085e-16L)" 987 | .LASF128: 988 | .string "__FLT_MIN_EXP__ (-125)" 989 | .LASF97: 990 | .string "__INT_LEAST16_MAX__ 0x7fff" 991 | .LASF22: 992 | .string "__SIZEOF_LONG_DOUBLE__ 12" 993 | .LASF27: 994 | .string "__ORDER_BIG_ENDIAN__ 4321" 995 | .LASF38: 996 | .string "__CHAR16_TYPE__ short unsigned int" 997 | .LASF157: 998 | .string "__LDBL_MIN_10_EXP__ (-4931)" 999 | .LASF207: 1000 | .string "__GCC_ATOMIC_POINTER_LOCK_FREE 2" 1001 | .LASF222: 1002 | .string "__pentiumpro 1" 1003 | .LASF36: 1004 | .string "__INTMAX_TYPE__ long long int" 1005 | .LASF19: 1006 | .string "__SIZEOF_SHORT__ 2" 1007 | .LASF234: 1008 | .string "_STDC_PREDEF_H 1" 1009 | .LASF98: 1010 | .string "__INT16_C(c) c" 1011 | .LASF130: 1012 | .string "__FLT_MAX_EXP__ 128" 1013 | .LASF179: 1014 | .string "__DEC64_MAX__ 9.999999999999999E384DD" 1015 | .LASF135: 1016 | .string "__FLT_EPSILON__ 1.19209289550781250000e-7F" 1017 | .LASF72: 1018 | .string "__INT_MAX__ 0x7fffffff" 1019 | .LASF205: 1020 | .string "__GCC_ATOMIC_LLONG_LOCK_FREE 2" 1021 | .LASF7: 1022 | .string "__GNUC_PATCHLEVEL__ 0" 1023 | .LASF146: 1024 | .string "__DBL_DECIMAL_DIG__ 17" 1025 | .LASF141: 1026 | .string "__DBL_DIG__ 15" 1027 | .LASF132: 1028 | .string "__FLT_DECIMAL_DIG__ 9" 1029 | .LASF60: 1030 | .string "__INT_FAST64_TYPE__ long long int" 1031 | .LASF185: 1032 | .string "__DEC128_MIN__ 1E-6143DL" 1033 | .LASF25: 1034 | .string "__BIGGEST_ALIGNMENT__ 16" 1035 | .LASF16: 1036 | .string "__SIZEOF_INT__ 4" 1037 | .LASF44: 1038 | .string "__INT64_TYPE__ long long int" 1039 | .LASF203: 1040 | .string "__GCC_ATOMIC_INT_LOCK_FREE 2" 1041 | .LASF184: 1042 | .string "__DEC128_MAX_EXP__ 6145" 1043 | .LASF88: 1044 | .string "__INT16_MAX__ 0x7fff" 1045 | .LASF195: 1046 | .string "__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4 1" 1047 | .LASF214: 1048 | .string "__i386__ 1" 1049 | .LASF177: 1050 | .string "__DEC64_MAX_EXP__ 385" 1051 | .LASF13: 1052 | .string "__ATOMIC_ACQ_REL 4" 1053 | .LASF126: 1054 | .string "__FLT_MANT_DIG__ 24" 1055 | .LASF5: 1056 | .string "__GNUC__ 5" 1057 | .LASF34: 1058 | .string "__WCHAR_TYPE__ long int" 1059 | .LASF163: 1060 | .string "__LDBL_EPSILON__ 1.08420217248550443401e-19L" 1061 | .LASF8: 1062 | .string "__VERSION__ \"5.4.0 20160609\"" 1063 | .LASF114: 1064 | .string "__INT_FAST64_MAX__ 0x7fffffffffffffffLL" 1065 | .LASF186: 1066 | .string "__DEC128_MAX__ 9.999999999999999999999999999999999E6144DL" 1067 | .LASF224: 1068 | .string "__code_model_32__ 1" 1069 | .LASF54: 1070 | .string "__UINT_LEAST16_TYPE__ short unsigned int" 1071 | .LASF57: 1072 | .string "__INT_FAST8_TYPE__ signed char" 1073 | .LASF144: 1074 | .string "__DBL_MAX_EXP__ 1024" 1075 | .LASF0: 1076 | .string "__STDC__ 1" 1077 | .LASF120: 1078 | .string "__UINTPTR_MAX__ 0xffffffffU" 1079 | .LASF11: 1080 | .string "__ATOMIC_ACQUIRE 2" 1081 | .LASF180: 1082 | .string "__DEC64_EPSILON__ 1E-15DD" 1083 | .LASF83: 1084 | .string "__UINTMAX_MAX__ 0xffffffffffffffffULL" 1085 | .LASF99: 1086 | .string "__INT_LEAST32_MAX__ 0x7fffffff" 1087 | .LASF198: 1088 | .string "__GCC_ATOMIC_CHAR_LOCK_FREE 2" 1089 | .LASF187: 1090 | .string "__DEC128_EPSILON__ 1E-33DL" 1091 | .LASF61: 1092 | .string "__UINT_FAST8_TYPE__ unsigned char" 1093 | .LASF169: 1094 | .string "__DEC32_MIN_EXP__ (-94)" 1095 | .LASF63: 1096 | .string "__UINT_FAST32_TYPE__ unsigned int" 1097 | .LASF232: 1098 | .string "__ELF__ 1" 1099 | .LASF155: 1100 | .string "__LDBL_DIG__ 18" 1101 | .LASF235: 1102 | .string "__STDC_IEC_559__ 1" 1103 | .LASF218: 1104 | .string "__ATOMIC_HLE_ACQUIRE 65536" 1105 | .LASF161: 1106 | .string "__LDBL_MAX__ 1.18973149535723176502e+4932L" 1107 | .LASF148: 1108 | .string "__DBL_MIN__ ((double)2.22507385850720138309e-308L)" 1109 | .LASF182: 1110 | .string "__DEC128_MANT_DIG__ 34" 1111 | .LASF100: 1112 | .string "__INT32_C(c) c" 1113 | .LASF176: 1114 | .string "__DEC64_MIN_EXP__ (-382)" 1115 | .LASF109: 1116 | .string "__UINT_LEAST64_MAX__ 0xffffffffffffffffULL" 1117 | .LASF76: 1118 | .string "__WCHAR_MIN__ (-__WCHAR_MAX__ - 1)" 1119 | .LASF199: 1120 | .string "__GCC_ATOMIC_CHAR16_T_LOCK_FREE 2" 1121 | .LASF158: 1122 | .string "__LDBL_MAX_EXP__ 16384" 1123 | .LASF221: 1124 | .string "__i686__ 1" 1125 | .LASF39: 1126 | .string "__CHAR32_TYPE__ unsigned int" 1127 | .LASF82: 1128 | .string "__INTMAX_C(c) c ## LL" 1129 | .LASF237: 1130 | .string "__STDC_ISO_10646__ 201505L" 1131 | .LASF79: 1132 | .string "__PTRDIFF_MAX__ 0x7fffffff" 1133 | .LASF49: 1134 | .string "__INT_LEAST8_TYPE__ signed char" 1135 | .LASF106: 1136 | .string "__UINT16_C(c) c" 1137 | .LASF71: 1138 | .string "__SHRT_MAX__ 0x7fff" 1139 | .LASF123: 1140 | .string "__FLT_EVAL_METHOD__ 2" 1141 | .LASF20: 1142 | .string "__SIZEOF_FLOAT__ 4" 1143 | .LASF196: 1144 | .string "__GCC_HAVE_SYNC_COMPARE_AND_SWAP_8 1" 1145 | .LASF145: 1146 | .string "__DBL_MAX_10_EXP__ 308" 1147 | .LASF241: 1148 | .string "/media/sf_Dropbox_home/books/os-c/kernel" 1149 | .LASF28: 1150 | .string "__ORDER_PDP_ENDIAN__ 3412" 1151 | .LASF26: 1152 | .string "__ORDER_LITTLE_ENDIAN__ 1234" 1153 | .LASF35: 1154 | .string "__WINT_TYPE__ unsigned int" 1155 | .LASF228: 1156 | .string "linux 1" 1157 | .LASF52: 1158 | .string "__INT_LEAST64_TYPE__ long long int" 1159 | .LASF9: 1160 | .string "__ATOMIC_RELAXED 0" 1161 | .LASF168: 1162 | .string "__DEC32_MANT_DIG__ 7" 1163 | .LASF121: 1164 | .string "__GCC_IEC_559 2" 1165 | .LASF225: 1166 | .string "__gnu_linux__ 1" 1167 | .LASF231: 1168 | .string "unix 1" 1169 | .LASF239: 1170 | .string "GNU C11 5.4.0 20160609 -masm=intel -m32 -mtune=generic -march=i686 -gdwarf-2 -ggdb3 -fno-stack-protector -fno-omit-frame-pointer -fno-asynchronous-unwind-tables -fno-builtin" 1171 | .LASF69: 1172 | .string "__GXX_ABI_VERSION 1009" 1173 | .LASF85: 1174 | .string "__SIG_ATOMIC_MAX__ 0x7fffffff" 1175 | .LASF142: 1176 | .string "__DBL_MIN_EXP__ (-1021)" 1177 | .LASF238: 1178 | .string "__STDC_NO_THREADS__ 1" 1179 | .LASF66: 1180 | .string "__UINTPTR_TYPE__ unsigned int" 1181 | .LASF164: 1182 | .string "__LDBL_DENORM_MIN__ 3.64519953188247460253e-4951L" 1183 | .LASF138: 1184 | .string "__FLT_HAS_INFINITY__ 1" 1185 | .LASF216: 1186 | .string "__SIZEOF_FLOAT80__ 12" 1187 | .LASF75: 1188 | .string "__WCHAR_MAX__ 0x7fffffffL" 1189 | .LASF117: 1190 | .string "__UINT_FAST32_MAX__ 0xffffffffU" 1191 | .LASF2: 1192 | .string "__STDC_UTF_16__ 1" 1193 | .LASF192: 1194 | .string "__NO_INLINE__ 1" 1195 | .LASF33: 1196 | .string "__PTRDIFF_TYPE__ int" 1197 | .LASF165: 1198 | .string "__LDBL_HAS_DENORM__ 1" 1199 | .LASF67: 1200 | .string "__has_include(STR) __has_include__(STR)" 1201 | .LASF113: 1202 | .string "__INT_FAST32_MAX__ 0x7fffffff" 1203 | .LASF189: 1204 | .string "__REGISTER_PREFIX__ " 1205 | .LASF14: 1206 | .string "__ATOMIC_CONSUME 1" 1207 | .LASF188: 1208 | .string "__DEC128_SUBNORMAL_MIN__ 0.000000000000000000000000000000001E-6143DL" 1209 | .LASF3: 1210 | .string "__STDC_UTF_32__ 1" 1211 | .LASF46: 1212 | .string "__UINT16_TYPE__ short unsigned int" 1213 | .LASF108: 1214 | .string "__UINT32_C(c) c ## U" 1215 | .LASF174: 1216 | .string "__DEC32_SUBNORMAL_MIN__ 0.000001E-95DF" 1217 | .LASF194: 1218 | .string "__GCC_HAVE_SYNC_COMPARE_AND_SWAP_2 1" 1219 | .LASF112: 1220 | .string "__INT_FAST16_MAX__ 0x7fffffff" 1221 | .LASF86: 1222 | .string "__SIG_ATOMIC_MIN__ (-__SIG_ATOMIC_MAX__ - 1)" 1223 | .LASF173: 1224 | .string "__DEC32_EPSILON__ 1E-6DF" 1225 | .LASF59: 1226 | .string "__INT_FAST32_TYPE__ int" 1227 | .LASF62: 1228 | .string "__UINT_FAST16_TYPE__ unsigned int" 1229 | .LASF154: 1230 | .string "__LDBL_MANT_DIG__ 64" 1231 | .LASF204: 1232 | .string "__GCC_ATOMIC_LONG_LOCK_FREE 2" 1233 | .LASF87: 1234 | .string "__INT8_MAX__ 0x7f" 1235 | .LASF115: 1236 | .string "__UINT_FAST8_MAX__ 0xff" 1237 | .LASF129: 1238 | .string "__FLT_MIN_10_EXP__ (-37)" 1239 | .LASF206: 1240 | .string "__GCC_ATOMIC_TEST_AND_SET_TRUEVAL 1" 1241 | .LASF15: 1242 | .string "__FINITE_MATH_ONLY__ 0" 1243 | .LASF73: 1244 | .string "__LONG_MAX__ 0x7fffffffL" 1245 | .LASF131: 1246 | .string "__FLT_MAX_10_EXP__ 38" 1247 | .LASF190: 1248 | .string "__USER_LABEL_PREFIX__ " 1249 | .LASF55: 1250 | .string "__UINT_LEAST32_TYPE__ unsigned int" 1251 | .LASF64: 1252 | .string "__UINT_FAST64_TYPE__ long long unsigned int" 1253 | .LASF104: 1254 | .string "__UINT8_C(c) c" 1255 | .LASF236: 1256 | .string "__STDC_IEC_559_COMPLEX__ 1" 1257 | .LASF53: 1258 | .string "__UINT_LEAST8_TYPE__ unsigned char" 1259 | .LASF193: 1260 | .string "__GCC_HAVE_SYNC_COMPARE_AND_SWAP_1 1" 1261 | .LASF93: 1262 | .string "__UINT32_MAX__ 0xffffffffU" 1263 | .LASF208: 1264 | .string "__GCC_HAVE_DWARF2_CFI_ASM 1" 1265 | .LASF95: 1266 | .string "__INT_LEAST8_MAX__ 0x7f" 1267 | .LASF178: 1268 | .string "__DEC64_MIN__ 1E-383DD" 1269 | .LASF143: 1270 | .string "__DBL_MIN_10_EXP__ (-307)" 1271 | .LASF136: 1272 | .string "__FLT_DENORM_MIN__ 1.40129846432481707092e-45F" 1273 | .LASF151: 1274 | .string "__DBL_HAS_DENORM__ 1" 1275 | .LASF191: 1276 | .string "__GNUC_STDC_INLINE__ 1" 1277 | .ident "GCC: (Ubuntu 5.4.0-6ubuntu1~16.04.4) 5.4.0 20160609" 1278 | .section .note.GNU-stack,"",@progbits 1279 | -------------------------------------------------------------------------------- /kernel/task1.c: -------------------------------------------------------------------------------- 1 | #include "task1.h" 2 | 3 | TASK_START(task1, init_task1); 4 | int task1_var; 5 | 6 | void job1(int a, int b) { 7 | task1_var = 1; 8 | } 9 | 10 | void job2() { 11 | task1_var = 2; 12 | } 13 | 14 | void init_task1() { 15 | int a = 3/0; 16 | job1(1, 2); 17 | job2(); 18 | } 19 | 20 | TASK_END(task1); 21 | -------------------------------------------------------------------------------- /kernel/task1.h: -------------------------------------------------------------------------------- 1 | // #includ "gdt.h" 2 | #include "task.h" 3 | 4 | TASK_REGISTER(task1); 5 | 6 | struct tss task1_tss; 7 | 8 | void init_task1(); 9 | -------------------------------------------------------------------------------- /kernel/task2.h: -------------------------------------------------------------------------------- 1 | struct tss task2_tss; 2 | -------------------------------------------------------------------------------- /kernel/test/.rid: -------------------------------------------------------------------------------- 1 | 268a222ee0729dc7a2f8ea34cc197eda -------------------------------------------------------------------------------- /kernel/test/Makefile: -------------------------------------------------------------------------------- 1 | BUILD_DIR=../../build 2 | INCLUDE=../ 3 | SRC=../gdt.c ../task.c ../irq.c 4 | CFLAGS=- 5 | 6 | all: runtest 7 | 8 | runtest: test.c 9 | gcc -I$(INCLUDE) -o test $(SRC) $< 10 | ./test -v || true 11 | -------------------------------------------------------------------------------- /kernel/test/greatest.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2011-2016 Scott Vokes 3 | * 4 | * Permission to use, copy, modify, and/or distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | #ifndef GREATEST_H 18 | #define GREATEST_H 19 | 20 | #ifdef __cplusplus 21 | extern "C" { 22 | #endif 23 | 24 | /* 1.2.1 */ 25 | #define GREATEST_VERSION_MAJOR 1 26 | #define GREATEST_VERSION_MINOR 2 27 | #define GREATEST_VERSION_PATCH 1 28 | 29 | /* A unit testing system for C, contained in 1 file. 30 | * It doesn't use dynamic allocation or depend on anything 31 | * beyond ANSI C89. 32 | * 33 | * An up-to-date version can be found at: 34 | * https://github.com/silentbicycle/greatest/ 35 | */ 36 | 37 | 38 | /********************************************************************* 39 | * Minimal test runner template 40 | *********************************************************************/ 41 | #if 0 42 | 43 | #include "greatest.h" 44 | 45 | TEST foo_should_foo(void) { 46 | PASS(); 47 | } 48 | 49 | static void setup_cb(void *data) { 50 | printf("setup callback for each test case\n"); 51 | } 52 | 53 | static void teardown_cb(void *data) { 54 | printf("teardown callback for each test case\n"); 55 | } 56 | 57 | SUITE(suite) { 58 | /* Optional setup/teardown callbacks which will be run before/after 59 | * every test case. If using a test suite, they will be cleared when 60 | * the suite finishes. */ 61 | SET_SETUP(setup_cb, voidp_to_callback_data); 62 | SET_TEARDOWN(teardown_cb, voidp_to_callback_data); 63 | 64 | RUN_TEST(foo_should_foo); 65 | } 66 | 67 | /* Add definitions that need to be in the test runner's main file. */ 68 | GREATEST_MAIN_DEFS(); 69 | 70 | /* Set up, run suite(s) of tests, report pass/fail/skip stats. */ 71 | int run_tests(void) { 72 | GREATEST_INIT(); /* init. greatest internals */ 73 | /* List of suites to run (if any). */ 74 | RUN_SUITE(suite); 75 | 76 | /* Tests can also be run directly, without using test suites. */ 77 | RUN_TEST(foo_should_foo); 78 | 79 | GREATEST_PRINT_REPORT(); /* display results */ 80 | return greatest_all_passed(); 81 | } 82 | 83 | /* main(), for a standalone command-line test runner. 84 | * This replaces run_tests above, and adds command line option 85 | * handling and exiting with a pass/fail status. */ 86 | int main(int argc, char **argv) { 87 | GREATEST_MAIN_BEGIN(); /* init & parse command-line args */ 88 | RUN_SUITE(suite); 89 | GREATEST_MAIN_END(); /* display results */ 90 | } 91 | 92 | #endif 93 | /*********************************************************************/ 94 | 95 | 96 | #include 97 | #include 98 | #include 99 | #include 100 | 101 | /*********** 102 | * Options * 103 | ***********/ 104 | 105 | /* Default column width for non-verbose output. */ 106 | #ifndef GREATEST_DEFAULT_WIDTH 107 | #define GREATEST_DEFAULT_WIDTH 72 108 | #endif 109 | 110 | /* FILE *, for test logging. */ 111 | #ifndef GREATEST_STDOUT 112 | #define GREATEST_STDOUT stdout 113 | #endif 114 | 115 | /* Remove GREATEST_ prefix from most commonly used symbols? */ 116 | #ifndef GREATEST_USE_ABBREVS 117 | #define GREATEST_USE_ABBREVS 1 118 | #endif 119 | 120 | /* Set to 0 to disable all use of setjmp/longjmp. */ 121 | #ifndef GREATEST_USE_LONGJMP 122 | #define GREATEST_USE_LONGJMP 1 123 | #endif 124 | 125 | #if GREATEST_USE_LONGJMP 126 | #include 127 | #endif 128 | 129 | /* Set to 0 to disable all use of time.h / clock(). */ 130 | #ifndef GREATEST_USE_TIME 131 | #define GREATEST_USE_TIME 1 132 | #endif 133 | 134 | #if GREATEST_USE_TIME 135 | #include 136 | #endif 137 | 138 | /* Floating point type, for ASSERT_IN_RANGE. */ 139 | #ifndef GREATEST_FLOAT 140 | #define GREATEST_FLOAT double 141 | #define GREATEST_FLOAT_FMT "%g" 142 | #endif 143 | 144 | /********* 145 | * Types * 146 | *********/ 147 | 148 | /* Info for the current running suite. */ 149 | typedef struct greatest_suite_info { 150 | unsigned int tests_run; 151 | unsigned int passed; 152 | unsigned int failed; 153 | unsigned int skipped; 154 | 155 | #if GREATEST_USE_TIME 156 | /* timers, pre/post running suite and individual tests */ 157 | clock_t pre_suite; 158 | clock_t post_suite; 159 | clock_t pre_test; 160 | clock_t post_test; 161 | #endif 162 | } greatest_suite_info; 163 | 164 | /* Type for a suite function. */ 165 | typedef void (greatest_suite_cb)(void); 166 | 167 | /* Types for setup/teardown callbacks. If non-NULL, these will be run 168 | * and passed the pointer to their additional data. */ 169 | typedef void (greatest_setup_cb)(void *udata); 170 | typedef void (greatest_teardown_cb)(void *udata); 171 | 172 | /* Type for an equality comparison between two pointers of the same type. 173 | * Should return non-0 if equal, otherwise 0. 174 | * UDATA is a closure value, passed through from ASSERT_EQUAL_T[m]. */ 175 | typedef int greatest_equal_cb(const void *exp, const void *got, void *udata); 176 | 177 | /* Type for a callback that prints a value pointed to by T. 178 | * Return value has the same meaning as printf's. 179 | * UDATA is a closure value, passed through from ASSERT_EQUAL_T[m]. */ 180 | typedef int greatest_printf_cb(const void *t, void *udata); 181 | 182 | /* Callbacks for an arbitrary type; needed for type-specific 183 | * comparisons via GREATEST_ASSERT_EQUAL_T[m].*/ 184 | typedef struct greatest_type_info { 185 | greatest_equal_cb *equal; 186 | greatest_printf_cb *print; 187 | } greatest_type_info; 188 | 189 | typedef struct greatest_memory_cmp_env { 190 | const unsigned char *exp; 191 | const unsigned char *got; 192 | size_t size; 193 | } greatest_memory_cmp_env; 194 | 195 | /* Callbacks for string and raw memory types. */ 196 | extern greatest_type_info greatest_type_info_string; 197 | extern greatest_type_info greatest_type_info_memory; 198 | 199 | typedef enum { 200 | GREATEST_FLAG_FIRST_FAIL = 0x01, 201 | GREATEST_FLAG_LIST_ONLY = 0x02 202 | } greatest_flag_t; 203 | 204 | /* Struct containing all test runner state. */ 205 | typedef struct greatest_run_info { 206 | unsigned char flags; 207 | unsigned char verbosity; 208 | unsigned int tests_run; /* total test count */ 209 | 210 | /* overall pass/fail/skip counts */ 211 | unsigned int passed; 212 | unsigned int failed; 213 | unsigned int skipped; 214 | unsigned int assertions; 215 | 216 | /* currently running test suite */ 217 | greatest_suite_info suite; 218 | 219 | /* info to print about the most recent failure */ 220 | const char *fail_file; 221 | unsigned int fail_line; 222 | const char *msg; 223 | 224 | /* current setup/teardown hooks and userdata */ 225 | greatest_setup_cb *setup; 226 | void *setup_udata; 227 | greatest_teardown_cb *teardown; 228 | void *teardown_udata; 229 | 230 | /* formatting info for ".....s...F"-style output */ 231 | unsigned int col; 232 | unsigned int width; 233 | 234 | /* only run a specific suite or test */ 235 | const char *suite_filter; 236 | const char *test_filter; 237 | 238 | #if GREATEST_USE_TIME 239 | /* overall timers */ 240 | clock_t begin; 241 | clock_t end; 242 | #endif 243 | 244 | #if GREATEST_USE_LONGJMP 245 | jmp_buf jump_dest; 246 | #endif 247 | } greatest_run_info; 248 | 249 | struct greatest_report_t { 250 | /* overall pass/fail/skip counts */ 251 | unsigned int passed; 252 | unsigned int failed; 253 | unsigned int skipped; 254 | unsigned int assertions; 255 | }; 256 | 257 | /* Global var for the current testing context. 258 | * Initialized by GREATEST_MAIN_DEFS(). */ 259 | extern greatest_run_info greatest_info; 260 | 261 | /* Type for ASSERT_ENUM_EQ's ENUM_STR argument. */ 262 | typedef const char *greatest_enum_str_fun(int value); 263 | 264 | /********************** 265 | * Exported functions * 266 | **********************/ 267 | 268 | /* These are used internally by greatest. */ 269 | void greatest_do_pass(const char *name); 270 | void greatest_do_fail(const char *name); 271 | void greatest_do_skip(const char *name); 272 | int greatest_pre_test(const char *name); 273 | void greatest_post_test(const char *name, int res); 274 | void greatest_usage(const char *name); 275 | int greatest_do_assert_equal_t(const void *exp, const void *got, 276 | greatest_type_info *type_info, void *udata); 277 | 278 | /* These are part of the public greatest API. */ 279 | void GREATEST_SET_SETUP_CB(greatest_setup_cb *cb, void *udata); 280 | void GREATEST_SET_TEARDOWN_CB(greatest_teardown_cb *cb, void *udata); 281 | int greatest_all_passed(void); 282 | void greatest_set_test_filter(const char *name); 283 | void greatest_set_suite_filter(const char *name); 284 | void greatest_get_report(struct greatest_report_t *report); 285 | unsigned int greatest_get_verbosity(void); 286 | void greatest_set_verbosity(unsigned int verbosity); 287 | void greatest_set_flag(greatest_flag_t flag); 288 | 289 | 290 | /******************** 291 | * Language Support * 292 | ********************/ 293 | 294 | /* If __VA_ARGS__ (C99) is supported, allow parametric testing 295 | * without needing to manually manage the argument struct. */ 296 | #if __STDC_VERSION__ >= 19901L || _MSC_VER >= 1800 297 | #define GREATEST_VA_ARGS 298 | #endif 299 | 300 | 301 | /********** 302 | * Macros * 303 | **********/ 304 | 305 | /* Define a suite. */ 306 | #define GREATEST_SUITE(NAME) void NAME(void); void NAME(void) 307 | 308 | /* Declare a suite, provided by another compilation unit. */ 309 | #define GREATEST_SUITE_EXTERN(NAME) void NAME(void) 310 | 311 | /* Start defining a test function. 312 | * The arguments are not included, to allow parametric testing. */ 313 | #define GREATEST_TEST static enum greatest_test_res 314 | 315 | /* PASS/FAIL/SKIP result from a test. Used internally. */ 316 | typedef enum greatest_test_res { 317 | GREATEST_TEST_RES_PASS = 0, 318 | GREATEST_TEST_RES_FAIL = -1, 319 | GREATEST_TEST_RES_SKIP = 1 320 | } greatest_test_res; 321 | 322 | /* Run a suite. */ 323 | #define GREATEST_RUN_SUITE(S_NAME) greatest_run_suite(S_NAME, #S_NAME) 324 | 325 | /* Run a test in the current suite. */ 326 | #define GREATEST_RUN_TEST(TEST) \ 327 | do { \ 328 | if (greatest_pre_test(#TEST) == 1) { \ 329 | enum greatest_test_res res = GREATEST_SAVE_CONTEXT(); \ 330 | if (res == GREATEST_TEST_RES_PASS) { \ 331 | res = TEST(); \ 332 | } \ 333 | greatest_post_test(#TEST, res); \ 334 | } else if (GREATEST_LIST_ONLY()) { \ 335 | fprintf(GREATEST_STDOUT, " %s\n", #TEST); \ 336 | } \ 337 | } while (0) 338 | 339 | /* Ignore a test, don't warn about it being unused. */ 340 | #define GREATEST_IGNORE_TEST(TEST) (void)TEST 341 | 342 | /* Run a test in the current suite with one void * argument, 343 | * which can be a pointer to a struct with multiple arguments. */ 344 | #define GREATEST_RUN_TEST1(TEST, ENV) \ 345 | do { \ 346 | if (greatest_pre_test(#TEST) == 1) { \ 347 | int res = TEST(ENV); \ 348 | greatest_post_test(#TEST, res); \ 349 | } else if (GREATEST_LIST_ONLY()) { \ 350 | fprintf(GREATEST_STDOUT, " %s\n", #TEST); \ 351 | } \ 352 | } while (0) 353 | 354 | #ifdef GREATEST_VA_ARGS 355 | #define GREATEST_RUN_TESTp(TEST, ...) \ 356 | do { \ 357 | if (greatest_pre_test(#TEST) == 1) { \ 358 | int res = TEST(__VA_ARGS__); \ 359 | greatest_post_test(#TEST, res); \ 360 | } else if (GREATEST_LIST_ONLY()) { \ 361 | fprintf(GREATEST_STDOUT, " %s\n", #TEST); \ 362 | } \ 363 | } while (0) 364 | #endif 365 | 366 | 367 | /* Check if the test runner is in verbose mode. */ 368 | #define GREATEST_IS_VERBOSE() ((greatest_info.verbosity) > 0) 369 | #define GREATEST_LIST_ONLY() \ 370 | (greatest_info.flags & GREATEST_FLAG_LIST_ONLY) 371 | #define GREATEST_FIRST_FAIL() \ 372 | (greatest_info.flags & GREATEST_FLAG_FIRST_FAIL) 373 | #define GREATEST_FAILURE_ABORT() \ 374 | (greatest_info.suite.failed > 0 && GREATEST_FIRST_FAIL()) 375 | 376 | /* Message-less forms of tests defined below. */ 377 | #define GREATEST_PASS() GREATEST_PASSm(NULL) 378 | #define GREATEST_FAIL() GREATEST_FAILm(NULL) 379 | #define GREATEST_SKIP() GREATEST_SKIPm(NULL) 380 | #define GREATEST_ASSERT(COND) \ 381 | GREATEST_ASSERTm(#COND, COND) 382 | #define GREATEST_ASSERT_OR_LONGJMP(COND) \ 383 | GREATEST_ASSERT_OR_LONGJMPm(#COND, COND) 384 | #define GREATEST_ASSERT_FALSE(COND) \ 385 | GREATEST_ASSERT_FALSEm(#COND, COND) 386 | #define GREATEST_ASSERT_EQ(EXP, GOT) \ 387 | GREATEST_ASSERT_EQm(#EXP " != " #GOT, EXP, GOT) 388 | #define GREATEST_ASSERT_EQ_FMT(EXP, GOT, FMT) \ 389 | GREATEST_ASSERT_EQ_FMTm(#EXP " != " #GOT, EXP, GOT, FMT) 390 | #define GREATEST_ASSERT_IN_RANGE(EXP, GOT, TOL) \ 391 | GREATEST_ASSERT_IN_RANGEm(#EXP " != " #GOT " +/- " #TOL, EXP, GOT, TOL) 392 | #define GREATEST_ASSERT_EQUAL_T(EXP, GOT, TYPE_INFO, UDATA) \ 393 | GREATEST_ASSERT_EQUAL_Tm(#EXP " != " #GOT, EXP, GOT, TYPE_INFO, UDATA) 394 | #define GREATEST_ASSERT_STR_EQ(EXP, GOT) \ 395 | GREATEST_ASSERT_STR_EQm(#EXP " != " #GOT, EXP, GOT) 396 | #define GREATEST_ASSERT_STRN_EQ(EXP, GOT, SIZE) \ 397 | GREATEST_ASSERT_STRN_EQm(#EXP " != " #GOT, EXP, GOT, SIZE) 398 | #define GREATEST_ASSERT_MEM_EQ(EXP, GOT, SIZE) \ 399 | GREATEST_ASSERT_MEM_EQm(#EXP " != " #GOT, EXP, GOT, SIZE) 400 | #define GREATEST_ASSERT_ENUM_EQ(EXP, GOT, ENUM_STR) \ 401 | GREATEST_ASSERT_ENUM_EQm(#EXP " != " #GOT, EXP, GOT, ENUM_STR) 402 | 403 | /* The following forms take an additional message argument first, 404 | * to be displayed by the test runner. */ 405 | 406 | /* Fail if a condition is not true, with message. */ 407 | #define GREATEST_ASSERTm(MSG, COND) \ 408 | do { \ 409 | greatest_info.assertions++; \ 410 | if (!(COND)) { GREATEST_FAILm(MSG); } \ 411 | } while (0) 412 | 413 | /* Fail if a condition is not true, longjmping out of test. */ 414 | #define GREATEST_ASSERT_OR_LONGJMPm(MSG, COND) \ 415 | do { \ 416 | greatest_info.assertions++; \ 417 | if (!(COND)) { GREATEST_FAIL_WITH_LONGJMPm(MSG); } \ 418 | } while (0) 419 | 420 | /* Fail if a condition is not false, with message. */ 421 | #define GREATEST_ASSERT_FALSEm(MSG, COND) \ 422 | do { \ 423 | greatest_info.assertions++; \ 424 | if ((COND)) { GREATEST_FAILm(MSG); } \ 425 | } while (0) 426 | 427 | /* Fail if EXP != GOT (equality comparison by ==). */ 428 | #define GREATEST_ASSERT_EQm(MSG, EXP, GOT) \ 429 | do { \ 430 | greatest_info.assertions++; \ 431 | if ((EXP) != (GOT)) { GREATEST_FAILm(MSG); } \ 432 | } while (0) 433 | 434 | /* Fail if EXP != GOT (equality comparison by ==). 435 | * Warning: EXP and GOT will be evaluated more than once on failure. */ 436 | #define GREATEST_ASSERT_EQ_FMTm(MSG, EXP, GOT, FMT) \ 437 | do { \ 438 | const char *greatest_FMT = ( FMT ); \ 439 | greatest_info.assertions++; \ 440 | if ((EXP) != (GOT)) { \ 441 | fprintf(GREATEST_STDOUT, "\nExpected: "); \ 442 | fprintf(GREATEST_STDOUT, greatest_FMT, EXP); \ 443 | fprintf(GREATEST_STDOUT, "\n Got: "); \ 444 | fprintf(GREATEST_STDOUT, greatest_FMT, GOT); \ 445 | fprintf(GREATEST_STDOUT, "\n"); \ 446 | GREATEST_FAILm(MSG); \ 447 | } \ 448 | } while (0) 449 | 450 | /* Fail if EXP is not equal to GOT, printing enum IDs. */ 451 | #define GREATEST_ASSERT_ENUM_EQm(MSG, EXP, GOT, ENUM_STR) \ 452 | do { \ 453 | int greatest_EXP = (int)(EXP); \ 454 | int greatest_GOT = (int)(GOT); \ 455 | greatest_enum_str_fun *greatest_ENUM_STR = ENUM_STR; \ 456 | if (greatest_EXP != greatest_GOT) { \ 457 | fprintf(GREATEST_STDOUT, "\nExpected: %s", \ 458 | greatest_ENUM_STR(greatest_EXP)); \ 459 | fprintf(GREATEST_STDOUT, "\n Got: %s\n", \ 460 | greatest_ENUM_STR(greatest_GOT)); \ 461 | GREATEST_FAILm(MSG); \ 462 | } \ 463 | } while (0) \ 464 | 465 | /* Fail if GOT not in range of EXP +|- TOL. */ 466 | #define GREATEST_ASSERT_IN_RANGEm(MSG, EXP, GOT, TOL) \ 467 | do { \ 468 | GREATEST_FLOAT greatest_EXP = (EXP); \ 469 | GREATEST_FLOAT greatest_GOT = (GOT); \ 470 | GREATEST_FLOAT greatest_TOL = (TOL); \ 471 | greatest_info.assertions++; \ 472 | if ((greatest_EXP > greatest_GOT && \ 473 | greatest_EXP - greatest_GOT > greatest_TOL) || \ 474 | (greatest_EXP < greatest_GOT && \ 475 | greatest_GOT - greatest_EXP > greatest_TOL)) { \ 476 | fprintf(GREATEST_STDOUT, \ 477 | "\nExpected: " GREATEST_FLOAT_FMT \ 478 | " +/- " GREATEST_FLOAT_FMT \ 479 | "\n Got: " GREATEST_FLOAT_FMT \ 480 | "\n", \ 481 | greatest_EXP, greatest_TOL, greatest_GOT); \ 482 | GREATEST_FAILm(MSG); \ 483 | } \ 484 | } while (0) 485 | 486 | /* Fail if EXP is not equal to GOT, according to strcmp. */ 487 | #define GREATEST_ASSERT_STR_EQm(MSG, EXP, GOT) \ 488 | do { \ 489 | GREATEST_ASSERT_EQUAL_Tm(MSG, EXP, GOT, \ 490 | &greatest_type_info_string, NULL); \ 491 | } while (0) \ 492 | 493 | /* Fail if EXP is not equal to GOT, according to strcmp. */ 494 | #define GREATEST_ASSERT_STRN_EQm(MSG, EXP, GOT, SIZE) \ 495 | do { \ 496 | size_t size = SIZE; \ 497 | GREATEST_ASSERT_EQUAL_Tm(MSG, EXP, GOT, \ 498 | &greatest_type_info_string, &size); \ 499 | } while (0) \ 500 | 501 | /* Fail if EXP is not equal to GOT, according to memcmp. */ 502 | #define GREATEST_ASSERT_MEM_EQm(MSG, EXP, GOT, SIZE) \ 503 | do { \ 504 | greatest_memory_cmp_env env; \ 505 | env.exp = (const unsigned char *)EXP; \ 506 | env.got = (const unsigned char *)GOT; \ 507 | env.size = SIZE; \ 508 | GREATEST_ASSERT_EQUAL_Tm(MSG, env.exp, env.got, \ 509 | &greatest_type_info_memory, &env); \ 510 | } while (0) \ 511 | 512 | /* Fail if EXP is not equal to GOT, according to a comparison 513 | * callback in TYPE_INFO. If they are not equal, optionally use a 514 | * print callback in TYPE_INFO to print them. */ 515 | #define GREATEST_ASSERT_EQUAL_Tm(MSG, EXP, GOT, TYPE_INFO, UDATA) \ 516 | do { \ 517 | greatest_type_info *type_info = (TYPE_INFO); \ 518 | greatest_info.assertions++; \ 519 | if (!greatest_do_assert_equal_t(EXP, GOT, \ 520 | type_info, UDATA)) { \ 521 | if (type_info == NULL || type_info->equal == NULL) { \ 522 | GREATEST_FAILm("type_info->equal callback missing!"); \ 523 | } else { \ 524 | GREATEST_FAILm(MSG); \ 525 | } \ 526 | } \ 527 | } while (0) \ 528 | 529 | /* Pass. */ 530 | #define GREATEST_PASSm(MSG) \ 531 | do { \ 532 | greatest_info.msg = MSG; \ 533 | return GREATEST_TEST_RES_PASS; \ 534 | } while (0) 535 | 536 | /* Fail. */ 537 | #define GREATEST_FAILm(MSG) \ 538 | do { \ 539 | greatest_info.fail_file = __FILE__; \ 540 | greatest_info.fail_line = __LINE__; \ 541 | greatest_info.msg = MSG; \ 542 | return GREATEST_TEST_RES_FAIL; \ 543 | } while (0) 544 | 545 | /* Optional GREATEST_FAILm variant that longjmps. */ 546 | #if GREATEST_USE_LONGJMP 547 | #define GREATEST_FAIL_WITH_LONGJMP() GREATEST_FAIL_WITH_LONGJMPm(NULL) 548 | #define GREATEST_FAIL_WITH_LONGJMPm(MSG) \ 549 | do { \ 550 | greatest_info.fail_file = __FILE__; \ 551 | greatest_info.fail_line = __LINE__; \ 552 | greatest_info.msg = MSG; \ 553 | longjmp(greatest_info.jump_dest, GREATEST_TEST_RES_FAIL); \ 554 | } while (0) 555 | #endif 556 | 557 | /* Skip the current test. */ 558 | #define GREATEST_SKIPm(MSG) \ 559 | do { \ 560 | greatest_info.msg = MSG; \ 561 | return GREATEST_TEST_RES_SKIP; \ 562 | } while (0) 563 | 564 | /* Check the result of a subfunction using ASSERT, etc. */ 565 | #define GREATEST_CHECK_CALL(RES) \ 566 | do { \ 567 | enum greatest_test_res greatest_RES = RES; \ 568 | if (greatest_RES != GREATEST_TEST_RES_PASS) { \ 569 | return greatest_RES; \ 570 | } \ 571 | } while (0) \ 572 | 573 | #if GREATEST_USE_TIME 574 | #define GREATEST_SET_TIME(NAME) \ 575 | NAME = clock(); \ 576 | if (NAME == (clock_t) -1) { \ 577 | fprintf(GREATEST_STDOUT, \ 578 | "clock error: %s\n", #NAME); \ 579 | exit(EXIT_FAILURE); \ 580 | } 581 | 582 | #define GREATEST_CLOCK_DIFF(C1, C2) \ 583 | fprintf(GREATEST_STDOUT, " (%lu ticks, %.3f sec)", \ 584 | (long unsigned int) (C2) - (long unsigned int)(C1), \ 585 | (double)((C2) - (C1)) / (1.0 * (double)CLOCKS_PER_SEC)) 586 | #else 587 | #define GREATEST_SET_TIME(UNUSED) 588 | #define GREATEST_CLOCK_DIFF(UNUSED1, UNUSED2) 589 | #endif 590 | 591 | #if GREATEST_USE_LONGJMP 592 | #define GREATEST_SAVE_CONTEXT() \ 593 | /* setjmp returns 0 (GREATEST_TEST_RES_PASS) on first call */ \ 594 | /* so the test runs, then RES_FAIL from FAIL_WITH_LONGJMP. */ \ 595 | ((enum greatest_test_res)(setjmp(greatest_info.jump_dest))) 596 | #else 597 | #define GREATEST_SAVE_CONTEXT() \ 598 | /*a no-op, since setjmp/longjmp aren't being used */ \ 599 | GREATEST_TEST_RES_PASS 600 | #endif 601 | 602 | /* Include several function definitions in the main test file. */ 603 | #define GREATEST_MAIN_DEFS() \ 604 | \ 605 | /* Is FILTER a subset of NAME? */ \ 606 | static int greatest_name_match(const char *name, \ 607 | const char *filter) { \ 608 | size_t offset = 0; \ 609 | size_t filter_len = strlen(filter); \ 610 | while (name[offset] != '\0') { \ 611 | if (name[offset] == filter[0]) { \ 612 | if (0 == strncmp(&name[offset], filter, filter_len)) { \ 613 | return 1; \ 614 | } \ 615 | } \ 616 | offset++; \ 617 | } \ 618 | \ 619 | return 0; \ 620 | } \ 621 | \ 622 | int greatest_pre_test(const char *name) { \ 623 | if (!GREATEST_LIST_ONLY() \ 624 | && (!GREATEST_FIRST_FAIL() || greatest_info.suite.failed == 0) \ 625 | && (greatest_info.test_filter == NULL || \ 626 | greatest_name_match(name, greatest_info.test_filter))) { \ 627 | GREATEST_SET_TIME(greatest_info.suite.pre_test); \ 628 | if (greatest_info.setup) { \ 629 | greatest_info.setup(greatest_info.setup_udata); \ 630 | } \ 631 | return 1; /* test should be run */ \ 632 | } else { \ 633 | return 0; /* skipped */ \ 634 | } \ 635 | } \ 636 | \ 637 | void greatest_post_test(const char *name, int res) { \ 638 | GREATEST_SET_TIME(greatest_info.suite.post_test); \ 639 | if (greatest_info.teardown) { \ 640 | void *udata = greatest_info.teardown_udata; \ 641 | greatest_info.teardown(udata); \ 642 | } \ 643 | \ 644 | if (res <= GREATEST_TEST_RES_FAIL) { \ 645 | greatest_do_fail(name); \ 646 | } else if (res >= GREATEST_TEST_RES_SKIP) { \ 647 | greatest_do_skip(name); \ 648 | } else if (res == GREATEST_TEST_RES_PASS) { \ 649 | greatest_do_pass(name); \ 650 | } \ 651 | greatest_info.suite.tests_run++; \ 652 | greatest_info.col++; \ 653 | if (GREATEST_IS_VERBOSE()) { \ 654 | GREATEST_CLOCK_DIFF(greatest_info.suite.pre_test, \ 655 | greatest_info.suite.post_test); \ 656 | fprintf(GREATEST_STDOUT, "\n"); \ 657 | } else if (greatest_info.col % greatest_info.width == 0) { \ 658 | fprintf(GREATEST_STDOUT, "\n"); \ 659 | greatest_info.col = 0; \ 660 | } \ 661 | if (GREATEST_STDOUT == stdout) fflush(stdout); \ 662 | } \ 663 | \ 664 | static void report_suite(void) { \ 665 | if (greatest_info.suite.tests_run > 0) { \ 666 | fprintf(GREATEST_STDOUT, \ 667 | "\n%u test%s - %u passed, %u failed, %u skipped", \ 668 | greatest_info.suite.tests_run, \ 669 | greatest_info.suite.tests_run == 1 ? "" : "s", \ 670 | greatest_info.suite.passed, \ 671 | greatest_info.suite.failed, \ 672 | greatest_info.suite.skipped); \ 673 | GREATEST_CLOCK_DIFF(greatest_info.suite.pre_suite, \ 674 | greatest_info.suite.post_suite); \ 675 | fprintf(GREATEST_STDOUT, "\n"); \ 676 | } \ 677 | } \ 678 | \ 679 | static void update_counts_and_reset_suite(void) { \ 680 | greatest_info.setup = NULL; \ 681 | greatest_info.setup_udata = NULL; \ 682 | greatest_info.teardown = NULL; \ 683 | greatest_info.teardown_udata = NULL; \ 684 | greatest_info.passed += greatest_info.suite.passed; \ 685 | greatest_info.failed += greatest_info.suite.failed; \ 686 | greatest_info.skipped += greatest_info.suite.skipped; \ 687 | greatest_info.tests_run += greatest_info.suite.tests_run; \ 688 | memset(&greatest_info.suite, 0, sizeof(greatest_info.suite)); \ 689 | greatest_info.col = 0; \ 690 | } \ 691 | \ 692 | static void greatest_run_suite(greatest_suite_cb *suite_cb, \ 693 | const char *suite_name) { \ 694 | if (greatest_info.suite_filter && \ 695 | !greatest_name_match(suite_name, greatest_info.suite_filter)) { \ 696 | return; \ 697 | } \ 698 | update_counts_and_reset_suite(); \ 699 | if (GREATEST_FIRST_FAIL() && greatest_info.failed > 0) { return; } \ 700 | fprintf(GREATEST_STDOUT, "\n* Suite %s:\n", suite_name); \ 701 | GREATEST_SET_TIME(greatest_info.suite.pre_suite); \ 702 | suite_cb(); \ 703 | GREATEST_SET_TIME(greatest_info.suite.post_suite); \ 704 | report_suite(); \ 705 | } \ 706 | \ 707 | void greatest_do_pass(const char *name) { \ 708 | if (GREATEST_IS_VERBOSE()) { \ 709 | fprintf(GREATEST_STDOUT, "PASS %s: %s", \ 710 | name, greatest_info.msg ? greatest_info.msg : ""); \ 711 | } else { \ 712 | fprintf(GREATEST_STDOUT, "."); \ 713 | } \ 714 | greatest_info.suite.passed++; \ 715 | } \ 716 | \ 717 | void greatest_do_fail(const char *name) { \ 718 | if (GREATEST_IS_VERBOSE()) { \ 719 | fprintf(GREATEST_STDOUT, \ 720 | "FAIL %s: %s (%s:%u)", \ 721 | name, greatest_info.msg ? greatest_info.msg : "", \ 722 | greatest_info.fail_file, greatest_info.fail_line); \ 723 | } else { \ 724 | fprintf(GREATEST_STDOUT, "F"); \ 725 | greatest_info.col++; \ 726 | /* add linebreak if in line of '.'s */ \ 727 | if (greatest_info.col != 0) { \ 728 | fprintf(GREATEST_STDOUT, "\n"); \ 729 | greatest_info.col = 0; \ 730 | } \ 731 | fprintf(GREATEST_STDOUT, "FAIL %s: %s (%s:%u)\n", \ 732 | name, \ 733 | greatest_info.msg ? greatest_info.msg : "", \ 734 | greatest_info.fail_file, greatest_info.fail_line); \ 735 | } \ 736 | greatest_info.suite.failed++; \ 737 | } \ 738 | \ 739 | void greatest_do_skip(const char *name) { \ 740 | if (GREATEST_IS_VERBOSE()) { \ 741 | fprintf(GREATEST_STDOUT, "SKIP %s: %s", \ 742 | name, \ 743 | greatest_info.msg ? \ 744 | greatest_info.msg : "" ); \ 745 | } else { \ 746 | fprintf(GREATEST_STDOUT, "s"); \ 747 | } \ 748 | greatest_info.suite.skipped++; \ 749 | } \ 750 | \ 751 | int greatest_do_assert_equal_t(const void *exp, const void *got, \ 752 | greatest_type_info *type_info, void *udata) { \ 753 | int eq = 0; \ 754 | if (type_info == NULL || type_info->equal == NULL) { \ 755 | return 0; \ 756 | } \ 757 | eq = type_info->equal(exp, got, udata); \ 758 | if (!eq) { \ 759 | if (type_info->print != NULL) { \ 760 | fprintf(GREATEST_STDOUT, "\nExpected: "); \ 761 | (void)type_info->print(exp, udata); \ 762 | fprintf(GREATEST_STDOUT, "\n Got: "); \ 763 | (void)type_info->print(got, udata); \ 764 | fprintf(GREATEST_STDOUT, "\n"); \ 765 | } else { \ 766 | fprintf(GREATEST_STDOUT, \ 767 | "GREATEST_ASSERT_EQUAL_T failure at %s:%u\n", \ 768 | greatest_info.fail_file, \ 769 | greatest_info.fail_line); \ 770 | } \ 771 | } \ 772 | return eq; \ 773 | } \ 774 | \ 775 | void greatest_usage(const char *name) { \ 776 | fprintf(GREATEST_STDOUT, \ 777 | "Usage: %s [-hlfv] [-s SUITE] [-t TEST]\n" \ 778 | " -h, --help print this Help\n" \ 779 | " -l List suites and their tests, then exit\n" \ 780 | " -f Stop runner after first failure\n" \ 781 | " -v Verbose output\n" \ 782 | " -s SUITE only run suites containing string SUITE\n" \ 783 | " -t TEST only run tests containing string TEST\n", \ 784 | name); \ 785 | } \ 786 | \ 787 | static void greatest_parse_args(int argc, char **argv) { \ 788 | int i = 0; \ 789 | for (i = 1; i < argc; i++) { \ 790 | if (0 == strncmp("-t", argv[i], 2)) { \ 791 | if (argc <= i + 1) { \ 792 | greatest_usage(argv[0]); \ 793 | exit(EXIT_FAILURE); \ 794 | } \ 795 | greatest_info.test_filter = argv[i+1]; \ 796 | i++; \ 797 | } else if (0 == strncmp("-s", argv[i], 2)) { \ 798 | if (argc <= i + 1) { \ 799 | greatest_usage(argv[0]); \ 800 | exit(EXIT_FAILURE); \ 801 | } \ 802 | greatest_info.suite_filter = argv[i+1]; \ 803 | i++; \ 804 | } else if (0 == strncmp("-f", argv[i], 2)) { \ 805 | greatest_info.flags |= GREATEST_FLAG_FIRST_FAIL; \ 806 | } else if (0 == strncmp("-v", argv[i], 2)) { \ 807 | greatest_info.verbosity++; \ 808 | } else if (0 == strncmp("-l", argv[i], 2)) { \ 809 | greatest_info.flags |= GREATEST_FLAG_LIST_ONLY; \ 810 | } else if (0 == strncmp("-h", argv[i], 2) || \ 811 | 0 == strncmp("--help", argv[i], 6)) { \ 812 | greatest_usage(argv[0]); \ 813 | exit(EXIT_SUCCESS); \ 814 | } else if (0 == strncmp("--", argv[i], 2)) { \ 815 | break; \ 816 | } else { \ 817 | fprintf(GREATEST_STDOUT, \ 818 | "Unknown argument '%s'\n", argv[i]); \ 819 | greatest_usage(argv[0]); \ 820 | exit(EXIT_FAILURE); \ 821 | } \ 822 | } \ 823 | } \ 824 | \ 825 | int greatest_all_passed(void) { return (greatest_info.failed == 0); } \ 826 | \ 827 | void greatest_set_test_filter(const char *name) { \ 828 | greatest_info.test_filter = name; \ 829 | } \ 830 | \ 831 | void greatest_set_suite_filter(const char *name) { \ 832 | greatest_info.suite_filter = name; \ 833 | } \ 834 | \ 835 | void greatest_get_report(struct greatest_report_t *report) { \ 836 | if (report) { \ 837 | report->passed = greatest_info.passed; \ 838 | report->failed = greatest_info.failed; \ 839 | report->skipped = greatest_info.skipped; \ 840 | report->assertions = greatest_info.assertions; \ 841 | } \ 842 | } \ 843 | \ 844 | unsigned int greatest_get_verbosity(void) { \ 845 | return greatest_info.verbosity; \ 846 | } \ 847 | \ 848 | void greatest_set_verbosity(unsigned int verbosity) { \ 849 | greatest_info.verbosity = (unsigned char)verbosity; \ 850 | } \ 851 | \ 852 | void greatest_set_flag(greatest_flag_t flag) { \ 853 | greatest_info.flags |= flag; \ 854 | } \ 855 | \ 856 | void GREATEST_SET_SETUP_CB(greatest_setup_cb *cb, void *udata) { \ 857 | greatest_info.setup = cb; \ 858 | greatest_info.setup_udata = udata; \ 859 | } \ 860 | \ 861 | void GREATEST_SET_TEARDOWN_CB(greatest_teardown_cb *cb, \ 862 | void *udata) { \ 863 | greatest_info.teardown = cb; \ 864 | greatest_info.teardown_udata = udata; \ 865 | } \ 866 | \ 867 | static int greatest_string_equal_cb(const void *exp, const void *got, \ 868 | void *udata) { \ 869 | size_t *size = (size_t *)udata; \ 870 | return (size != NULL \ 871 | ? (0 == strncmp((const char *)exp, (const char *)got, *size)) \ 872 | : (0 == strcmp((const char *)exp, (const char *)got))); \ 873 | } \ 874 | \ 875 | static int greatest_string_printf_cb(const void *t, void *udata) { \ 876 | (void)udata; /* note: does not check \0 termination. */ \ 877 | return fprintf(GREATEST_STDOUT, "%s", (const char *)t); \ 878 | } \ 879 | \ 880 | greatest_type_info greatest_type_info_string = { \ 881 | greatest_string_equal_cb, \ 882 | greatest_string_printf_cb, \ 883 | }; \ 884 | \ 885 | static int greatest_memory_equal_cb(const void *exp, const void *got, \ 886 | void *udata) { \ 887 | greatest_memory_cmp_env *env = (greatest_memory_cmp_env *)udata; \ 888 | return (0 == memcmp(exp, got, env->size)); \ 889 | } \ 890 | \ 891 | static int greatest_memory_printf_cb(const void *t, void *udata) { \ 892 | greatest_memory_cmp_env *env = (greatest_memory_cmp_env *)udata; \ 893 | unsigned char *buf = (unsigned char *)t, diff_mark = ' '; \ 894 | FILE *out = GREATEST_STDOUT; \ 895 | size_t i, line_i, line_len = 0; \ 896 | int len = 0; /* format hexdump with differences highlighted */ \ 897 | for (i = 0; i < env->size; i+= line_len) { \ 898 | diff_mark = ' '; \ 899 | line_len = env->size - i; \ 900 | if (line_len > 16) { line_len = 16; } \ 901 | for (line_i = i; line_i < i + line_len; line_i++) { \ 902 | if (env->exp[line_i] != env->got[line_i]) diff_mark = 'X'; \ 903 | } \ 904 | len += fprintf(out, "\n%04x %c ", (unsigned int)i, diff_mark); \ 905 | for (line_i = i; line_i < i + line_len; line_i++) { \ 906 | int m = env->exp[line_i] == env->got[line_i]; /* match? */ \ 907 | len += fprintf(out, "%02x%c", buf[line_i], m ? ' ' : '<'); \ 908 | } \ 909 | for (line_i = 0; line_i < 16 - line_len; line_i++) { \ 910 | len += fprintf(out, " "); \ 911 | } \ 912 | fprintf(out, " "); \ 913 | for (line_i = i; line_i < i + line_len; line_i++) { \ 914 | unsigned char c = buf[line_i]; \ 915 | len += fprintf(out, "%c", isprint(c) ? c : '.'); \ 916 | } \ 917 | } \ 918 | len += fprintf(out, "\n"); \ 919 | return len; \ 920 | } \ 921 | \ 922 | greatest_type_info greatest_type_info_memory = { \ 923 | greatest_memory_equal_cb, \ 924 | greatest_memory_printf_cb, \ 925 | }; \ 926 | \ 927 | greatest_run_info greatest_info 928 | 929 | /* Init internals. */ 930 | #define GREATEST_INIT() \ 931 | do { \ 932 | /* Suppress unused function warning if features aren't used */ \ 933 | (void)greatest_run_suite; \ 934 | (void)greatest_parse_args; \ 935 | \ 936 | memset(&greatest_info, 0, sizeof(greatest_info)); \ 937 | greatest_info.width = GREATEST_DEFAULT_WIDTH; \ 938 | GREATEST_SET_TIME(greatest_info.begin); \ 939 | } while (0) \ 940 | 941 | /* Handle command-line arguments, etc. */ 942 | #define GREATEST_MAIN_BEGIN() \ 943 | do { \ 944 | GREATEST_INIT(); \ 945 | greatest_parse_args(argc, argv); \ 946 | } while (0) 947 | 948 | /* Report passes, failures, skipped tests, the number of 949 | * assertions, and the overall run time. */ 950 | #define GREATEST_PRINT_REPORT() \ 951 | do { \ 952 | if (!GREATEST_LIST_ONLY()) { \ 953 | update_counts_and_reset_suite(); \ 954 | GREATEST_SET_TIME(greatest_info.end); \ 955 | fprintf(GREATEST_STDOUT, \ 956 | "\nTotal: %u test%s", \ 957 | greatest_info.tests_run, \ 958 | greatest_info.tests_run == 1 ? "" : "s"); \ 959 | GREATEST_CLOCK_DIFF(greatest_info.begin, \ 960 | greatest_info.end); \ 961 | fprintf(GREATEST_STDOUT, ", %u assertion%s\n", \ 962 | greatest_info.assertions, \ 963 | greatest_info.assertions == 1 ? "" : "s"); \ 964 | fprintf(GREATEST_STDOUT, \ 965 | "Pass: %u, fail: %u, skip: %u.\n", \ 966 | greatest_info.passed, \ 967 | greatest_info.failed, greatest_info.skipped); \ 968 | } \ 969 | } while (0) 970 | 971 | /* Report results, exit with exit status based on results. */ 972 | #define GREATEST_MAIN_END() \ 973 | do { \ 974 | GREATEST_PRINT_REPORT(); \ 975 | return (greatest_all_passed() ? EXIT_SUCCESS : EXIT_FAILURE); \ 976 | } while (0) 977 | 978 | /* Make abbreviations without the GREATEST_ prefix for the 979 | * most commonly used symbols. */ 980 | #if GREATEST_USE_ABBREVS 981 | #define TEST GREATEST_TEST 982 | #define SUITE GREATEST_SUITE 983 | #define SUITE_EXTERN GREATEST_SUITE_EXTERN 984 | #define RUN_TEST GREATEST_RUN_TEST 985 | #define RUN_TEST1 GREATEST_RUN_TEST1 986 | #define RUN_SUITE GREATEST_RUN_SUITE 987 | #define IGNORE_TEST GREATEST_IGNORE_TEST 988 | #define ASSERT GREATEST_ASSERT 989 | #define ASSERTm GREATEST_ASSERTm 990 | #define ASSERT_FALSE GREATEST_ASSERT_FALSE 991 | #define ASSERT_EQ GREATEST_ASSERT_EQ 992 | #define ASSERT_EQ_FMT GREATEST_ASSERT_EQ_FMT 993 | #define ASSERT_IN_RANGE GREATEST_ASSERT_IN_RANGE 994 | #define ASSERT_EQUAL_T GREATEST_ASSERT_EQUAL_T 995 | #define ASSERT_STR_EQ GREATEST_ASSERT_STR_EQ 996 | #define ASSERT_STRN_EQ GREATEST_ASSERT_STRN_EQ 997 | #define ASSERT_MEM_EQ GREATEST_ASSERT_MEM_EQ 998 | #define ASSERT_ENUM_EQ GREATEST_ASSERT_ENUM_EQ 999 | #define ASSERT_FALSEm GREATEST_ASSERT_FALSEm 1000 | #define ASSERT_EQm GREATEST_ASSERT_EQm 1001 | #define ASSERT_EQ_FMTm GREATEST_ASSERT_EQ_FMTm 1002 | #define ASSERT_IN_RANGEm GREATEST_ASSERT_IN_RANGEm 1003 | #define ASSERT_EQUAL_Tm GREATEST_ASSERT_EQUAL_Tm 1004 | #define ASSERT_STR_EQm GREATEST_ASSERT_STR_EQm 1005 | #define ASSERT_STRN_EQm GREATEST_ASSERT_STRN_EQm 1006 | #define ASSERT_MEM_EQm GREATEST_ASSERT_MEM_EQm 1007 | #define ASSERT_ENUM_EQm GREATEST_ASSERT_ENUM_EQm 1008 | #define PASS GREATEST_PASS 1009 | #define FAIL GREATEST_FAIL 1010 | #define SKIP GREATEST_SKIP 1011 | #define PASSm GREATEST_PASSm 1012 | #define FAILm GREATEST_FAILm 1013 | #define SKIPm GREATEST_SKIPm 1014 | #define SET_SETUP GREATEST_SET_SETUP_CB 1015 | #define SET_TEARDOWN GREATEST_SET_TEARDOWN_CB 1016 | #define CHECK_CALL GREATEST_CHECK_CALL 1017 | 1018 | #ifdef GREATEST_VA_ARGS 1019 | #define RUN_TESTp GREATEST_RUN_TESTp 1020 | #endif 1021 | 1022 | #if GREATEST_USE_LONGJMP 1023 | #define ASSERT_OR_LONGJMP GREATEST_ASSERT_OR_LONGJMP 1024 | #define ASSERT_OR_LONGJMPm GREATEST_ASSERT_OR_LONGJMPm 1025 | #define FAIL_WITH_LONGJMP GREATEST_FAIL_WITH_LONGJMP 1026 | #define FAIL_WITH_LONGJMPm GREATEST_FAIL_WITH_LONGJMPm 1027 | #endif 1028 | 1029 | #endif /* USE_ABBREVS */ 1030 | 1031 | #ifdef __cplusplus 1032 | } 1033 | #endif 1034 | 1035 | #endif 1036 | -------------------------------------------------------------------------------- /kernel/test/main: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tuhdo/sample-os/09e25a85e2588bbcf68d935f76a2b4a7402a941e/kernel/test/main -------------------------------------------------------------------------------- /kernel/test/test: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tuhdo/sample-os/09e25a85e2588bbcf68d935f76a2b4a7402a941e/kernel/test/test -------------------------------------------------------------------------------- /kernel/test/test.c: -------------------------------------------------------------------------------- 1 | #include "greatest.h" 2 | #include "gdt.h" 3 | #include "irq.h" 4 | 5 | /* A test runs various assertions, then calls PASS(), FAIL(), or SKIP(). */ 6 | TEST test_bit_mask(void) { 7 | ASSERT_EQ(bit_mask(0,0), 0x1); 8 | ASSERT_EQ(bit_mask(0,1), 0x3); 9 | ASSERT_EQ(bit_mask(1,3), 0xE); 10 | ASSERT_EQ(bit_mask(4,7), 0xF0); 11 | ASSERT_EQ(bit_mask(8,15), 0xFF00); 12 | 13 | PASS(); 14 | } 15 | 16 | TEST test_bit_value(void) { 17 | ASSERT_EQ(0x1, bit_value(0x1,0, 1)); 18 | ASSERT_EQ(0x7, bit_value(0xFF,1,3)); 19 | ASSERT_EQ_FMT(0xF, bit_value(0xFF, 4,7), "%d"); 20 | ASSERT_EQ_FMT(0xF, bit_value(0xFF, 4,7), "%d"); 21 | ASSERT_EQ(0xFF, bit_value(0xFFFF,8,15)); 22 | ASSERT_EQ_FMT(0x1, bit_value(0x10000,16,23), "%x"); 23 | ASSERT_EQ(0xFFFF, bit_value(0xFFFFFFFF,16,31)); 24 | /* ASSERT_EQ(bit_value(8,15), 0xFF00); */ 25 | PASS(); 26 | } 27 | 28 | TEST test_create_segments(void) { 29 | /* 30 | dw 0FFFFh ; limit low 31 | dw 0x500 ; base low 32 | db 0x00 ; base middle 33 | db 10011010b ; access 34 | db 11001111b ; granularity 35 | db 0x0 ; base high 36 | */ 37 | /* ASSERT_EQ(0x00CF9A000500FFFF, seg(0xFFFF, 0x0500, 0x00, 0x0A, 1, 0x00, 1, 0xF, 0, 0, 1, 1, 0x0000)); */ 38 | segment_descriptor s, s1, s2; 39 | uint32_t g = SEG4K | SEG32 | SEG64_0 | SEG_LIMIT_16_19(0xf); 40 | uint32_t t = SEG_PRESENT | SEG_RING0 | SEG_CODE_DATA | SEG_XR; 41 | 42 | add_segment(&gdt, 0x1FFFF, 0xFFFF, g | t, 0x0, 0x1); 43 | ASSERT_EQ_FMT(0xFFFFFFFF, get_segment(&gdt, 1)->first, "%lx"); 44 | ASSERT_EQ_FMT(0x00CF9A01, get_segment(&gdt, 1)->second, "%lx"); 45 | 46 | add_segment(&gdt, 0x0, 0xFFFF, 47 | SEG4K | SEG32 | SEG64_0 | SEG_LIMIT_16_19(0xf) | 48 | SEG_PRESENT | SEG_RING0 | SEG_CODE_DATA | SEG_RW, 0x0, 0x1); 49 | ASSERT_EQ_FMT(0x0000FFFF, get_segment(&gdt, 2)->first, "%lx"); 50 | ASSERT_EQ_FMT(0x00CF9200, get_segment(&gdt, 2)->second, "%lx"); 51 | 52 | uint32_t tid = idt_add_gate(0x28, 0x0000, 8); 53 | ASSERT_EQ_FMT(0x00280000, get_segment(&idt, 8)->first, "%lx"); 54 | printf("tid: %x\n", tid); 55 | 56 | /* seg(s2, 0x200FF, 0x00FF, g, t); */ 57 | /* ASSERT_EQ_FMT(0x00FF00FF, s2.first, "%lx"); */ 58 | /* ASSERT_EQ_FMT(0x00CF9A02, s2.second, "%lx"); */ 59 | 60 | /* segment_descriptor task1; */ 61 | /* seg(task1, 0x2500, 0x0100, */ 62 | /* SEG4K | SEG16 | SEG64_0 | SEG_LIMIT_16_19(0xf), */ 63 | /* SEG_PRESENT | SEG_RING0 | SEG_SYSTEM | SEG_TSS32_AVAILABLE); */ 64 | /* ASSERT_EQ_FMT(0x25000100, task1.first, "%lx"); */ 65 | /* ASSERT_EQ_FMT(0x008F8900, task1.second, "%lx"); */ 66 | 67 | /* seg(s1, 0xFFFF, 0x0000, 0x00, SEG_EXE_RW, SEG_CODE_DATA, DPL_RING0, SEG_PRESENT, 0xF, 0, SEG_IA32, SEG32, SEG4K, 0x00); */ 68 | /* ASSERT_EQ(0x00CF92000000FFFF, s1.raw); */ 69 | 70 | PASS(); 71 | } 72 | 73 | /* Suites can group multiple tests with common setup. */ 74 | SUITE(gdt_suite) { 75 | RUN_TEST(test_bit_mask); 76 | RUN_TEST(test_bit_value); 77 | RUN_TEST(test_create_segments); 78 | } 79 | 80 | /* definitions that need to be in the test runner's main file. */ 81 | GREATEST_MAIN_DEFS(); 82 | 83 | int main(int argc, char **argv) { 84 | GREATEST_MAIN_BEGIN(); /* command-line arguments, initialization. */ 85 | 86 | /* Individual tests can be run directly. */ 87 | /* RUN_TEST(x_should_equal_1); */ 88 | 89 | /* Tests can also be gathered into test suites. */ 90 | RUN_SUITE(gdt_suite); 91 | 92 | GREATEST_MAIN_END(); /* display results */ 93 | } 94 | -------------------------------------------------------------------------------- /kernel/test/test.o: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tuhdo/sample-os/09e25a85e2588bbcf68d935f76a2b4a7402a941e/kernel/test/test.o -------------------------------------------------------------------------------- /qemu.log: -------------------------------------------------------------------------------- 1 | CPU Reset (CPU 0) 2 | EAX=00000000 EBX=00000000 ECX=00000000 EDX=00000000 3 | ESI=00000000 EDI=00000000 EBP=00000000 ESP=00000000 4 | EIP=00000000 EFL=00000000 [-------] CPL=0 II=0 A20=0 SMM=0 HLT=0 5 | ES =0000 00000000 00000000 00000000 6 | CS =0000 00000000 00000000 00000000 7 | SS =0000 00000000 00000000 00000000 8 | DS =0000 00000000 00000000 00000000 9 | FS =0000 00000000 00000000 00000000 10 | GS =0000 00000000 00000000 00000000 11 | LDT=0000 00000000 00000000 00000000 12 | TR =0000 00000000 00000000 00000000 13 | GDT= 00000000 00000000 14 | IDT= 00000000 00000000 15 | CR0=00000000 CR2=00000000 CR3=00000000 CR4=00000000 16 | DR0=00000000 DR1=00000000 DR2=00000000 DR3=00000000 17 | DR6=00000000 DR7=00000000 18 | CCS=00000000 CCD=00000000 CCO=DYNAMIC 19 | EFER=0000000000000000 20 | FCW=0000 FSW=0000 [ST=0] FTW=ff MXCSR=00000000 21 | FPR0=0000000000000000 0000 FPR1=0000000000000000 0000 22 | FPR2=0000000000000000 0000 FPR3=0000000000000000 0000 23 | FPR4=0000000000000000 0000 FPR5=0000000000000000 0000 24 | FPR6=0000000000000000 0000 FPR7=0000000000000000 0000 25 | XMM00=00000000000000000000000000000000 XMM01=00000000000000000000000000000000 26 | XMM02=00000000000000000000000000000000 XMM03=00000000000000000000000000000000 27 | XMM04=00000000000000000000000000000000 XMM05=00000000000000000000000000000000 28 | XMM06=00000000000000000000000000000000 XMM07=00000000000000000000000000000000 29 | CR0 update: CR0=0x60000010 30 | CPU Reset (CPU 0) 31 | EAX=00000000 EBX=00000000 ECX=00000000 EDX=00000663 32 | ESI=00000000 EDI=00000000 EBP=00000000 ESP=00000000 33 | EIP=0000fff0 EFL=00000002 [-------] CPL=0 II=0 A20=1 SMM=0 HLT=0 34 | ES =0000 00000000 0000ffff 00009300 35 | CS =f000 ffff0000 0000ffff 00009b00 36 | SS =0000 00000000 0000ffff 00009300 37 | DS =0000 00000000 0000ffff 00009300 38 | FS =0000 00000000 0000ffff 00009300 39 | GS =0000 00000000 0000ffff 00009300 40 | LDT=0000 00000000 0000ffff 00008200 41 | TR =0000 00000000 0000ffff 00008b00 42 | GDT= 00000000 0000ffff 43 | IDT= 00000000 0000ffff 44 | CR0=60000010 CR2=00000000 CR3=00000000 CR4=00000000 45 | DR0=00000000 DR1=00000000 DR2=00000000 DR3=00000000 46 | DR6=ffff0ff0 DR7=00000400 47 | CCS=00000000 CCD=00000000 CCO=DYNAMIC 48 | EFER=0000000000000000 49 | FCW=037f FSW=0000 [ST=0] FTW=00 MXCSR=00001f80 50 | FPR0=0000000000000000 0000 FPR1=0000000000000000 0000 51 | FPR2=0000000000000000 0000 FPR3=0000000000000000 0000 52 | FPR4=0000000000000000 0000 FPR5=0000000000000000 0000 53 | FPR6=0000000000000000 0000 FPR7=0000000000000000 0000 54 | XMM00=00000000000000000000000000000000 XMM01=00000000000000000000000000000000 55 | XMM02=00000000000000000000000000000000 XMM03=00000000000000000000000000000000 56 | XMM04=00000000000000000000000000000000 XMM05=00000000000000000000000000000000 57 | XMM06=00000000000000000000000000000000 XMM07=00000000000000000000000000000000 58 | CR0 update: CR0=0x60000010 59 | --------------------------------------------------------------------------------