├── .gitignore ├── .travis.yml ├── LICENSE.md ├── Makefile ├── README.md ├── bios ├── Makefile ├── bios.bin ├── bios.c ├── bios.h ├── common.h ├── crt0.asm ├── crt0.bin ├── disk.asm ├── font8x8.h ├── functions.asm ├── keyboard.asm ├── service.asm ├── startup.asm ├── vga.c └── video.asm ├── device ├── Makefile ├── com.cpp ├── fdd.cpp ├── keyboard.cpp ├── mouse.cpp ├── pic.cpp ├── pit.cpp ├── syscontrol.cpp └── vga.cpp ├── emulator ├── Makefile ├── access.cpp ├── emulator.cpp ├── interrupt.cpp └── ui.cpp ├── hardware ├── Makefile ├── eflags.cpp ├── io.cpp ├── memory.cpp └── processor.cpp ├── haribote_10a.img ├── haribote_21h.img ├── include ├── common.hpp ├── device │ ├── com.hpp │ ├── dev_io.hpp │ ├── dev_irq.hpp │ ├── devices.hpp │ ├── dma.hpp │ ├── fdd.hpp │ ├── keyboard.hpp │ ├── mouse.hpp │ ├── pic.hpp │ ├── pit.hpp │ ├── syscontrol.hpp │ └── vga.hpp ├── emulator │ ├── access.hpp │ ├── descriptor.hpp │ ├── emulator.hpp │ ├── exception.hpp │ ├── interrupt.hpp │ └── ui.hpp ├── hardware │ ├── cr.hpp │ ├── eflags.hpp │ ├── hardware.hpp │ ├── io.hpp │ ├── memory.hpp │ └── processor.hpp ├── instruction │ ├── base.hpp │ └── instruction.hpp └── util │ ├── debug.hpp │ └── lru.hpp ├── instruction ├── Makefile ├── emu.cpp ├── exec.cpp ├── instr16.cpp ├── instr32.cpp ├── instr_base.cpp └── parse.cpp ├── main.cpp ├── run.sh ├── sample ├── .gitignore ├── Makefile ├── boot.asm ├── common.h ├── funcs.asm ├── init.c ├── kernel.img ├── keyboard.c ├── main.c ├── main2.c ├── startup.asm └── vga.c └── util ├── Makefile └── debug.cpp /.gitignore: -------------------------------------------------------------------------------- 1 | *.d 2 | *.o 3 | *.a 4 | *.swp 5 | x86emu 6 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | sudo: false 2 | addons: 3 | apt: 4 | packages: 5 | - libglfw3-dev 6 | 7 | # Enable C++ support 8 | language: cpp 9 | 10 | # Compiler selection 11 | compiler: 12 | - g++ 13 | 14 | os: 15 | - linux 16 | 17 | install: 18 | - true 19 | 20 | # Build steps 21 | script: 22 | - make all 23 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Yutaro Shimizu 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | TARGET := x86emu 2 | 3 | SRCS := main.cpp 4 | OBJS := $(SRCS:.cpp=.o) 5 | DEPS := $(SRCS:.cpp=.d) 6 | 7 | SUB_OBJS := emulator/emulator.a 8 | SUB_OBJS += instruction/instruction.a 9 | SUB_OBJS += hardware/hardware.a 10 | SUB_OBJS += device/device.a 11 | SUB_OBJS += util/util.a 12 | 13 | CXXFLAGS := -Wall -MMD -std=c++11 -I./include $(DEBUG) 14 | 15 | LDFLAGS := -lpthread 16 | 17 | UNAME = ${shell uname} 18 | ifeq ($(OS),Windows_NT) 19 | LDFLAGS += -lglfw3 -lopengl32 20 | else ifeq ($(UNAME),Linux) 21 | LDFLAGS += -lglfw -lGL 22 | else ifeq ($(UNAME),Darwin) 23 | LDFLAGS += -lglfw -framework OpenGL 24 | endif 25 | 26 | $(TARGET): $(OBJS) $(SUB_OBJS) 27 | $(CXX) $(CXXFLAGS) $^ -o $@ $(LDFLAGS) 28 | 29 | -include $(DEPS) 30 | 31 | $(SUB_OBJS): emu 32 | 33 | .PHONY: emu 34 | emu: 35 | ifdef DEBUG 36 | make -C hardware DEBUG=$(DEBUG) 37 | make -C emulator DEBUG=$(DEBUG) 38 | make -C instruction DEBUG=$(DEBUG) 39 | make -C device DEBUG=$(DEBUG) 40 | make -C util DEBUG=$(DEBUG) 41 | else 42 | make -C hardware 43 | make -C emulator 44 | make -C instruction 45 | make -C device 46 | make -C util 47 | endif 48 | 49 | .PHONY: os 50 | os: 51 | make -C bios 52 | make -C sample 53 | 54 | .PHONY: all 55 | all: emu $(TARGET) os 56 | 57 | .PHONY: clean 58 | clean: 59 | make clean -C hardware 60 | make clean -C emulator 61 | make clean -C instruction 62 | make clean -C device 63 | make clean -C util 64 | make clean -C bios 65 | make clean -C sample 66 | $(RM) $(DEPS) $(OBJS) $(TARGET) 67 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # x86emu 2 | 3 | [![Build Status](https://travis-ci.org/shift-crops/x86emu.svg?branch=master)](https://travis-ci.org/shift-crops/x86emu) 4 | [![MIT License](http://img.shields.io/badge/license-MIT-blue.svg?style=flat)](LICENSE.md) 5 | 6 | simple x86 emulator 7 | 8 | ## Description 9 | 10 | x86emu is an emulator of x86 architecture. 11 | 12 | This software supports multiple CPU mode (16bit/32bit, RealMode/ProtectedMode), and some devices. 13 | You can boot via FDD simulator (not support DMA), and operate with mouse and keyboard. 14 | 15 | ![Demo](https://github.com/shift-crops/x86emu/blob/media/demo_170524.gif) 16 | 17 | ## Features 18 | 19 | - Real mode / Protected mode 20 | - Interrupt and Exception 21 | - Devices 22 | - Lightweight BIOS 23 | - Preload FD image function (to reduce boot time) 24 | 25 | For more information, see `x86emu --help`. 26 | 27 | ## Requirement 28 | 29 | - [GLFW3](http://www.glfw.org/) 30 | 31 | ## Installation 32 | $ git clone https://github.com/shift-crops/x86emu 33 | $ make all 34 | 35 | ## Usage 36 | 37 | 1. Run the emulator with kernel image 38 | - `./x86emu haribote.img` 39 | 40 | ## License 41 | 42 | [MIT License](LICENSE.md) 43 | 44 | ## Author 45 | 46 | [@shift\_crops](https://twitter.com/shift_crops) 47 | 48 | -------------------------------------------------------------------------------- /bios/Makefile: -------------------------------------------------------------------------------- 1 | TARGET = bios.bin 2 | OBJS = startup.o bios.o functions.o service.o disk.o vga.o video.o keyboard.o 3 | 4 | CC := gcc 5 | AS := nasm 6 | CFLAGS += -masm=intel -nostdlib -fno-asynchronous-unwind-tables -fcf-protection=none -fno-stack-protector -fno-pie -m16 7 | LDFLAGS += --entry=start --oformat=binary -Ttext 0x0 -melf_i386 8 | 9 | all : 10 | make $(TARGET) 11 | 12 | %.o : %.c 13 | $(CC) $(CFLAGS) -c $< 14 | 15 | %.o : %.asm 16 | $(AS) -f elf $< 17 | 18 | crt0.bin : crt0.asm 19 | $(AS) $< -o $@ 20 | 21 | $(TARGET) : $(OBJS) crt0.bin 22 | $(LD) $(LDFLAGS) -o $@ $(OBJS) 23 | 24 | clean: 25 | #$(RM) $(OBJS) $(TARGET) crt0.bin 26 | $(RM) $(OBJS) 27 | -------------------------------------------------------------------------------- /bios/bios.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shift-crops/x86emu/fa65d448d71145fd611559a8a037dba211bb31a5/bios/bios.bin -------------------------------------------------------------------------------- /bios/bios.c: -------------------------------------------------------------------------------- 1 | #include "bios.h" 2 | 3 | char *msg = "now booting from floppy disk..."; 4 | 5 | int bios_main(void){ 6 | print(msg); 7 | return 0; 8 | } 9 | 10 | void bios_init(void){ 11 | init_ivt(); 12 | } 13 | 14 | void init_ivt(void){ 15 | set_ivt(0x10, (uint32_t)bsv_video, 0xf000); 16 | set_ivt(0x13, (uint32_t)bsv_disk, 0xf000); 17 | set_ivt(0x16, (uint32_t)bsv_keyboard, 0xf000); 18 | set_ivt(0x26, (uint32_t)bsv_irq_disk, 0xf000); 19 | } 20 | 21 | void set_ivt(int n, uint32_t offset, uint16_t cs){ 22 | IVT* ivt = (IVT*)0; 23 | 24 | write_esw(&(ivt[n].offset), offset); 25 | write_esw(&(ivt[n].segment), cs); 26 | } 27 | -------------------------------------------------------------------------------- /bios/bios.h: -------------------------------------------------------------------------------- 1 | #ifndef _BIOS_H 2 | #define _BIOS_H 3 | 4 | #include "common.h" 5 | 6 | typedef struct { 7 | uint16_t offset; 8 | uint16_t segment; 9 | } IVT; 10 | 11 | void init_ivt(void); 12 | void set_ivt(int n, uint32_t offset, uint16_t cs); 13 | 14 | #endif 15 | -------------------------------------------------------------------------------- /bios/common.h: -------------------------------------------------------------------------------- 1 | #ifndef _COMMON_H 2 | #define _COMMON_H 3 | 4 | #define uint8_t unsigned char 5 | #define uint16_t unsigned short 6 | #define uint32_t unsigned long 7 | #define bool uint8_t 8 | #define true 1 9 | #define false 0 10 | 11 | void write_esb(uint8_t *addr, uint8_t v); 12 | void write_esw(uint16_t *addr, uint16_t v); 13 | void write_esd(uint32_t *addr, uint32_t v); 14 | void copy_esw(uint16_t *daddr, uint16_t *saddr); 15 | uint8_t in_port(uint16_t port); 16 | void out_port(uint16_t port, uint8_t v); 17 | void _cli(void); 18 | void _sti(void); 19 | 20 | void bsv_test(void); 21 | void bsv_video(void); 22 | void bsv_disk(void); 23 | void bsv_keyboard(void); 24 | void bsv_irq_disk(void); 25 | 26 | uint32_t print(const uint8_t *s); 27 | 28 | #endif 29 | -------------------------------------------------------------------------------- /bios/crt0.asm: -------------------------------------------------------------------------------- 1 | BITS 16 2 | org 0xfff0 3 | jmp 0 4 | -------------------------------------------------------------------------------- /bios/crt0.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shift-crops/x86emu/fa65d448d71145fd611559a8a037dba211bb31a5/bios/crt0.bin -------------------------------------------------------------------------------- /bios/disk.asm: -------------------------------------------------------------------------------- 1 | global bsv_disk, bsv_irq_disk, fdd_configure 2 | 3 | BITS 16 4 | ; bsv_disk 5 | bsv_disk: 6 | cmp ah, 0x02 7 | je disk_read_sector 8 | cmp ah, 0x03 9 | je disk_write_sector 10 | ;cmp ah, 0x0c 11 | ;je disk_seek_cylinder 12 | ;mov ax, 0x01 13 | iret 14 | 15 | ; bsv_irq_disk 16 | bsv_irq_disk: 17 | cli 18 | pusha 19 | mov al, 0x66 20 | out 0x20, al 21 | mov dx, 0x03f4 22 | in al, dx 23 | test al, 0x80 24 | jz irq_disk_end 25 | mov dx, 0x03f5 26 | test al, 0x40 27 | jz irq_disk_read 28 | mov al, [es:bx] 29 | out dx, al 30 | jmp irq_disk_end 31 | irq_disk_read: 32 | in al, dx 33 | mov [es:bx], al 34 | irq_disk_end: 35 | popa 36 | inc bx 37 | iret 38 | 39 | ; disk_read_sector 40 | disk_read_sector: 41 | pusha 42 | 43 | mov ah, al 44 | xchg dh, ch 45 | xchg ch, cl 46 | read_loop: 47 | mov di, bx 48 | add di, 0x200 49 | 50 | push 0xff00 51 | push 0x1202 52 | push cx 53 | push dx 54 | call fdd_read_data 55 | read_busywait: 56 | mov dx, 0x03f4 57 | in al, dx 58 | test al, 0x80 59 | jz read_busywait 60 | 61 | mov dx, 0x03f5 62 | read_next: 63 | in al, dx 64 | mov [es:bx], al 65 | inc bx 66 | cmp bx, di 67 | jl read_next 68 | 69 | mov cx, 0 70 | read_status: 71 | in al, dx 72 | inc cx 73 | cmp cx, 7 74 | jl read_status 75 | 76 | pop dx 77 | pop cx 78 | add sp, 0x04 79 | sub ah, 1 80 | add ch, 1 81 | test ah, ah 82 | jne read_loop 83 | 84 | mov di, sp 85 | add di, 0x14 86 | mov ax, [ss:di] 87 | and ax, 0xfffe 88 | mov [ss:di], ax 89 | 90 | popa 91 | iret 92 | 93 | ; disk_write_sector 94 | disk_write_sector: 95 | mov ah, al 96 | xchg dh, ch 97 | xchg ch, cl 98 | write_loop: 99 | mov di, bx 100 | add di, 0x200 101 | 102 | push 0xff00 103 | push 0x1202 104 | push cx 105 | push dx 106 | call fdd_write_data 107 | mov al, [es:bx] 108 | out dx, al 109 | inc bx 110 | write_busywait: 111 | cmp bx, di 112 | jl write_busywait 113 | 114 | mov dx, 0x03f5 115 | mov cx, 0 116 | write_status: 117 | in al, dx 118 | inc cx 119 | cmp cx, 7 120 | jl write_status 121 | 122 | pop dx 123 | pop cx 124 | add sp, 0x04 125 | sub ah, 1 126 | add ch, 1 127 | test ah, ah 128 | jne write_loop 129 | iret 130 | 131 | ; fdd_read_track 132 | fdd_read_track: 133 | push bp 134 | mov bp, sp 135 | mov dx, 0x03f5 136 | mov al, 0x02 137 | out dx, al 138 | mov cx, 0x08 139 | jmp fdd_args 140 | 141 | ; fdd_write_data 142 | fdd_write_data: 143 | push bp 144 | mov bp, sp 145 | mov dx, 0x03f5 146 | mov al, 0x05 147 | out dx, al 148 | mov cx, 0x08 149 | jmp fdd_args 150 | 151 | ; fdd_read_data 152 | fdd_read_data: 153 | push bp 154 | mov bp, sp 155 | mov dx, 0x03f5 156 | mov al, 0x06 157 | out dx, al 158 | mov cx, 0x08 159 | jmp fdd_args 160 | 161 | ; fdd_configure 162 | fdd_configure: 163 | push bp 164 | mov bp, sp 165 | mov dx, 0x03f5 166 | mov al, 0x13 167 | out dx, al 168 | mov cx, 0x03 169 | jmp fdd_args 170 | 171 | fdd_args: 172 | mov si, 0 173 | args_loop: 174 | cmp si, cx 175 | jge args_end 176 | mov al, [bp+si+4] 177 | out dx, al 178 | inc si 179 | jmp args_loop 180 | args_end: 181 | leave 182 | ret 183 | -------------------------------------------------------------------------------- /bios/font8x8.h: -------------------------------------------------------------------------------- 1 | /** 2 | * 8x8 monochrome bitmap fonts for rendering 3 | * Author: Daniel Hepper 4 | * 5 | * License: Public Domain 6 | * 7 | * Based on: 8 | * // Summary: font8x8.h 9 | * // 8x8 monochrome bitmap fonts for rendering 10 | * // 11 | * // Author: 12 | * // Marcel Sondaar 13 | * // International Business Machines (public domain VGA fonts) 14 | * // 15 | * // License: 16 | * // Public Domain 17 | * 18 | * Fetched from: http://dimensionalrift.homelinux.net/combuster/mos3/?p=viewsource&file=/modules/gfx/font8_8.asm 19 | **/ 20 | 21 | // Constant: font8x8_basic 22 | // Contains an 8x8 font map for unicode points U+0000 - U+007F (basic latin) 23 | unsigned char font8x8_basic[128][8] = { 24 | { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0000 (nul) 25 | { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0001 26 | { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0002 27 | { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0003 28 | { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0004 29 | { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0005 30 | { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0006 31 | { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0007 32 | { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0008 33 | { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0009 34 | { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+000A 35 | { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+000B 36 | { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+000C 37 | { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+000D 38 | { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+000E 39 | { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+000F 40 | { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0010 41 | { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0011 42 | { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0012 43 | { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0013 44 | { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0014 45 | { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0015 46 | { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0016 47 | { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0017 48 | { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0018 49 | { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0019 50 | { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+001A 51 | { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+001B 52 | { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+001C 53 | { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+001D 54 | { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+001E 55 | { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+001F 56 | { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0020 (space) 57 | { 0x18, 0x3C, 0x3C, 0x18, 0x18, 0x00, 0x18, 0x00}, // U+0021 (!) 58 | { 0x36, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0022 (") 59 | { 0x36, 0x36, 0x7F, 0x36, 0x7F, 0x36, 0x36, 0x00}, // U+0023 (#) 60 | { 0x0C, 0x3E, 0x03, 0x1E, 0x30, 0x1F, 0x0C, 0x00}, // U+0024 ($) 61 | { 0x00, 0x63, 0x33, 0x18, 0x0C, 0x66, 0x63, 0x00}, // U+0025 (%) 62 | { 0x1C, 0x36, 0x1C, 0x6E, 0x3B, 0x33, 0x6E, 0x00}, // U+0026 (&) 63 | { 0x06, 0x06, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0027 (') 64 | { 0x18, 0x0C, 0x06, 0x06, 0x06, 0x0C, 0x18, 0x00}, // U+0028 (() 65 | { 0x06, 0x0C, 0x18, 0x18, 0x18, 0x0C, 0x06, 0x00}, // U+0029 ()) 66 | { 0x00, 0x66, 0x3C, 0xFF, 0x3C, 0x66, 0x00, 0x00}, // U+002A (*) 67 | { 0x00, 0x0C, 0x0C, 0x3F, 0x0C, 0x0C, 0x00, 0x00}, // U+002B (+) 68 | { 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x0C, 0x06}, // U+002C (,) 69 | { 0x00, 0x00, 0x00, 0x3F, 0x00, 0x00, 0x00, 0x00}, // U+002D (-) 70 | { 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x0C, 0x00}, // U+002E (.) 71 | { 0x60, 0x30, 0x18, 0x0C, 0x06, 0x03, 0x01, 0x00}, // U+002F (/) 72 | { 0x3E, 0x63, 0x73, 0x7B, 0x6F, 0x67, 0x3E, 0x00}, // U+0030 (0) 73 | { 0x0C, 0x0E, 0x0C, 0x0C, 0x0C, 0x0C, 0x3F, 0x00}, // U+0031 (1) 74 | { 0x1E, 0x33, 0x30, 0x1C, 0x06, 0x33, 0x3F, 0x00}, // U+0032 (2) 75 | { 0x1E, 0x33, 0x30, 0x1C, 0x30, 0x33, 0x1E, 0x00}, // U+0033 (3) 76 | { 0x38, 0x3C, 0x36, 0x33, 0x7F, 0x30, 0x78, 0x00}, // U+0034 (4) 77 | { 0x3F, 0x03, 0x1F, 0x30, 0x30, 0x33, 0x1E, 0x00}, // U+0035 (5) 78 | { 0x1C, 0x06, 0x03, 0x1F, 0x33, 0x33, 0x1E, 0x00}, // U+0036 (6) 79 | { 0x3F, 0x33, 0x30, 0x18, 0x0C, 0x0C, 0x0C, 0x00}, // U+0037 (7) 80 | { 0x1E, 0x33, 0x33, 0x1E, 0x33, 0x33, 0x1E, 0x00}, // U+0038 (8) 81 | { 0x1E, 0x33, 0x33, 0x3E, 0x30, 0x18, 0x0E, 0x00}, // U+0039 (9) 82 | { 0x00, 0x0C, 0x0C, 0x00, 0x00, 0x0C, 0x0C, 0x00}, // U+003A (:) 83 | { 0x00, 0x0C, 0x0C, 0x00, 0x00, 0x0C, 0x0C, 0x06}, // U+003B (//) 84 | { 0x18, 0x0C, 0x06, 0x03, 0x06, 0x0C, 0x18, 0x00}, // U+003C (<) 85 | { 0x00, 0x00, 0x3F, 0x00, 0x00, 0x3F, 0x00, 0x00}, // U+003D (=) 86 | { 0x06, 0x0C, 0x18, 0x30, 0x18, 0x0C, 0x06, 0x00}, // U+003E (>) 87 | { 0x1E, 0x33, 0x30, 0x18, 0x0C, 0x00, 0x0C, 0x00}, // U+003F (?) 88 | { 0x3E, 0x63, 0x7B, 0x7B, 0x7B, 0x03, 0x1E, 0x00}, // U+0040 (@) 89 | { 0x0C, 0x1E, 0x33, 0x33, 0x3F, 0x33, 0x33, 0x00}, // U+0041 (A) 90 | { 0x3F, 0x66, 0x66, 0x3E, 0x66, 0x66, 0x3F, 0x00}, // U+0042 (B) 91 | { 0x3C, 0x66, 0x03, 0x03, 0x03, 0x66, 0x3C, 0x00}, // U+0043 (C) 92 | { 0x1F, 0x36, 0x66, 0x66, 0x66, 0x36, 0x1F, 0x00}, // U+0044 (D) 93 | { 0x7F, 0x46, 0x16, 0x1E, 0x16, 0x46, 0x7F, 0x00}, // U+0045 (E) 94 | { 0x7F, 0x46, 0x16, 0x1E, 0x16, 0x06, 0x0F, 0x00}, // U+0046 (F) 95 | { 0x3C, 0x66, 0x03, 0x03, 0x73, 0x66, 0x7C, 0x00}, // U+0047 (G) 96 | { 0x33, 0x33, 0x33, 0x3F, 0x33, 0x33, 0x33, 0x00}, // U+0048 (H) 97 | { 0x1E, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x1E, 0x00}, // U+0049 (I) 98 | { 0x78, 0x30, 0x30, 0x30, 0x33, 0x33, 0x1E, 0x00}, // U+004A (J) 99 | { 0x67, 0x66, 0x36, 0x1E, 0x36, 0x66, 0x67, 0x00}, // U+004B (K) 100 | { 0x0F, 0x06, 0x06, 0x06, 0x46, 0x66, 0x7F, 0x00}, // U+004C (L) 101 | { 0x63, 0x77, 0x7F, 0x7F, 0x6B, 0x63, 0x63, 0x00}, // U+004D (M) 102 | { 0x63, 0x67, 0x6F, 0x7B, 0x73, 0x63, 0x63, 0x00}, // U+004E (N) 103 | { 0x1C, 0x36, 0x63, 0x63, 0x63, 0x36, 0x1C, 0x00}, // U+004F (O) 104 | { 0x3F, 0x66, 0x66, 0x3E, 0x06, 0x06, 0x0F, 0x00}, // U+0050 (P) 105 | { 0x1E, 0x33, 0x33, 0x33, 0x3B, 0x1E, 0x38, 0x00}, // U+0051 (Q) 106 | { 0x3F, 0x66, 0x66, 0x3E, 0x36, 0x66, 0x67, 0x00}, // U+0052 (R) 107 | { 0x1E, 0x33, 0x07, 0x0E, 0x38, 0x33, 0x1E, 0x00}, // U+0053 (S) 108 | { 0x3F, 0x2D, 0x0C, 0x0C, 0x0C, 0x0C, 0x1E, 0x00}, // U+0054 (T) 109 | { 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x3F, 0x00}, // U+0055 (U) 110 | { 0x33, 0x33, 0x33, 0x33, 0x33, 0x1E, 0x0C, 0x00}, // U+0056 (V) 111 | { 0x63, 0x63, 0x63, 0x6B, 0x7F, 0x77, 0x63, 0x00}, // U+0057 (W) 112 | { 0x63, 0x63, 0x36, 0x1C, 0x1C, 0x36, 0x63, 0x00}, // U+0058 (X) 113 | { 0x33, 0x33, 0x33, 0x1E, 0x0C, 0x0C, 0x1E, 0x00}, // U+0059 (Y) 114 | { 0x7F, 0x63, 0x31, 0x18, 0x4C, 0x66, 0x7F, 0x00}, // U+005A (Z) 115 | { 0x1E, 0x06, 0x06, 0x06, 0x06, 0x06, 0x1E, 0x00}, // U+005B ([) 116 | { 0x03, 0x06, 0x0C, 0x18, 0x30, 0x60, 0x40, 0x00}, // U+005C (\) 117 | { 0x1E, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1E, 0x00}, // U+005D (]) 118 | { 0x08, 0x1C, 0x36, 0x63, 0x00, 0x00, 0x00, 0x00}, // U+005E (^) 119 | { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF}, // U+005F (_) 120 | { 0x0C, 0x0C, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0060 (`) 121 | { 0x00, 0x00, 0x1E, 0x30, 0x3E, 0x33, 0x6E, 0x00}, // U+0061 (a) 122 | { 0x07, 0x06, 0x06, 0x3E, 0x66, 0x66, 0x3B, 0x00}, // U+0062 (b) 123 | { 0x00, 0x00, 0x1E, 0x33, 0x03, 0x33, 0x1E, 0x00}, // U+0063 (c) 124 | { 0x38, 0x30, 0x30, 0x3e, 0x33, 0x33, 0x6E, 0x00}, // U+0064 (d) 125 | { 0x00, 0x00, 0x1E, 0x33, 0x3f, 0x03, 0x1E, 0x00}, // U+0065 (e) 126 | { 0x1C, 0x36, 0x06, 0x0f, 0x06, 0x06, 0x0F, 0x00}, // U+0066 (f) 127 | { 0x00, 0x00, 0x6E, 0x33, 0x33, 0x3E, 0x30, 0x1F}, // U+0067 (g) 128 | { 0x07, 0x06, 0x36, 0x6E, 0x66, 0x66, 0x67, 0x00}, // U+0068 (h) 129 | { 0x0C, 0x00, 0x0E, 0x0C, 0x0C, 0x0C, 0x1E, 0x00}, // U+0069 (i) 130 | { 0x30, 0x00, 0x30, 0x30, 0x30, 0x33, 0x33, 0x1E}, // U+006A (j) 131 | { 0x07, 0x06, 0x66, 0x36, 0x1E, 0x36, 0x67, 0x00}, // U+006B (k) 132 | { 0x0E, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x1E, 0x00}, // U+006C (l) 133 | { 0x00, 0x00, 0x33, 0x7F, 0x7F, 0x6B, 0x63, 0x00}, // U+006D (m) 134 | { 0x00, 0x00, 0x1F, 0x33, 0x33, 0x33, 0x33, 0x00}, // U+006E (n) 135 | { 0x00, 0x00, 0x1E, 0x33, 0x33, 0x33, 0x1E, 0x00}, // U+006F (o) 136 | { 0x00, 0x00, 0x3B, 0x66, 0x66, 0x3E, 0x06, 0x0F}, // U+0070 (p) 137 | { 0x00, 0x00, 0x6E, 0x33, 0x33, 0x3E, 0x30, 0x78}, // U+0071 (q) 138 | { 0x00, 0x00, 0x3B, 0x6E, 0x66, 0x06, 0x0F, 0x00}, // U+0072 (r) 139 | { 0x00, 0x00, 0x3E, 0x03, 0x1E, 0x30, 0x1F, 0x00}, // U+0073 (s) 140 | { 0x08, 0x0C, 0x3E, 0x0C, 0x0C, 0x2C, 0x18, 0x00}, // U+0074 (t) 141 | { 0x00, 0x00, 0x33, 0x33, 0x33, 0x33, 0x6E, 0x00}, // U+0075 (u) 142 | { 0x00, 0x00, 0x33, 0x33, 0x33, 0x1E, 0x0C, 0x00}, // U+0076 (v) 143 | { 0x00, 0x00, 0x63, 0x6B, 0x7F, 0x7F, 0x36, 0x00}, // U+0077 (w) 144 | { 0x00, 0x00, 0x63, 0x36, 0x1C, 0x36, 0x63, 0x00}, // U+0078 (x) 145 | { 0x00, 0x00, 0x33, 0x33, 0x33, 0x3E, 0x30, 0x1F}, // U+0079 (y) 146 | { 0x00, 0x00, 0x3F, 0x19, 0x0C, 0x26, 0x3F, 0x00}, // U+007A (z) 147 | { 0x38, 0x0C, 0x0C, 0x07, 0x0C, 0x0C, 0x38, 0x00}, // U+007B ({) 148 | { 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x00}, // U+007C (|) 149 | { 0x07, 0x0C, 0x0C, 0x38, 0x0C, 0x0C, 0x07, 0x00}, // U+007D (}) 150 | { 0x6E, 0x3B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+007E (~) 151 | { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} // U+007F 152 | }; 153 | -------------------------------------------------------------------------------- /bios/functions.asm: -------------------------------------------------------------------------------- 1 | global write_esb, write_esw, write_esd, copy_esw 2 | global in_port, out_port, _cli, _sti 3 | 4 | BITS 16 5 | write_esb: 6 | push ebp 7 | mov ebp, esp 8 | push edi 9 | mov di, word [ebp+0x8] 10 | mov eax, dword [ebp+0xc] 11 | mov byte [es:di], al 12 | pop edi 13 | o32 leave 14 | o32 ret 15 | 16 | write_esw: 17 | push ebp 18 | mov ebp, esp 19 | push edi 20 | mov di, word [ebp+0x8] 21 | mov eax, dword [ebp+0xc] 22 | mov word [es:di], ax 23 | pop edi 24 | o32 leave 25 | o32 ret 26 | 27 | write_esd: 28 | push ebp 29 | mov ebp, esp 30 | push edi 31 | mov di, word [ebp+0x8] 32 | mov eax, dword [ebp+0xc] 33 | mov dword [es:di], eax 34 | pop edi 35 | o32 leave 36 | o32 ret 37 | 38 | copy_esw: 39 | push ebp 40 | mov ebp, esp 41 | push esi 42 | push edi 43 | mov di, word [ebp+0x8] 44 | mov si, word [ebp+0xc] 45 | mov ax, word [es:si] 46 | mov word [es:di], ax 47 | pop edi 48 | pop esi 49 | o32 leave 50 | o32 ret 51 | 52 | in_port: 53 | push ebp 54 | mov ebp, esp 55 | push edx 56 | mov edx, dword [ebp+0x8] 57 | xor eax, eax 58 | in al, dx 59 | pop edx 60 | o32 leave 61 | o32 ret 62 | 63 | out_port: 64 | push ebp 65 | mov ebp, esp 66 | push eax 67 | push edx 68 | mov edx, dword [ebp+0x8] 69 | mov eax, dword [ebp+0xc] 70 | out dx, al 71 | pop edx 72 | pop eax 73 | o32 leave 74 | o32 ret 75 | 76 | _cli: 77 | cli 78 | o32 ret 79 | 80 | _sti: 81 | sti 82 | o32 ret 83 | -------------------------------------------------------------------------------- /bios/keyboard.asm: -------------------------------------------------------------------------------- 1 | global bsv_keyboard 2 | 3 | BITS 16 4 | ; bsv_keyboard 5 | bsv_keyboard: 6 | cmp ah, 0x02 7 | je keyboard_ret_sf_stat 8 | iret 9 | 10 | ; keyboard_ret_sf_stat 11 | keyboard_ret_sf_stat: 12 | mov al, 0 13 | iret 14 | -------------------------------------------------------------------------------- /bios/service.asm: -------------------------------------------------------------------------------- 1 | global bsv_test 2 | 3 | BITS 16 4 | bsv_test: 5 | mov dx, 0x03f8 6 | mov si, msghello 7 | puts_loop: 8 | mov al, [si] 9 | inc si 10 | cmp al, 0 11 | je puts_end 12 | out dx, al 13 | jmp puts_loop 14 | puts_end: 15 | iret 16 | 17 | msghello: 18 | db "Hello, World", 0x0a, 0x00 19 | -------------------------------------------------------------------------------- /bios/startup.asm: -------------------------------------------------------------------------------- 1 | extern bios_main, bios_init 2 | extern fdd_configure 3 | extern attr_configure, seq_configure, dac_configure, gc_configure, load_font 4 | global start 5 | 6 | BITS 16 7 | start: 8 | mov ax, cs 9 | mov ds, ax 10 | mov ax, 0x400 11 | mov ss, ax 12 | mov sp, 0x2000 13 | 14 | xor ax, ax 15 | mov es, ax 16 | 17 | ;call init_pic 18 | call init_fdd 19 | call init_vga 20 | call dword bios_init 21 | call dword bios_main 22 | call load_mbr 23 | jmp 0x0:0x7c00 24 | 25 | init_pic: 26 | cli 27 | mov al, 0x11 28 | out 0x20, al 29 | out 0xa0, al 30 | 31 | mov al, 0x20 32 | out 0x21, al 33 | mov al, 0x28 34 | out 0xa1, al 35 | 36 | mov al, 0x4 37 | out 0x21, al 38 | mov al, 2 39 | out 0xa1, al 40 | 41 | mov al, 0x1 42 | out 0x21, al 43 | out 0xa1, al 44 | 45 | mov al, 0xfb 46 | out 0x21, al 47 | mov al, 0xff 48 | out 0xa1, al 49 | sti 50 | ret 51 | 52 | init_fdd: 53 | push 0x0000 54 | push 0x4000 55 | call fdd_configure 56 | add sp, 4 57 | 58 | cli 59 | in al, 0x21 60 | and al, 0xbf 61 | out 0x21, al 62 | sti 63 | ret 64 | 65 | init_vga: 66 | cli 67 | ; mor : 0x2 68 | mov dx, 0x03c2 69 | mov al, 0x2 70 | out dx, al 71 | sti 72 | 73 | call dword load_font 74 | 75 | cli 76 | call dword attr_configure 77 | call dword seq_configure 78 | call dword dac_configure 79 | call dword gc_configure 80 | 81 | ; x : 320 82 | mov dx, 0x03b4 83 | mov al, 0x1 84 | out dx, al 85 | mov dx, 0x03b5 86 | mov al, 0x28 87 | out dx, al 88 | 89 | ; y : 200 90 | mov dx, 0x03b4 91 | mov al, 0x12 92 | out dx, al 93 | mov dx, 0x03b5 94 | mov al, 0x19 95 | out dx, al 96 | 97 | ; MSL : 8 98 | mov dx, 0x03b4 99 | mov al, 0x09 100 | out dx, al 101 | mov dx, 0x03b5 102 | mov al, 0x8-1 103 | out dx, al 104 | sti 105 | 106 | ret 107 | 108 | load_mbr: 109 | mov ax, 0x0 110 | mov es, ax 111 | mov bx, 0x7c00 112 | 113 | mov ah, 0x2 ; read 114 | mov al, 0x1 ; sectors 115 | mov ch, 0x0 ; cylinder 116 | mov cl, 0x1 ; sector 117 | mov dh, 0x0 ; head 118 | mov dl, 0x0 ; drive 119 | int 0x13 120 | ret 121 | -------------------------------------------------------------------------------- /bios/vga.c: -------------------------------------------------------------------------------- 1 | #include "common.h" 2 | #include "font8x8.h" 3 | 4 | typedef struct { 5 | uint8_t red; 6 | uint8_t green; 7 | uint8_t blue; 8 | } rgb_t; 9 | 10 | const rgb_t palette[0x10] = { 11 | // R, G, B 12 | {0x00, 0x00, 0x00}, 13 | {0x00, 0x00, 0x2a}, 14 | {0x00, 0x2a, 0x00}, 15 | {0x00, 0x2a, 0x2a}, 16 | {0x2a, 0x00, 0x00}, 17 | {0x2a, 0x00, 0x2a}, 18 | {0x2a, 0x15, 0x00}, 19 | {0x2a, 0x2a, 0x2a}, 20 | {0x15, 0x15, 0x15}, 21 | {0x15, 0x15, 0x3f}, 22 | {0x15, 0x3f, 0x15}, 23 | {0x15, 0x3f, 0x3f}, 24 | {0x3f, 0x15, 0x15}, 25 | {0x3f, 0x15, 0x3f}, 26 | {0x3f, 0x3f, 0x15}, 27 | {0x3f, 0x3f, 0x3f} 28 | }; 29 | 30 | void attr_configure(void){ 31 | for(int i=0; i<0x10; i++){ 32 | out_port(0x3c0, i); 33 | out_port(0x3c1, i); 34 | } 35 | } 36 | 37 | void seq_configure(void){ 38 | out_port(0x3c4, 2); 39 | out_port(0x3c5, 0x3); 40 | 41 | out_port(0x3c4, 3); 42 | out_port(0x3c5, 0x0); 43 | 44 | out_port(0x3c4, 4); 45 | out_port(0x3c5, 0x2); 46 | } 47 | 48 | void dac_configure(void){ 49 | out_port(0x3c8, 0); 50 | for(int i=0; i<0x10; i++){ 51 | out_port(0x3c9, palette[i].red); 52 | out_port(0x3c9, palette[i].green); 53 | out_port(0x3c9, palette[i].blue); 54 | } 55 | } 56 | 57 | void gc_configure(void){ 58 | out_port(0x3ce, 5); 59 | out_port(0x3cf, 0x10); 60 | 61 | out_port(0x3ce, 6); 62 | out_port(0x3cf, 0xe); 63 | } 64 | 65 | void load_font(void){ 66 | _cli(); 67 | out_port(0x3c4, 2); 68 | out_port(0x3c5, 0x4); 69 | out_port(0x3c4, 4); 70 | out_port(0x3c5, 0x6); 71 | 72 | out_port(0x3ce, 5); 73 | out_port(0x3cf, 0x0); 74 | out_port(0x3ce, 6); 75 | out_port(0x3cf, 0x0); 76 | _sti(); 77 | 78 | __asm__("push es\n" 79 | "mov ax, 0xa000\n" 80 | "mov es, ax"); 81 | 82 | for(int i=0; i<0x80; i++){ 83 | uint8_t *p = font8x8_basic[i]; 84 | write_esd((uint32_t*)(i*0x10), *(uint32_t*)&p[0]); 85 | write_esd((uint32_t*)(i*0x10+4), *(uint32_t*)&p[4]); 86 | } 87 | __asm__("pop es"); 88 | } 89 | 90 | extern uint16_t cursor_x, cursor_y; 91 | uint32_t print(const uint8_t *s){ 92 | uint32_t i; 93 | 94 | __asm__("push es\n" 95 | "mov ax, 0xb800\n" 96 | "mov es, ax"); 97 | 98 | for(i=0; s[i]; i++){ 99 | write_esw((uint16_t*)((cursor_y*0x28 + cursor_x)*2), 0x0700 + s[i]); 100 | cursor_x++; 101 | if(cursor_x >= 0x28 || !(s[i]^0x0a)){ 102 | cursor_x = 0; 103 | cursor_y++; 104 | } 105 | 106 | if(cursor_y >= 0x19){ 107 | uint32_t j; 108 | for(j=0; j<0x18*0x28; j++) 109 | copy_esw((uint16_t*)(j*2), (uint16_t*)((0x28+j)*2)); 110 | for(; j<0x19*0x28; j++) 111 | write_esw((uint16_t*)(j*2), 0x0700); 112 | cursor_x = 0; 113 | cursor_y--; 114 | } 115 | } 116 | 117 | __asm__("pop es"); 118 | 119 | return i; 120 | } 121 | 122 | -------------------------------------------------------------------------------- /bios/video.asm: -------------------------------------------------------------------------------- 1 | global bsv_video, cursor_x, cursor_y 2 | 3 | BITS 16 4 | ; bsv_video 5 | bsv_video: 6 | cmp ah, 0x00 7 | je video_set_video_mode 8 | cmp ah, 0x02 9 | je video_set_cursor_pos 10 | cmp ah, 0x03 11 | je video_get_cursor_pos 12 | cmp ah, 0x06 13 | je video_scroll_up 14 | cmp ah, 0x0e 15 | je video_write_teletype 16 | cmp ah, 0x13 17 | je video_write_string 18 | iret 19 | 20 | ; video_set_video_mode 21 | video_set_video_mode: 22 | mov dx, 0x3c4 23 | mov al, 2 24 | out dx, al 25 | mov dx, 0x3c5 26 | mov al, 0x4 27 | out dx, al 28 | mov dx, 0x3c4 29 | mov al, 4 30 | out dx, al 31 | mov dx, 0x3c5 32 | mov al, 0x6 33 | out dx, al 34 | 35 | mov dx, 0x3ce 36 | mov al, 5 37 | out dx, al 38 | mov dx, 0x3cf 39 | mov al, 0x0 40 | out dx, al 41 | mov dx, 0x3ce 42 | mov al, 6 43 | out dx, al 44 | mov dx, 0x3cf 45 | mov al, 0x5 46 | out dx, al 47 | iret 48 | 49 | ; video_set_cursor_pos 50 | video_set_cursor_pos: 51 | mov [cursor_x], dl 52 | mov [cursor_y], dh 53 | mov ax, 0x0 54 | iret 55 | 56 | ; video_get_cursor_pos 57 | video_get_cursor_pos: 58 | mov dl, [cursor_x] 59 | mov dh, [cursor_y] 60 | mov ax, 0x0 61 | iret 62 | 63 | ; video_scroll_up 64 | video_scroll_up: 65 | pusha 66 | push ds 67 | mov cx, 0xb800 68 | mov ds, cx 69 | xor ah, ah 70 | sub word [cursor_y], ax 71 | mov si, ax 72 | imul si, 0x28*2 73 | xor di, di 74 | mov cx, 0x19 ; 0xc8/0x8 75 | sub cx, ax 76 | imul cx, 0x28 77 | video_up_loop: 78 | mov dx, [si] 79 | mov [di], dx 80 | add si, 2 81 | add di, 2 82 | dec cx 83 | test cx, cx 84 | jnz video_up_loop 85 | 86 | xor bl, bl 87 | video_up_attr_loop: 88 | mov [di], bx 89 | add di, 2 90 | cmp di, 0x28*2*0x19 91 | jl video_up_attr_loop 92 | pop ds 93 | popa 94 | iret 95 | 96 | ; video_write_teletype 97 | video_write_teletype: 98 | pusha 99 | push ds 100 | mov cx, 0xb800 101 | mov ds, cx 102 | mov di, [cursor_y] 103 | imul di, 0x28 104 | add di, [cursor_x] 105 | imul di, 2 106 | mov [di], al 107 | inc di 108 | mov [di], bl 109 | 110 | mov di, [cursor_x] 111 | inc di 112 | cmp di, 0x28 113 | jl video_teletype_end 114 | 115 | mov di, 0 116 | inc word [cursor_y] 117 | video_teletype_end: 118 | mov [cursor_x], di 119 | pop ds 120 | popa 121 | iret 122 | 123 | ; video_write_string 124 | video_write_string: 125 | pusha 126 | push ds 127 | push dx 128 | mov cx, 0xb800 129 | mov ds, cx 130 | 131 | xor cx, cx 132 | mov cl, dh 133 | imul cx, 0x28 134 | xor dh, dh 135 | add dx, cx 136 | imul di, dx, 2 137 | 138 | xor cx, cx 139 | video_string_loop: 140 | mov ah, [es:bp] 141 | cmp ah ,0x0 142 | jz video_string_end 143 | mov [di], ah 144 | inc di 145 | cmp al, 0x2 146 | jl video_string_skip_attr 147 | mov [di], bl 148 | video_string_skip_attr: 149 | inc bp 150 | inc di 151 | inc cx 152 | jmp video_string_loop 153 | 154 | video_string_end: 155 | pop dx 156 | test al, 1 157 | jz video_string_skip_cursor 158 | mov [cursor_x], dl 159 | add [cursor_x], cx 160 | mov [cursor_y], dh 161 | video_string_skip_cursor: 162 | pop ds 163 | popa 164 | iret 165 | 166 | cursor_x: 167 | dw 0 168 | cursor_y: 169 | dw 0 170 | -------------------------------------------------------------------------------- /device/Makefile: -------------------------------------------------------------------------------- 1 | TARGET := device.a 2 | 3 | SRCS := com.cpp syscontrol.cpp pic.cpp pit.cpp fdd.cpp vga.cpp keyboard.cpp mouse.cpp 4 | OBJS := $(SRCS:.cpp=.o) 5 | DEPS := $(SRCS:.cpp=.d) 6 | 7 | CXXFLAGS := -Wall -MMD -std=c++11 -I../include $(DEBUG) 8 | 9 | .PHONY: all 10 | all: $(TARGET) 11 | 12 | -include $(DEPS) 13 | 14 | $(TARGET): $(OBJS) 15 | $(AR) rcs $@ $^ 16 | 17 | .PHONY: clean 18 | clean: 19 | $(RM) $(DEPS) $(OBJS) $(TARGET) 20 | -------------------------------------------------------------------------------- /device/com.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "device/com.hpp" 3 | 4 | uint8_t COM::in8(uint16_t addr){ 5 | return getchar(); 6 | } 7 | 8 | void COM::out8(uint16_t addr, uint8_t v){ 9 | putchar(v); 10 | } 11 | -------------------------------------------------------------------------------- /device/fdd.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "device/fdd.hpp" 4 | 5 | FDD::FDD(){ 6 | fddfuncs[FDD_READ_TRACK] = &FDD::fdd_read_track; 7 | fddfuncs[FDD_WRITE_DATA] = &FDD::fdd_write_data; 8 | fddfuncs[FDD_READ_DATA] = &FDD::fdd_read_data; 9 | fddfuncs[FDD_CONFIGURE] = &FDD::fdd_configure; 10 | 11 | for(int i=0; i=MAX_FDD || drive[slot]) 37 | return false; 38 | 39 | d = new DRIVE; 40 | d->disk = fopen(fname, write ? "rb+" : "rb"); 41 | if(!d->disk){ 42 | delete d; 43 | return false; 44 | } 45 | d->cylinder = 0; 46 | d->head = 0; 47 | d->sector = 1; 48 | d->write = write; 49 | 50 | drive[slot] = d; 51 | 52 | return true; 53 | } 54 | 55 | bool FDD::eject_disk(uint8_t slot){ 56 | if(slot>=MAX_FDD || !drive[slot]) 57 | return false; 58 | 59 | fclose(drive[slot]->disk); 60 | delete drive[slot]; 61 | drive[slot] = NULL; 62 | 63 | return true; 64 | } 65 | 66 | int32_t FDD::seek(uint8_t slot, uint8_t c, uint8_t h, uint8_t s){ 67 | int32_t dc, dh, ds, offset; 68 | 69 | if(!drive[slot] || !drive[slot]->disk) 70 | ERROR("not ready disk%d", slot); 71 | 72 | if(s < 1 || s > N_SpH) ERROR(""); 73 | if(h < 0 || h >= N_HpC) ERROR(""); 74 | if(c < 0) ERROR(""); 75 | 76 | msr.DRV_BSY |= 1<sector) * SIZE_SECTOR; 78 | dh = (h - drive[slot]->head) * SIZE_SECTOR * N_SpH; 79 | dc = (c - drive[slot]->cylinder) * SIZE_SECTOR * N_SpH * N_HpC; 80 | offset = dc+dh+ds; 81 | 82 | INFO(3, "seek : %d, ds : %d(%d->%d), dh : %d(%d->%d), dc : %d(%d->%d)" 83 | , offset, ds, drive[slot]->sector, s, dh, drive[slot]->head, h, dc, drive[slot]->cylinder, c); 84 | drive[slot]->cylinder = c; 85 | drive[slot]->head = h; 86 | drive[slot]->sector = s; 87 | drive[slot]->progress = 0; 88 | 89 | fseek(drive[slot]->disk, offset, SEEK_CUR); 90 | msr.DRV_BSY ^= 1<disk) 99 | ERROR("not ready disk%d", slot); 100 | 101 | if(!fread(&v, 1, 1, drive[slot]->disk)) 102 | v = 0; 103 | sync_position(slot); 104 | return v; 105 | } 106 | 107 | void FDD::write(uint8_t slot, uint8_t v){ 108 | if(!drive[slot] || !drive[slot]->disk) 109 | ERROR("not ready disk%d", slot); 110 | 111 | fwrite(&v, 1, 1, drive[slot]->disk); 112 | sync_position(slot); 113 | } 114 | 115 | void FDD::sync_position(uint8_t slot){ 116 | if(++drive[slot]->progress < 0x200) 117 | return; 118 | 119 | drive[slot]->progress = 0; 120 | drive[slot]->sector++; 121 | if(drive[slot]->sector > N_SpH){ 122 | drive[slot]->sector = 1; 123 | if(drive[slot]->head++) 124 | drive[slot]->cylinder++; 125 | } 126 | } 127 | 128 | uint8_t FDD::in8(uint16_t addr){ 129 | uint8_t v; 130 | switch(addr){ 131 | case 0x3f0: 132 | v = sra.raw; 133 | break; 134 | case 0x3f1: 135 | v = srb.raw; 136 | break; 137 | case 0x3f3: 138 | v = tdr.raw; 139 | break; 140 | case 0x3f4: 141 | v = msr.raw; 142 | break; 143 | case 0x3f5: 144 | v = read_datareg(); 145 | break; 146 | case 0x3f7: 147 | v = ccr.raw; 148 | break; 149 | } 150 | return v; 151 | } 152 | 153 | void FDD::out8(uint16_t addr, uint8_t v){ 154 | switch(addr){ 155 | case 0x3f2: 156 | dor.raw = v; 157 | break; 158 | case 0x3f3: 159 | tdr.raw = v; 160 | break; 161 | case 0x3f4: 162 | dsr.raw = v; 163 | break; 164 | case 0x3f5: 165 | enqueue(&data_q, v); 166 | break; 167 | case 0x3f7: 168 | dir.raw = v; 169 | break; 170 | } 171 | } 172 | 173 | void FDD::worker(void){ 174 | uint8_t mode; 175 | 176 | while(true){ 177 | while(data_q.queue.empty()) 178 | std::this_thread::sleep_for(std::chrono::milliseconds(10)); 179 | 180 | mode = dequeue(&data_q); 181 | if(!fddfuncs.count(mode)){ 182 | data = 0x80; 183 | continue; 184 | } 185 | 186 | msr.CMD_BSY = 1; 187 | (this->*fddfuncs[mode])(); 188 | msr.CMD_BSY = 0; 189 | } 190 | } 191 | 192 | void FDD::fdd_read_track(void){ 193 | uint8_t cmd[8]; 194 | uint8_t slot; 195 | 196 | msr.RQM = 1; 197 | msr.DIO = 0; 198 | 199 | for(int i=0; i<8; i++) 200 | cmd[i] = dequeue(&data_q); 201 | 202 | slot = cmd[0]&3; 203 | if(conf.EIS) 204 | seek(slot, cmd[1], cmd[2], 1); 205 | 206 | for(int i=0; icylinder); 215 | write_datareg(drive[slot]->head); 216 | write_datareg(drive[slot]->sector); 217 | write_datareg(cmd[4]); 218 | 219 | msr.RQM = 0; 220 | } 221 | 222 | void FDD::fdd_write_data(void){ 223 | uint8_t cmd[8]; 224 | uint8_t slot; 225 | 226 | msr.RQM = 1; 227 | msr.DIO = 1; 228 | 229 | for(int i=0; i<8; i++) 230 | cmd[i] = dequeue(&data_q); 231 | 232 | slot = cmd[0]&3; 233 | if(conf.EIS) 234 | seek(slot, cmd[1], cmd[2], cmd[3]); 235 | 236 | for(int i=0; icylinder); 245 | write_datareg(drive[slot]->head); 246 | write_datareg(drive[slot]->sector); 247 | write_datareg(cmd[4]); 248 | 249 | msr.RQM = 0; 250 | } 251 | 252 | void FDD::fdd_read_data(void){ 253 | uint8_t cmd[8]; 254 | uint8_t slot; 255 | 256 | msr.RQM = 1; 257 | msr.DIO = 0; 258 | 259 | for(int i=0; i<8; i++) 260 | cmd[i] = dequeue(&data_q); 261 | 262 | slot = cmd[0]&3; 263 | if(conf.EIS) 264 | seek(slot, cmd[1], cmd[2], cmd[3]); 265 | 266 | for(int i=0; icylinder); 275 | write_datareg(drive[slot]->head); 276 | write_datareg(drive[slot]->sector); 277 | write_datareg(cmd[4]); 278 | 279 | msr.RQM = 0; 280 | } 281 | 282 | void FDD::fdd_configure(void){ 283 | uint8_t cmd[3]; 284 | 285 | for(int i=0; i<3; i++) 286 | cmd[i] = dequeue(&data_q); 287 | conf.raw = cmd[1]; 288 | } 289 | 290 | uint8_t FDD::read_datareg(void){ 291 | uint8_t v; 292 | 293 | while(!sra.INT) 294 | std::this_thread::sleep_for(std::chrono::microseconds(50)); 295 | v = data; 296 | sra.INT = 0; 297 | 298 | return v; 299 | } 300 | 301 | void FDD::write_datareg(uint8_t v){ 302 | while(sra.INT) 303 | std::this_thread::sleep_for(std::chrono::microseconds(50)); 304 | data = v; 305 | sra.INT = 1; 306 | } 307 | 308 | void FDD::enqueue(QUEUE *q, uint8_t v){ 309 | while(q->max && q->queue.size() >= q->max) 310 | std::this_thread::sleep_for(std::chrono::microseconds(50)); 311 | q->mtx.lock(); 312 | q->queue.push(v); 313 | q->mtx.unlock(); 314 | } 315 | 316 | uint8_t FDD::dequeue(QUEUE *q){ 317 | uint8_t v; 318 | 319 | q->mtx.lock(); 320 | while(q->queue.empty()){ 321 | q->mtx.unlock(); 322 | std::this_thread::sleep_for(std::chrono::microseconds(50)); 323 | q->mtx.lock(); 324 | } 325 | 326 | v = q->queue.front(); 327 | q->queue.pop(); 328 | q->mtx.unlock(); 329 | 330 | return v; 331 | } 332 | -------------------------------------------------------------------------------- /device/keyboard.cpp: -------------------------------------------------------------------------------- 1 | #include "device/keyboard.hpp" 2 | 3 | uint8_t Keyboard::in8(uint16_t addr){ 4 | switch(addr){ 5 | case 0x60: return read_outbuf(); 6 | case 0x64: return kcsr.raw; 7 | } 8 | return -1; 9 | } 10 | 11 | void Keyboard::out8(uint16_t addr, uint8_t v){ 12 | switch(addr){ 13 | case 0x60: 14 | kcsr.F1 = 0; 15 | break; 16 | case 0x64: 17 | kcsr.F1 = 1; 18 | break; 19 | } 20 | command(v); 21 | } 22 | 23 | void Keyboard::command(uint8_t v){ 24 | if(!kcsr.ST6){ 25 | if(kcsr.F1){ 26 | switch(v){ 27 | case 0xa7: 28 | ccb->ME = 0; // enable 29 | return; 30 | case 0xa8: 31 | ccb->ME = 1; // diable 32 | return; 33 | case 0xad: 34 | ccb->KE = 0; // enable 35 | return; 36 | case 0xae: 37 | ccb->KE = 1; // diable 38 | return; 39 | default: 40 | if(v < 0x40){ 41 | write_outbuf(controller_ram[v%0x20]); 42 | return; 43 | } 44 | } 45 | } 46 | else{ 47 | } 48 | 49 | mode = v; 50 | kcsr.ST6 = 1; 51 | } 52 | else{ 53 | if(kcsr.F1){ 54 | } 55 | else{ 56 | switch(mode){ 57 | case 0xd1: 58 | swt_a20gate(v); 59 | break; 60 | case 0xd2: 61 | send_code(v); 62 | break; 63 | case 0xd3: 64 | mouse->send_code(v); 65 | break; 66 | case 0xd4: 67 | mouse->command(v); 68 | break; 69 | default: 70 | if(mode >= 0x40 && mode < 0x80) 71 | controller_ram[(mode-0x40)%0x20] = v; 72 | } 73 | } 74 | kcsr.ST6 = 0; 75 | } 76 | } 77 | 78 | void Keyboard::write_outbuf(uint8_t v){ 79 | while(kcsr.OBF); 80 | 81 | kcsr.OBF = 1; 82 | out_buf = v; 83 | if(ccb->KIE) 84 | intr = true; 85 | } 86 | 87 | uint8_t Keyboard::read_outbuf(void){ 88 | kcsr.OBF = 0; 89 | return out_buf; 90 | } 91 | 92 | void Keyboard::send_code(uint8_t scancode){ 93 | if(!ccb->KE) // enable 94 | write_outbuf(scancode); 95 | } 96 | 97 | void Keyboard::swt_a20gate(uint8_t v){ 98 | switch(v){ 99 | case 0xdd: 100 | mem->set_a20gate(false); 101 | break; 102 | case 0xdf: 103 | mem->set_a20gate(true); 104 | break; 105 | } 106 | } 107 | 108 | -------------------------------------------------------------------------------- /device/mouse.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "device/mouse.hpp" 3 | #include "device/keyboard.hpp" 4 | 5 | void Mouse::command(uint8_t v){ 6 | switch(v){ 7 | case 0xf4: 8 | while(keyboard->kcsr.OBF); // busy wait 9 | 10 | keyboard->kcsr.OBF = 1; 11 | keyboard->out_buf = 0xfa; 12 | if(keyboard->ccb->MIE) 13 | intr = true; 14 | 15 | enable = true; 16 | break; 17 | } 18 | } 19 | void Mouse::send_code(uint8_t code){ 20 | if(keyboard->ccb->ME || !enable) // disabled 21 | return; 22 | 23 | while(keyboard->kcsr.OBF) 24 | std::this_thread::sleep_for(std::chrono::microseconds(10)); 25 | 26 | keyboard->kcsr.OBF = 1; 27 | keyboard->out_buf = code; 28 | if(keyboard->ccb->MIE) 29 | intr = true; 30 | } 31 | 32 | -------------------------------------------------------------------------------- /device/pic.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "device/pic.hpp" 3 | 4 | PIC::PIC(PIC* master) { 5 | pic_m = master; 6 | for(int i=0; i>i)&1); i++); 18 | if(i == MAX_IRQ) 19 | return -1; 20 | INFO(4, "IRQ %d", !pic_m ? i : i+MAX_IRQ); 21 | 22 | if(!ic4.AEOI) isr |= 1<chk_m2s_pic(ic3.ID)) // slave 29 | ERROR(""); 30 | } 31 | 32 | iva = ic4.PM ? ic2.IVA_x86 << 3 : ic1.IVA_l + (ic2.IVA_h << 3); 33 | return iva + i; 34 | } 35 | 36 | bool PIC::chk_intreq(void){ 37 | int i; 38 | 39 | if(init_icn) 40 | return false; 41 | 42 | for(i=0; i>i)&1 && irq[i]->chk_intreq()); i++); 43 | if(i == MAX_IRQ) 44 | return false; 45 | if(isr && (1<= isr) 46 | return false; 47 | 48 | irr |= 1 << i; 49 | return true; 50 | } 51 | 52 | /*************************************************************************/ 53 | 54 | uint8_t PIC::in8(uint16_t addr){ 55 | // TODO 56 | switch(addr){ 57 | case 0x21: 58 | case 0xa1: 59 | return ~imr; 60 | } 61 | 62 | return 0; 63 | } 64 | 65 | void PIC::out8(uint16_t addr, uint8_t v){ 66 | switch(addr){ 67 | case 0x20: 68 | case 0xa0: 69 | set_command(v); 70 | break; 71 | case 0x21: 72 | case 0xa1: 73 | set_data(v); 74 | break; 75 | 76 | } 77 | } 78 | 79 | void PIC::set_command(uint8_t v){ 80 | if(init_icn){ 81 | ic1.raw = v; 82 | INFO(2, "ic1 : 0x%04x", v); 83 | init_icn = 1; 84 | } 85 | else{ 86 | OCW2 ocw2; 87 | 88 | ocw2.raw = v; 89 | if(ocw2.EOI){ 90 | if(ocw2.SL){ 91 | isr &= ~(1<>i)&1); i++); 96 | if(i 0){ 106 | switch(++init_icn){ 107 | case 2: 108 | ic2.raw = v; 109 | INFO(2, "ic2 : 0x%04x", v); 110 | if(ic1.SNGL) 111 | goto done; 112 | return; 113 | case 3: 114 | ic3.raw = v; 115 | INFO(2, "ic3 : 0x%04x", v); 116 | if(!ic1.IC4) 117 | goto done; 118 | return; 119 | case 4: 120 | ic4.raw = v; 121 | INFO(2, "ic4 : 0x%04x", v); 122 | default: 123 | done: init_icn = 0; 124 | for(int i=0; ichk_intreq(); 126 | } 127 | } 128 | else 129 | imr = ~v; 130 | } 131 | 132 | -------------------------------------------------------------------------------- /device/pit.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "device/pit.hpp" 4 | 5 | PIT::PIT(){ 6 | memset(timer, 0, sizeof(timer)); 7 | for(int i=0; i<3; i++) 8 | timer[i].count = timer[i].def = 0xffff; 9 | } 10 | 11 | PIT::~PIT(){ 12 | for(int i=0; i<3; i++) 13 | if(timer[i].th.joinable()){ 14 | timer[i].running = false; 15 | timer[i].th.join(); 16 | } 17 | } 18 | 19 | bool rl_fst; 20 | 21 | uint8_t PIT::in8(uint16_t addr){ 22 | uint8_t rgn = addr&0x3; 23 | 24 | switch(rgn){ 25 | case 0: 26 | case 1: 27 | case 2: 28 | switch(cwr.RL){ 29 | case 1: // LSB 30 | return timer[rgn].count>>8; 31 | case 2: // MSB 32 | return timer[rgn].count&0xff; 33 | case 3: 34 | if(!(rl_fst ^= true)) // LSB 35 | return timer[rgn].count>>8; 36 | else // MSB 37 | return timer[rgn].count&0xff; 38 | } 39 | default: 40 | return 0; 41 | } 42 | } 43 | 44 | void PIT::out8(uint16_t addr, uint8_t v){ 45 | uint8_t rgn = addr&0x3; 46 | 47 | switch(rgn){ 48 | case 0: 49 | case 1: 50 | case 2: 51 | //if(cwr.SC != rgn) 52 | // break; 53 | switch(cwr.RL){ 54 | case 1: // LSB 55 | timer[rgn].count = (timer[rgn].count&0xff00) + v; 56 | break; 57 | case 2: // MSB 58 | timer[rgn].count = (v<<8) + (timer[rgn].count&0xff); 59 | break; 60 | case 3: 61 | if(!(rl_fst ^= true)) // LSB 62 | timer[rgn].count = v; 63 | else // MSB 64 | timer[rgn].count = (v<<8) + (timer[rgn].count&0xff); 65 | break; 66 | } 67 | timer[rgn].def = timer[rgn].count; 68 | INFO(2, "timer[%d].def = 0x%04x", rgn, timer[rgn].def); 69 | break; 70 | case 3: 71 | cwr.raw = v; 72 | if(cwr.SC < 3){ 73 | timer[cwr.SC].mode = cwr.mode; 74 | switch(cwr.RL){ 75 | case 0: 76 | timer[cwr.SC].def = timer[cwr.SC].count; 77 | break; 78 | case 3: 79 | rl_fst = true; 80 | break; 81 | } 82 | } 83 | 84 | if(!timer[cwr.SC].th.joinable()){ 85 | timer[cwr.SC].running = true; 86 | timer[cwr.SC].th = std::thread(&PIT::counter, this, &timer[cwr.SC]); 87 | } 88 | 89 | break; 90 | } 91 | } 92 | 93 | /* 94 | bool PIT::chk_intreq(void){ 95 | if(cwr.BCD){ 96 | } 97 | else timer[0].count--; 98 | 99 | switch(cwr.mode){ 100 | // TODO 101 | case 2: 102 | if(timer[0].count==1){ 103 | timer[0].count = timer[0].def; 104 | return true; 105 | } 106 | } 107 | 108 | return false; 109 | } 110 | */ 111 | 112 | void PIT::counter(Timer *t){ 113 | while(t->running){ 114 | switch(t->mode){ 115 | case 2: 116 | std::this_thread::sleep_for(std::chrono::milliseconds(100*t->def/119318)); 117 | intr = true; 118 | break; 119 | default: 120 | std::this_thread::sleep_for(std::chrono::milliseconds(100)); 121 | } 122 | } 123 | } 124 | -------------------------------------------------------------------------------- /device/syscontrol.cpp: -------------------------------------------------------------------------------- 1 | #include "device/syscontrol.hpp" 2 | 3 | uint8_t SysControl::in8(uint16_t addr){ 4 | return mem->is_ena_a20gate() << 1; 5 | } 6 | 7 | void SysControl::out8(uint16_t addr, uint8_t v){ 8 | mem->set_a20gate((v>>1)&1); 9 | INFO(2, "set A20 gate : %d", mem->is_ena_a20gate()); 10 | } 11 | -------------------------------------------------------------------------------- /device/vga.cpp: -------------------------------------------------------------------------------- 1 | #include "device/vga.hpp" 2 | #define chk_regidx(n) do{ if(n>sizeof(regs))ERROR("register index out of bound", n); if(!regs[n])ERROR("not implemented"); }while(0); 3 | 4 | void VGA::get_windowsize(uint16_t *x, uint16_t *y){ 5 | crt.get_windowsize(x, y); 6 | } 7 | 8 | void VGA::rgb_image(uint8_t *buffer, uint32_t size){ 9 | gmode_t mode = gc.graphic_mode(); 10 | 11 | for(uint32_t i=0; i>8)&0xff; 21 | *(buffer++) = (rgb>>16)&0xff; 22 | } 23 | } 24 | 25 | uint8_t VGA::in8(uint16_t addr){ 26 | switch(addr){ 27 | case 0x3c2: 28 | return 0; 29 | case 0x3c3: 30 | return 0; 31 | case 0x3cc: 32 | return mor.raw; 33 | case 0x3ba: 34 | case 0x3da: 35 | return 0; 36 | } 37 | return -1; 38 | } 39 | 40 | void VGA::out8(uint16_t addr, uint8_t v){ 41 | switch(addr){ 42 | case 0x3c2: 43 | mor.raw = v; 44 | break; 45 | case 0x3c3: 46 | break; 47 | case 0x3ba: 48 | case 0x3da: 49 | break; 50 | } 51 | 52 | } 53 | 54 | uint8_t VGA::read8(uint32_t offset){ 55 | return mor.ER ? seq.read(offset) : 0; 56 | } 57 | 58 | void VGA::write8(uint32_t offset, uint8_t v){ 59 | static int count = 0; 60 | 61 | if(mor.ER){ 62 | seq.write(offset, v); 63 | if(!(count++ % 0x10)) 64 | refresh = true; 65 | } 66 | } 67 | 68 | uint8_t VGA::read_plane(uint8_t nplane, uint32_t offset){ 69 | if(nplane > 3 || offset > (1<<16)-1) 70 | ERROR("Out of Plane range"); 71 | return plane[nplane][offset]; 72 | } 73 | 74 | void VGA::write_plane(uint8_t nplane, uint32_t offset, uint8_t v){ 75 | if(nplane > 3 || offset > (1<<16)-1) 76 | ERROR("Out of Plane range"); 77 | plane[nplane][offset] = v; 78 | } 79 | 80 | /* Sequencer */ 81 | uint8_t VGA::Sequencer::read(uint32_t offset){ 82 | if(!mem_mr.EM) 83 | offset &= (1<<16)-1; 84 | 85 | return vga->gc.read(offset); 86 | } 87 | 88 | #define SEQ_WRITE_PLANE(n, o, v) if((map_mr.raw>>(n)) & 1) vga->gc.write(n, o ,v) 89 | void VGA::Sequencer::write(uint32_t offset, uint8_t v){ 90 | if(!mem_mr.EM) 91 | offset &= (1<<16)-1; 92 | 93 | if(mem_mr.C4){ 94 | SEQ_WRITE_PLANE(offset&3, offset&(~3), v); 95 | } 96 | else{ 97 | if(mem_mr.OE){ 98 | for(int i=0; i<4; i++) 99 | SEQ_WRITE_PLANE(i, offset, v); 100 | } 101 | else{ 102 | uint8_t nplane = offset&1; 103 | SEQ_WRITE_PLANE(nplane, offset, v); 104 | SEQ_WRITE_PLANE(nplane+2, offset, v); 105 | } 106 | } 107 | } 108 | 109 | uint8_t *VGA::Sequencer::get_font(uint8_t att){ 110 | uint8_t v; 111 | uint16_t font_ofst = 0; 112 | 113 | v = att&0x8 ? (cmsr.CMAM<<2) + cmsr.CMA : (cmsr.CMBM<<2) + cmsr.CMB; 114 | font_ofst = v&4 ? (v&(~4))*2 + 1 : v*2; 115 | 116 | if(!mem_mr.EM) 117 | font_ofst &= (1<<16)-1; 118 | 119 | return vga->plane[2] + font_ofst; 120 | } 121 | 122 | uint8_t VGA::Sequencer::in8(uint16_t addr){ 123 | switch(addr){ 124 | case 0x3c4: return sar.raw; 125 | case 0x3c5: return *regs[sar.INDX]; 126 | } 127 | return -1; 128 | } 129 | 130 | void VGA::Sequencer::out8(uint16_t addr, uint8_t v){ 131 | switch(addr){ 132 | case 0x3c4: 133 | chk_regidx(v); 134 | sar.raw = v; 135 | break; 136 | case 0x3c5: 137 | *regs[sar.INDX] = v; 138 | break; 139 | } 140 | } 141 | 142 | /* CRT */ 143 | void VGA::CRT::get_windowsize(uint16_t *x, uint16_t *y){ 144 | *x = 8 * hdeer.HDEE; 145 | *y = 8 * vdeer.VDEE; 146 | } 147 | 148 | uint8_t VGA::CRT::attr_index_text(uint32_t n){ 149 | uint8_t chr, att; 150 | uint8_t *font; 151 | uint8_t bits; 152 | uint16_t idx, x, y; 153 | 154 | x = n % (8*hdeer.HDEE); 155 | y = n / (8*hdeer.HDEE); 156 | 157 | idx = y/(mslr.MSL+1)*hdeer.HDEE + x/8; 158 | chr = vga->read_plane(0, idx*2); 159 | att = vga->read_plane(1, idx*2); 160 | 161 | font = vga->seq.get_font(att); 162 | bits = *(font + chr*0x10 + y%(mslr.MSL+1)); 163 | 164 | return (bits>>(x%8))&1 ? att&0x0f : (att&0xf0)>>4; 165 | } 166 | 167 | uint8_t VGA::CRT::in8(uint16_t addr){ 168 | switch(addr){ 169 | case 0x3b4: 170 | case 0x3d4: 171 | return crtcar.raw; 172 | case 0x3b5: 173 | case 0x3d5: 174 | return *regs[crtcar.INDX]; 175 | } 176 | return -1; 177 | } 178 | 179 | void VGA::CRT::out8(uint16_t addr, uint8_t v){ 180 | switch(addr){ 181 | case 0x3b4: 182 | case 0x3d4: 183 | chk_regidx(v); 184 | crtcar.raw = v; 185 | break; 186 | case 0x3b5: 187 | case 0x3d5: 188 | *regs[crtcar.INDX] = v; 189 | break; 190 | } 191 | } 192 | 193 | /* GraphicController */ 194 | uint8_t VGA::GraphicController::read(uint32_t offset){ 195 | if(!chk_offset(&offset)) 196 | return 0; 197 | 198 | switch(gmr.WM){ 199 | case 0: 200 | if(gmr.OE){ 201 | uint8_t nplane = (rmsr.MS&2) + (offset&1); 202 | return vga->read_plane(nplane, offset&(~1)); 203 | } 204 | else 205 | return vga->read_plane(rmsr.MS, offset); 206 | case 1: 207 | break; 208 | } 209 | 210 | return 0; 211 | } 212 | 213 | void VGA::GraphicController::write(uint8_t nplane, uint32_t offset, uint8_t v){ 214 | if(!chk_offset(&offset)) 215 | return; 216 | 217 | switch(gmr.WM){ 218 | case 0: 219 | if(gmr.OE) 220 | offset &= ~1; 221 | vga->write_plane(nplane, offset, v); 222 | break; 223 | case 1: 224 | break; 225 | case 2: 226 | break; 227 | case 3: 228 | break; 229 | } 230 | INFO(4, "plane[%d][0x%x] = 0x%02x", nplane, offset, v); 231 | } 232 | 233 | bool VGA::GraphicController::chk_offset(uint32_t *offset){ 234 | uint32_t base, size; 235 | bool valid; 236 | 237 | switch(mr.MM){ 238 | case 0: 239 | base = 0x00000; size = 0x20000; 240 | break; 241 | case 1: 242 | base = 0x00000; size = 0x10000; 243 | break; 244 | case 2: 245 | base = 0x10000; size = 0x08000; 246 | break; 247 | case 3: 248 | base = 0x18000; size = 0x08000; 249 | break; 250 | } 251 | 252 | valid = (*offset >= base && *offset < base+size); 253 | *offset -= base; 254 | return valid; 255 | } 256 | 257 | gmode_t VGA::GraphicController::graphic_mode(void){ 258 | if(mr.GM){ 259 | if(gmr._256CM) 260 | return MODE_GRAPHIC256; 261 | return MODE_GRAPHIC; 262 | } 263 | return MODE_TEXT; 264 | } 265 | 266 | uint8_t VGA::GraphicController::attr_index_graphic(uint32_t n){ 267 | return vga->read_plane(2, n); 268 | } 269 | 270 | uint8_t VGA::GraphicController::in8(uint16_t addr){ 271 | switch(addr){ 272 | case 0x3ce: return gcar.raw; 273 | case 0x3cf: return *regs[gcar.INDX]; 274 | } 275 | return -1; 276 | } 277 | 278 | void VGA::GraphicController::out8(uint16_t addr, uint8_t v){ 279 | switch(addr){ 280 | case 0x3ce: 281 | chk_regidx(v); 282 | gcar.raw = v; 283 | break; 284 | case 0x3cf: 285 | *regs[gcar.INDX] = v; 286 | break; 287 | } 288 | } 289 | 290 | /* Attribute */ 291 | uint8_t VGA::Attribute::dac_index(uint8_t index){ 292 | uint8_t dac_idx; 293 | 294 | union { 295 | uint8_t raw; 296 | struct { 297 | uint8_t low : 4; 298 | uint8_t high : 2; 299 | }; 300 | } ip_data; 301 | ip_data.raw = ipr[index&0xf].raw; 302 | 303 | if(amcr.GAM){ 304 | dac_idx = ip_data.low; 305 | dac_idx += (amcr.P54S ? csr.SC45 : ip_data.high) << 4; 306 | dac_idx += csr.SC67 << 6; 307 | } 308 | else 309 | dac_idx = ip_data.low; 310 | 311 | return dac_idx; 312 | } 313 | 314 | uint8_t VGA::Attribute::in8(uint16_t addr){ 315 | switch(addr){ 316 | case 0x3c0: return acar.raw; 317 | case 0x3c1: return *regs[acar.INDX]; 318 | } 319 | return -1; 320 | } 321 | 322 | void VGA::Attribute::out8(uint16_t addr, uint8_t v){ 323 | switch(addr){ 324 | case 0x3c0: 325 | chk_regidx(v); 326 | acar.raw = v; 327 | break; 328 | case 0x3c1: 329 | *regs[acar.INDX] = v; 330 | break; 331 | } 332 | } 333 | 334 | /* DAC */ 335 | uint32_t VGA::DAC::translate_rgb(uint8_t index){ 336 | uint32_t rgb; 337 | 338 | // 6bit -> 8bit 339 | rgb = clut[index].R<<0x02; 340 | rgb += clut[index].G<<0x0a; 341 | rgb += clut[index].B<<0x12; 342 | 343 | return rgb; 344 | } 345 | 346 | uint8_t VGA::DAC::in8(uint16_t addr){ 347 | uint8_t v; 348 | 349 | switch(addr){ 350 | case 0x3c6: return pelmr.raw; 351 | case 0x3c7: return dacsr.raw; 352 | case 0x3c9: 353 | v = clut[r_par.index].raw[progress++]; 354 | if(progress==3){ 355 | progress = 0; 356 | r_par.index++; 357 | } 358 | return v; 359 | } 360 | return -1; 361 | } 362 | 363 | void VGA::DAC::out8(uint16_t addr, uint8_t v){ 364 | switch(addr){ 365 | case 0x3c7: 366 | if(v>0xff) ERROR(""); 367 | r_par.raw = v; 368 | progress = 0; 369 | break; 370 | case 0x3c8: 371 | if(v>0xff) ERROR(""); 372 | w_par.raw = v; 373 | progress = 0; 374 | break; 375 | case 0x3c9: 376 | clut[w_par.index].raw[progress++] = v; 377 | if(progress==3){ 378 | progress = 0; 379 | w_par.index++; 380 | } 381 | break; 382 | } 383 | } 384 | -------------------------------------------------------------------------------- /emulator/Makefile: -------------------------------------------------------------------------------- 1 | TARGET := emulator.a 2 | 3 | SRCS := emulator.cpp access.cpp interrupt.cpp ui.cpp 4 | OBJS := $(SRCS:.cpp=.o) 5 | DEPS := $(SRCS:.cpp=.d) 6 | 7 | CXXFLAGS := -Wall -MMD -std=c++11 -I../include $(DEBUG) 8 | 9 | .PHONY: all 10 | all: $(TARGET) 11 | 12 | -include $(DEPS) 13 | 14 | $(TARGET): $(OBJS) 15 | $(AR) rcs $@ $^ 16 | 17 | .PHONY: clean 18 | clean: 19 | $(RM) $(DEPS) $(OBJS) $(TARGET) 20 | -------------------------------------------------------------------------------- /emulator/access.cpp: -------------------------------------------------------------------------------- 1 | #include "emulator/access.hpp" 2 | #include "emulator/exception.hpp" 3 | #include "emulator/descriptor.hpp" 4 | 5 | void DataAccess::set_segment(sgreg_t reg, uint16_t sel){ 6 | SGRegister sg; 7 | SGRegCache *cache = &sg.cache; 8 | 9 | get_sgreg(reg, &sg); 10 | sg.raw = sel; 11 | 12 | if(is_protected()){ 13 | uint32_t dt_base; 14 | uint16_t dt_limit, dt_index; 15 | SegDesc gdt; 16 | const char* sgreg_name[] = { "ES", "CS", "SS", "DS", "FS", "GS" }; 17 | 18 | dt_index = sg.index << 3; 19 | 20 | dt_base = get_dtreg_base(sg.TI ? LDTR : GDTR); 21 | dt_limit = get_dtreg_limit(sg.TI ? LDTR : GDTR); 22 | 23 | EXCEPTION(EXP_GP, (reg == CS || reg == SS) && !dt_index); 24 | EXCEPTION(EXP_GP, dt_index > dt_limit); 25 | 26 | read_data(&gdt, dt_base + dt_index, sizeof(SegDesc)); 27 | 28 | cache->base = (gdt.base_h << 24) + (gdt.base_m << 16) + gdt.base_l; 29 | cache->limit = (gdt.limit_h << 16) + gdt.limit_l; 30 | 31 | *(uint8_t*)&cache->flags.type = *(uint8_t*)&gdt.type; 32 | cache->flags.AVL = gdt.AVL; 33 | cache->flags.DB = gdt.DB; 34 | cache->flags.G = gdt.G; 35 | 36 | INFO(3, "%s : dt_base=0x%04x, dt_limit=0x%02x, dt_index=0x%02x {base=0x%08x, limit=0x%08x, flags=0x%04x}" 37 | , sgreg_name[reg], dt_base, dt_limit, dt_index 38 | , cache->base, cache->limit<<(cache->flags.G ? 12 : 0), cache->flags.raw); 39 | 40 | } 41 | else 42 | cache->base = (uint32_t)sel << 4; 43 | 44 | set_sgreg(reg, &sg); 45 | } 46 | 47 | inline uint16_t DataAccess::get_segment(sgreg_t reg){ 48 | SGRegister sg; 49 | 50 | get_sgreg(reg, &sg); 51 | return sg.raw; 52 | } 53 | 54 | uint32_t DataAccess::trans_v2p(acsmode_t mode, sgreg_t seg, uint32_t vaddr){ 55 | uint32_t laddr, paddr; 56 | 57 | laddr = trans_v2l(mode, seg, vaddr); 58 | 59 | if(is_ena_paging()){ 60 | uint32_t vpn; 61 | uint16_t offset; 62 | uint8_t cpl; 63 | PTE pte; 64 | 65 | EXCEPTION(EXP_GP, !is_protected()); 66 | 67 | cpl = get_segment(CS) & 3; 68 | vpn = laddr >> 12; 69 | offset = laddr & ((1<<12)-1); 70 | 71 | if(!search_tlb(vpn, &pte)){ 72 | uint32_t pdir_base, ptbl_base; 73 | uint16_t pdir_index, ptbl_index; 74 | PDE pde; 75 | 76 | pdir_index = laddr >> 22; 77 | ptbl_index = (laddr >> 12) & ((1<<10)-1); 78 | 79 | pdir_base = get_pdir_base() << 12; 80 | read_data(&pde, pdir_base + pdir_index*sizeof(PDE), sizeof(PDE)); 81 | EXCEPTION_WITH(EXP_PF, !pde.P, set_crn(2, laddr)); 82 | EXCEPTION_WITH(EXP_PF, !pde.RW && mode == MODE_WRITE, set_crn(2, laddr)); 83 | EXCEPTION_WITH(EXP_PF, !pde.US && cpl>2, set_crn(2, laddr)); 84 | 85 | ptbl_base = pde.ptbl_base << 12; 86 | read_data(&pte, ptbl_base + ptbl_index*sizeof(PTE), sizeof(PTE)); 87 | cache_tlb(vpn, pte); 88 | 89 | INFO(3, "Cache TLB : pdir_base=0x%04x, ptbl_base=0x%04x {vpn=0x%04x, pfn=0x%04x}" 90 | , pdir_base, ptbl_base, vpn, pte.page_base); 91 | } 92 | 93 | EXCEPTION_WITH(EXP_PF, !pte.P, set_crn(2, laddr)); 94 | EXCEPTION_WITH(EXP_PF, !pte.RW && mode == MODE_WRITE, set_crn(2, laddr)); 95 | EXCEPTION_WITH(EXP_PF, !pte.US && cpl>2, set_crn(2, laddr)); 96 | 97 | paddr = (pte.page_base<<12) + offset; 98 | } 99 | else 100 | paddr = laddr; 101 | 102 | if(!is_ena_a20gate()) 103 | paddr &= (1<<20)-1; 104 | 105 | return paddr; 106 | } 107 | 108 | uint32_t DataAccess::trans_v2l(acsmode_t mode, sgreg_t seg, uint32_t vaddr){ 109 | uint32_t laddr; 110 | uint8_t CPL; 111 | SGRegister sg; 112 | 113 | CPL = get_segment(CS) & 3; 114 | get_sgreg(seg, &sg); 115 | 116 | if(is_protected()){ 117 | uint32_t base, limit; 118 | SGRegCache cache = sg.cache; 119 | 120 | base = cache.base; 121 | limit = cache.limit; 122 | if(cache.flags.G) limit <<= 12; 123 | 124 | if(cache.flags.type.segc){ 125 | EXCEPTION(EXP_GP, mode == MODE_WRITE); 126 | EXCEPTION(EXP_GP, mode == MODE_READ && !cache.flags.type.code.r); 127 | EXCEPTION(EXP_GP, CPL > cache.flags.DPL && !(mode == MODE_EXEC && cache.flags.type.code.cnf)); 128 | } 129 | else{ 130 | EXCEPTION(EXP_GP, mode == MODE_EXEC); 131 | EXCEPTION(EXP_GP, mode == MODE_WRITE && !cache.flags.type.data.w); 132 | EXCEPTION(EXP_GP, CPL > cache.flags.DPL); 133 | 134 | if(cache.flags.type.data.exd) 135 | base -= limit; 136 | } 137 | EXCEPTION(EXP_GP, vaddr > limit); 138 | 139 | laddr = base + vaddr; 140 | INFO(6, "base=0x%04x, limit=0x%02x, laddr=0x%02x", base, limit, laddr); 141 | } 142 | else{ 143 | laddr = (sg.raw << 4) + vaddr; 144 | INFO(6, "base=0x%04x, laddr=0x%02x", sg.raw<<4, laddr); 145 | } 146 | 147 | return laddr; 148 | } 149 | 150 | bool DataAccess::search_tlb(uint32_t vpn, PTE *pte){ 151 | if(vpn+1 > tlb.size() || !tlb[vpn]) 152 | return false; 153 | 154 | ASSERT(pte); 155 | *pte = *tlb[vpn]; 156 | 157 | return true; 158 | } 159 | 160 | void DataAccess::cache_tlb(uint32_t vpn, PTE pte){ 161 | if(vpn+1 > tlb.size()) 162 | tlb.resize(vpn+1, NULL); 163 | 164 | tlb[vpn] = new PTE; 165 | *tlb[vpn] = pte; 166 | } 167 | 168 | void DataAccess::push32(uint32_t value){ 169 | uint32_t esp; 170 | 171 | update_gpreg(ESP, -4); 172 | esp = get_gpreg(ESP); 173 | write_mem32_seg(SS, esp, value); 174 | } 175 | 176 | uint32_t DataAccess::pop32(void){ 177 | uint32_t esp, value; 178 | 179 | esp = get_gpreg(ESP); 180 | value = read_mem32_seg(SS, esp); 181 | update_gpreg(ESP, 4); 182 | 183 | return value; 184 | } 185 | 186 | void DataAccess::push16(uint16_t value){ 187 | uint16_t sp; 188 | 189 | update_gpreg(SP, -2); 190 | sp = get_gpreg(SP); 191 | write_mem16_seg(SS, sp, value); 192 | } 193 | 194 | uint16_t DataAccess::pop16(void){ 195 | uint16_t sp, value; 196 | 197 | sp = get_gpreg(SP); 198 | value = read_mem16_seg(SS, sp); 199 | update_gpreg(SP, 2); 200 | 201 | return value; 202 | } 203 | 204 | uint32_t DataAccess::read_mem32_seg(sgreg_t seg, uint32_t addr){ 205 | uint32_t paddr, io_base; 206 | 207 | paddr = trans_v2p(MODE_READ, seg, addr); 208 | return (io_base = chk_memio(paddr)) ? read_memio32(io_base, paddr-io_base) : read_mem32(paddr); 209 | } 210 | 211 | uint16_t DataAccess::read_mem16_seg(sgreg_t seg, uint32_t addr) { 212 | uint32_t paddr, io_base; 213 | 214 | paddr = trans_v2p(MODE_READ, seg, addr); 215 | return (io_base = chk_memio(paddr)) ? read_memio16(io_base, paddr-io_base) : read_mem16(paddr); 216 | } 217 | 218 | uint8_t DataAccess::read_mem8_seg(sgreg_t seg, uint32_t addr){ 219 | uint32_t paddr, io_base; 220 | 221 | paddr = trans_v2p(MODE_READ, seg, addr); 222 | return (io_base = chk_memio(paddr)) ? read_memio8(io_base, paddr-io_base) : read_mem8(paddr); 223 | } 224 | 225 | void DataAccess::write_mem32_seg(sgreg_t seg, uint32_t addr, uint32_t v){ 226 | uint32_t paddr, io_base; 227 | 228 | paddr = trans_v2p(MODE_WRITE, seg, addr); 229 | if((io_base = chk_memio(paddr))) 230 | write_memio32(io_base, paddr-io_base, v); 231 | else 232 | write_mem32(paddr, v); 233 | } 234 | 235 | void DataAccess::write_mem16_seg(sgreg_t seg, uint32_t addr, uint16_t v){ 236 | uint32_t paddr, io_base; 237 | 238 | paddr = trans_v2p(MODE_WRITE, seg, addr); 239 | if((io_base = chk_memio(paddr))) 240 | write_memio16(io_base, paddr-io_base, v); 241 | else 242 | write_mem16(paddr, v); 243 | } 244 | 245 | void DataAccess::write_mem8_seg(sgreg_t seg, uint32_t addr, uint8_t v){ 246 | uint32_t paddr, io_base; 247 | 248 | paddr = trans_v2p(MODE_WRITE, seg, addr); 249 | if((io_base = chk_memio(paddr))) 250 | write_memio8(io_base, paddr-io_base, v); 251 | else 252 | write_mem8(paddr, v); 253 | } 254 | 255 | -------------------------------------------------------------------------------- /emulator/emulator.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "emulator/emulator.hpp" 3 | #include "device/devices.hpp" 4 | 5 | Emulator::Emulator(EmuSetting set) : Hardware(set.mem_size) { 6 | PIC *pic_m, *pic_s; 7 | PIT *pit; 8 | SysControl *syscon; 9 | COM *com; 10 | VGA *vga; 11 | Keyboard *kb; 12 | 13 | pic_m = new PIC(); 14 | pic_s = new PIC(pic_m); 15 | set_pic(pic_m, true); 16 | set_pic(pic_s, false); 17 | 18 | ui = new UI(this, set.uiset); 19 | pit = new PIT(); 20 | fdd = new FDD(); 21 | syscon = new SysControl(this); 22 | com = new COM(); 23 | vga = ui->get_vga(); 24 | kb = ui->get_keyboard(); 25 | 26 | pic_m->set_irq(0, pit); 27 | pic_m->set_irq(1, kb); 28 | pic_m->set_irq(2, pic_s); 29 | pic_m->set_irq(6, fdd); 30 | pic_s->set_irq(4, kb->get_mouse()); 31 | 32 | set_portio(0x020, 2, pic_m); // 0x20, 0x21 33 | set_portio(0x040, 4, pit); // 0x40, 0x41, 0x42, 0x43 34 | set_portio(0x060, 1, kb); // 0x60 35 | set_portio(0x064, 1, kb); // 0x64 36 | set_portio(0x0a0, 2, pic_s); // 0xa0, 0xa1 37 | set_portio(0x092, 1, syscon); // 0x92 38 | set_portio(0x3b4, 2, vga->get_crt()); // 0x3b4, 0x3b5 39 | set_portio(0x3ba, 1, vga); // 0x3ba 40 | set_portio(0x3c0, 2, vga->get_attr()); // 0x3c0, 0x3c1 41 | set_portio(0x3c2, 2, vga); // 0x3c2, 0x3c3 42 | set_portio(0x3c4, 2, vga->get_seq()); // 0x3c4, 0x3c5 43 | set_portio(0x3c6, 4, vga->get_dac()); // 0x3c6, 0x3c7, 0x3c8, 0x3c9 44 | set_portio(0x3cc, 1, vga); // 0x3cc 45 | set_portio(0x3ce, 2, vga->get_gc()); // 0x3ce, 0x3cf 46 | set_portio(0x3d4, 2, vga->get_crt()); // 0x3d4, 0x3d5 47 | set_portio(0x3da, 1, vga); // 0x3da 48 | set_portio(0x3f0, 8, fdd); // 0x3f0, 0x3f1, 0x3f2, 0x3f3, 0x3f4, 0x3f5, 0x3f7 49 | set_portio(0x3f8, 1, com); // 0x3f8 50 | set_memio(0xa0000, 0x20000, vga); 51 | } 52 | 53 | void Emulator::load_binary(const char* fname, uint32_t addr, uint32_t offset, size_t size){ 54 | FILE *fp; 55 | uint8_t *buf; 56 | 57 | fp = fopen(fname, "rb"); 58 | if(!fp) 59 | return; 60 | 61 | if((int32_t)size < 0){ 62 | fseek(fp, 0, SEEK_END); 63 | size = ftell(fp); 64 | } 65 | 66 | buf = new uint8_t[size]; 67 | fseek(fp, offset, SEEK_SET); 68 | fread(buf, 1, size, fp); 69 | fclose(fp); 70 | 71 | write_data(addr, buf, size); 72 | 73 | delete[] buf; 74 | } 75 | -------------------------------------------------------------------------------- /emulator/interrupt.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "emulator/interrupt.hpp" 3 | #include "emulator/exception.hpp" 4 | #include "emulator/descriptor.hpp" 5 | 6 | void Interrupt::hundle_interrupt(void){ 7 | std::pair intr; 8 | uint8_t n; 9 | uint16_t cs; 10 | bool hard; 11 | 12 | if(intr_q.empty()) 13 | return; 14 | 15 | intr = intr_q.front(); 16 | intr_q.pop(); 17 | n = intr.first; 18 | hard = intr.second; 19 | 20 | if(is_protected()){ 21 | IntGateDesc idt; 22 | uint32_t idt_base; 23 | uint16_t idt_limit, idt_offset; 24 | uint8_t CPL, RPL; 25 | 26 | CPL = get_segment(CS) & 3; 27 | 28 | idt_base = get_dtreg_base(IDTR); 29 | idt_limit = get_dtreg_limit(IDTR); 30 | idt_offset = n<<3; 31 | 32 | EXCEPTION(EXP_GP, idt_offset > idt_limit); 33 | 34 | read_data(&idt, idt_base + idt_offset, sizeof(IntGateDesc)); 35 | RPL = ((SGRegister*)&(idt.seg_sel))->RPL; 36 | 37 | INFO(4, "int 0x%02x [CPL : %d, DPL : %d RPL : %d] (EIP : 0x%04x, CS : 0x%04x)" 38 | , n, CPL, idt.DPL, RPL, (idt.offset_h << 16) + idt.offset_l, idt.seg_sel); 39 | 40 | EXCEPTION(EXP_NP, !idt.P); 41 | EXCEPTION(EXP_GP, CPL < RPL); 42 | EXCEPTION(EXP_GP, !hard && CPL > idt.DPL); 43 | 44 | cs = get_segment(CS); 45 | set_segment(CS, idt.seg_sel); 46 | save_regs(CPL ^ RPL, cs); 47 | set_eip((idt.offset_h << 16) + idt.offset_l); 48 | 49 | if(idt.type == TYPE_INTERRUPT) 50 | set_interrupt(false); 51 | } 52 | else{ 53 | uint32_t idt_base; 54 | uint16_t idt_limit, idt_offset; 55 | IVT ivt; 56 | 57 | idt_base = get_dtreg_base(IDTR); 58 | idt_limit = get_dtreg_limit(IDTR); 59 | idt_offset = n<<2; 60 | 61 | EXCEPTION(EXP_GP, idt_offset > idt_limit); 62 | ivt.raw = read_mem32(idt_base + idt_offset); 63 | 64 | cs = get_segment(CS); 65 | set_segment(CS, ivt.segment); 66 | save_regs(false, cs); 67 | set_ip(ivt.offset); 68 | 69 | //set_interrupt(false); 70 | INFO(4, "int 0x%02x (IP : 0x%04x, CS : 0x%04x)", n, ivt.offset, ivt.segment); 71 | } 72 | } 73 | 74 | bool Interrupt::chk_irq(void){ 75 | int8_t n_intr; 76 | 77 | if(!is_interrupt()) 78 | return false; 79 | if(!pic_m || !pic_m->chk_intreq()) 80 | return false; 81 | 82 | n_intr = pic_m->get_nintr(); 83 | if(n_intr < 0) 84 | n_intr = pic_s->get_nintr(); 85 | queue_interrupt(n_intr, true); 86 | return true; 87 | } 88 | 89 | void Interrupt::save_regs(bool chpl, uint16_t cs){ 90 | if(is_protected()){ 91 | if(chpl){ 92 | uint32_t base, limit, esp; 93 | uint16_t ss; 94 | TSS tss; 95 | 96 | base = get_dtreg_base(TR); 97 | limit = get_dtreg_limit(TR); 98 | EXCEPTION(EXP_TS, limit < sizeof(TSS)-1); 99 | 100 | read_data(&tss, base, sizeof(TSS)); 101 | 102 | ss = get_segment(SS); 103 | esp = get_gpreg(ESP); 104 | set_segment(SS, tss.ss0); 105 | set_gpreg(ESP, tss.esp0); 106 | 107 | INFO(4, "save_regs (ESP : 0x%08x->0x%08x, SS : 0x%04x->0x%04x)", esp, tss.esp0, ss, tss.ss0); 108 | push32(ss); 109 | push32(esp); 110 | } 111 | push32(get_eflags()); 112 | push32(cs); 113 | push32(get_eip()); 114 | } 115 | else{ 116 | push16(get_flags()); 117 | push16(cs); 118 | push16(get_ip()); 119 | } 120 | } 121 | 122 | -------------------------------------------------------------------------------- /emulator/ui.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "emulator/ui.hpp" 4 | 5 | UI::UI(Memory *m, UISetting s){ 6 | std::thread main_th; 7 | 8 | vga = new VGA(); 9 | keyboard = new Keyboard(m); 10 | 11 | set = s; 12 | working = true; 13 | capture = false; 14 | 15 | size_x = 320; 16 | size_y = 200; 17 | image = new uint8_t[size_x*size_y*3]; 18 | 19 | X = size_x/2; 20 | Y = size_y/2; 21 | click[0] = click[1] = false; 22 | 23 | glfwInit(); 24 | if(set.enable){ 25 | main_th = std::thread(&UI::ui_main, this); 26 | main_th.detach(); 27 | } 28 | } 29 | 30 | UI::~UI(void){ 31 | glfwTerminate(); 32 | delete[] image; 33 | delete vga; 34 | delete keyboard; 35 | } 36 | 37 | 38 | void UI::ui_main(void){ 39 | GLFWwindow* window; 40 | GLuint texID; 41 | 42 | window = glfwCreateWindow(size_x, size_y, "x86emu", set.full ? glfwGetPrimaryMonitor() : NULL, NULL); 43 | 44 | glfwSetWindowUserPointer(window, this); 45 | glfwMakeContextCurrent(window); 46 | 47 | glfwSetKeyCallback(window, keyboard_callback); 48 | glfwSetMouseButtonCallback(window, mouse_callback); 49 | glfwSetCursorPosCallback(window, cursorpos_callback); 50 | glfwSetWindowSizeCallback(window, window_size_callback); 51 | //glfwSetCursorEnterCallback(window, cursorenter_callback); 52 | 53 | glfwSetWindowAspectRatio(window, size_x, size_y); 54 | glOrtho(0, size_x, 0, size_y, -1, 1); 55 | 56 | glGenTextures(1, &texID); 57 | glBindTexture(GL_TEXTURE_2D, texID); 58 | 59 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 60 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); 61 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP); 62 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP); 63 | 64 | glEnable(GL_TEXTURE_2D); 65 | glEnableClientState(GL_VERTEX_ARRAY); 66 | glEnableClientState(GL_TEXTURE_COORD_ARRAY); 67 | 68 | GLfloat vtx[] = {0, 0, (float)size_x, 0, (float)size_x, (float)size_y, 0, (float)size_y}; 69 | const GLfloat texuv[] = {0, 1, 1, 1, 1, 0, 0, 0}; 70 | while (!glfwWindowShouldClose(window)) { 71 | std::this_thread::sleep_for(std::chrono::milliseconds(40)); 72 | glfwPollEvents(); 73 | 74 | glClearColor(0.5f, 0.5f, 0.5f, 0.0f); 75 | glClear(GL_COLOR_BUFFER_BIT); 76 | 77 | if(vga->need_refresh()){ 78 | uint16_t x, y; 79 | 80 | vga->get_windowsize(&x, &y); 81 | if(x && y && ((size_x^x) || (size_y^y))){ 82 | printf("x : %d, y : %d\n", x, y); 83 | size_x = vtx[2] = vtx[4] = x; 84 | size_y = vtx[5] = vtx[7] = y; 85 | 86 | glfwSetWindowSize(window, x, y); 87 | glfwSetWindowAspectRatio(window, x, y); 88 | glOrtho(0, x, 0, y, -1, 1); 89 | 90 | delete[] image; 91 | image = new uint8_t[x*y*3]; 92 | } 93 | 94 | vga->rgb_image(image, x*y); 95 | glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, size_x, size_y, 0, GL_RGB, GL_UNSIGNED_BYTE, image); 96 | 97 | glVertexPointer(2, GL_FLOAT, 0, vtx); 98 | glTexCoordPointer(2, GL_FLOAT, 0, texuv); 99 | } 100 | glDrawArrays(GL_QUADS, 0, 4); 101 | 102 | glfwSwapBuffers(window); 103 | } 104 | 105 | glDisableClientState(GL_TEXTURE_COORD_ARRAY); 106 | glDisableClientState(GL_VERTEX_ARRAY); 107 | glDisable(GL_TEXTURE_2D); 108 | 109 | glfwDestroyWindow(window); 110 | working = false; 111 | } 112 | 113 | void UI::keyboard_callback(GLFWwindow *window, int key, int scancode, int action, int mods){ 114 | UI *ui = static_cast(glfwGetWindowUserPointer(window)); 115 | Keyboard *kb = ui->keyboard; 116 | 117 | if(!ui->capture) 118 | return; 119 | 120 | DEBUG_MSG(1, "key : 0x%02x, scancode : 0x%02x, action : %d, mods : %d\n", key, scancode, action, mods); 121 | switch(key){ 122 | case 0x159: // right CTRL 123 | ui->capture = false; 124 | glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_NORMAL); 125 | return; 126 | } 127 | 128 | switch(action){ 129 | case GLFW_RELEASE: 130 | kb->send_code(scancode - (ui->set.vm ? 8 : 0) + 0x80); 131 | break; 132 | case GLFW_PRESS: 133 | case GLFW_REPEAT: 134 | kb->send_code(scancode - (ui->set.vm ? 8 : 0)); 135 | break; 136 | } 137 | } 138 | 139 | void UI::mouse_callback(GLFWwindow *window, int button, int action, int mods){ 140 | UI *ui = static_cast(glfwGetWindowUserPointer(window)); 141 | Mouse *mouse = ui->keyboard->get_mouse(); 142 | 143 | if(ui->capture){ 144 | ui->click[button%2] = action; 145 | mouse->send_code((1<<3) + (ui->click[1]<<1) + ui->click[0]); 146 | mouse->send_code(0); 147 | mouse->send_code(0); 148 | 149 | DEBUG_MSG(1, "[%02x %02x %02x] button : %d, action : %d, mods : %d\n" 150 | , (1<<3) + (ui->click[1]<<1) + ui->click[0], 0 ,0, button, action, mods); 151 | } 152 | else{ 153 | ui->capture = true; 154 | glfwSetInputMode(window, GLFW_CURSOR, !ui->set.vm ? GLFW_CURSOR_DISABLED : GLFW_CURSOR_HIDDEN); 155 | MSG("To cancel the input capture, press the right control key.\n"); 156 | } 157 | } 158 | 159 | void UI::cursorpos_callback(GLFWwindow *window, double xpos, double ypos){ 160 | UI *ui = static_cast(glfwGetWindowUserPointer(window)); 161 | Mouse *mouse = ui->keyboard->get_mouse(); 162 | int32_t _xpos = xpos, _ypos = ypos; 163 | bool sx, sy; 164 | static int count = 0; 165 | 166 | if(!ui->capture || count++ % 6) 167 | return; 168 | 169 | sx = _xpos < ui->X; 170 | sy = _ypos > ui->Y; 171 | 172 | mouse->send_code((sy<<5) + (sx<<4) + (1<<3) + (ui->click[1]<<1) + ui->click[0]); 173 | std::this_thread::sleep_for(std::chrono::microseconds(100)); 174 | mouse->send_code(_xpos-ui->X); 175 | std::this_thread::sleep_for(std::chrono::microseconds(100)); 176 | mouse->send_code(ui->Y-_ypos); 177 | 178 | DEBUG_MSG(1, "[%02x %02x %02x] _xpos : %d, _ypos : %d\n" 179 | , (sy<<5) + (sx<<4) + (1<<3) + (ui->click[1]<<1) + ui->click[0] 180 | , (uint8_t)(_xpos-ui->X), (uint8_t)(ui->Y-_ypos), _xpos, _ypos); 181 | ui->X = _xpos; 182 | ui->Y = _ypos; 183 | } 184 | 185 | void UI::window_size_callback(GLFWwindow* window, int width, int height){ 186 | DEBUG_MSG(1, "width : %d, height : %d\n", width, height); 187 | 188 | glViewport(0, 0, width, height); 189 | } 190 | 191 | /* 192 | void UI::cursorenter_callback(GLFWwindow *window, int entered){ 193 | } 194 | */ 195 | -------------------------------------------------------------------------------- /hardware/Makefile: -------------------------------------------------------------------------------- 1 | TARGET := hardware.a 2 | 3 | SRCS := processor.cpp memory.cpp eflags.cpp io.cpp 4 | OBJS := $(SRCS:.cpp=.o) 5 | DEPS := $(SRCS:.cpp=.d) 6 | 7 | CXXFLAGS := -Wall -MMD -std=c++11 -I../include $(DEBUG) 8 | 9 | .PHONY: all 10 | all: $(TARGET) 11 | 12 | -include $(DEPS) 13 | 14 | $(TARGET): $(OBJS) 15 | $(AR) rcs $@ $^ 16 | 17 | .PHONY: clean 18 | clean: 19 | $(RM) $(DEPS) $(OBJS) $(TARGET) 20 | -------------------------------------------------------------------------------- /hardware/eflags.cpp: -------------------------------------------------------------------------------- 1 | #include "hardware/eflags.hpp" 2 | 3 | template uint32_t Eflags::update_eflags_add(uint32_t v1, uint32_t v2); 4 | template uint32_t Eflags::update_eflags_add(uint16_t v1, uint32_t v2); 5 | template uint32_t Eflags::update_eflags_add(uint8_t v1, uint32_t v2); 6 | template uint32_t Eflags::update_eflags_add(T v1, uint32_t v2){ 7 | bool s1, s2, sr; 8 | uint64_t result; 9 | uint8_t size; 10 | 11 | v2 = (T)v2; 12 | result = (uint64_t)v1 + v2; 13 | size = sizeof(T)*8; 14 | 15 | s1 = v1 >> (size-1); 16 | s2 = v2 >> (size-1); 17 | sr = (result >> (size-1)) & 1; 18 | 19 | set_carry(result >> size); 20 | set_parity(chk_parity(result & 0xff)); 21 | set_zero(!result); 22 | set_sign(sr); 23 | set_overflow(!(s1^s2) && s1^sr); 24 | 25 | return eflags.reg32; 26 | } 27 | 28 | template uint32_t Eflags::update_eflags_or(uint32_t v1, uint32_t v2); 29 | template uint32_t Eflags::update_eflags_or(uint16_t v1, uint32_t v2); 30 | template uint32_t Eflags::update_eflags_or(uint8_t v1, uint32_t v2); 31 | template uint32_t Eflags::update_eflags_or(T v1, uint32_t v2){ 32 | T result; 33 | uint8_t size; 34 | 35 | v2 = (T)v2; 36 | result = v1 | v2; 37 | size = sizeof(T)*8; 38 | 39 | set_carry(0); 40 | set_parity(chk_parity(result & 0xff)); 41 | set_zero(!result); 42 | set_sign((result >> (size-1)) & 1); 43 | set_overflow(0); 44 | 45 | return eflags.reg32; 46 | } 47 | 48 | template uint32_t Eflags::update_eflags_and(uint32_t v1, uint32_t v2); 49 | template uint32_t Eflags::update_eflags_and(uint16_t v1, uint32_t v2); 50 | template uint32_t Eflags::update_eflags_and(uint8_t v1, uint32_t v2); 51 | template uint32_t Eflags::update_eflags_and(T v1, uint32_t v2){ 52 | T result; 53 | uint8_t size; 54 | 55 | v2 = (T)v2; 56 | result = v1 & v2; 57 | size = sizeof(T)*8; 58 | 59 | set_carry(0); 60 | set_parity(chk_parity(result & 0xff)); 61 | set_zero(!result); 62 | set_sign((result >> (size-1)) & 1); 63 | set_overflow(0); 64 | 65 | return eflags.reg32; 66 | } 67 | 68 | template uint32_t Eflags::update_eflags_sub(uint32_t v1, uint32_t v2); 69 | template uint32_t Eflags::update_eflags_sub(uint16_t v1, uint32_t v2); 70 | template uint32_t Eflags::update_eflags_sub(uint8_t v1, uint32_t v2); 71 | template uint32_t Eflags::update_eflags_sub(T v1, uint32_t v2){ 72 | bool s1, s2, sr; 73 | uint64_t result; 74 | uint8_t size; 75 | 76 | v2 = (T)v2; 77 | result = (uint64_t)v1 - v2; 78 | size = sizeof(T)*8; 79 | 80 | s1 = v1 >> (size-1); 81 | s2 = v2 >> (size-1); 82 | sr = (result >> (size-1)) & 1; 83 | 84 | set_carry(result >> size); 85 | set_parity(chk_parity(result & 0xff)); 86 | set_zero(!result); 87 | set_sign(sr); 88 | set_overflow(s1^s2 && s1^sr); 89 | 90 | return eflags.reg32; 91 | } 92 | 93 | template uint32_t Eflags::update_eflags_mul(uint32_t v1, uint32_t v2); 94 | template uint32_t Eflags::update_eflags_mul(uint16_t v1, uint32_t v2); 95 | template uint32_t Eflags::update_eflags_mul(uint8_t v1, uint32_t v2); 96 | template uint32_t Eflags::update_eflags_mul(T v1, uint32_t v2){ 97 | uint64_t result; 98 | uint8_t size; 99 | 100 | v2 = (T)v2; 101 | result = (uint64_t)v1 * v2; 102 | size = sizeof(T)*8; 103 | 104 | set_carry(result >> size); 105 | set_overflow(result >> size); 106 | 107 | return eflags.reg32; 108 | } 109 | 110 | template uint32_t Eflags::update_eflags_imul(int32_t v1, int32_t v2); 111 | template uint32_t Eflags::update_eflags_imul(int16_t v1, int32_t v2); 112 | template uint32_t Eflags::update_eflags_imul(int8_t v1, int32_t v2); 113 | template uint32_t Eflags::update_eflags_imul(T v1, int32_t v2){ 114 | int64_t result; 115 | uint8_t size; 116 | 117 | v2 = (T)v2; 118 | result = (int64_t)v1 * v2; 119 | size = sizeof(T)*8; 120 | 121 | set_carry((result >> size) != -1); 122 | set_overflow((result >> size) != -1); 123 | 124 | return eflags.reg32; 125 | } 126 | 127 | template uint32_t Eflags::update_eflags_shl(uint32_t v, uint8_t c); 128 | template uint32_t Eflags::update_eflags_shl(uint16_t v, uint8_t c); 129 | template uint32_t Eflags::update_eflags_shl(uint8_t v, uint8_t c); 130 | template uint32_t Eflags::update_eflags_shl(T v, uint8_t c){ 131 | T result; 132 | uint8_t size; 133 | 134 | result = v << c; 135 | size = sizeof(T)*8; 136 | 137 | set_carry((v >> (size-c)) & 1); 138 | set_parity(chk_parity(result & 0xff)); 139 | set_zero(!result); 140 | set_sign((result >> (size-1)) & 1); 141 | if(c==1) 142 | set_overflow(((v >> (size-1)) & 1) ^ ((v >> (size-2)) & 1)); 143 | 144 | return eflags.reg32; 145 | } 146 | 147 | template uint32_t Eflags::update_eflags_shr(uint32_t v, uint8_t c); 148 | template uint32_t Eflags::update_eflags_shr(uint16_t v, uint8_t c); 149 | template uint32_t Eflags::update_eflags_shr(uint8_t v, uint8_t c); 150 | template uint32_t Eflags::update_eflags_shr(T v, uint8_t c){ 151 | T result; 152 | uint8_t size; 153 | 154 | result = v >> c; 155 | size = sizeof(T)*8; 156 | 157 | set_carry((v >> (c-1)) & 1); 158 | set_parity(chk_parity(result & 0xff)); 159 | set_zero(!result); 160 | set_sign((result >> (size-1)) & 1); 161 | if(c==1) 162 | set_overflow((v >> (size-1)) & 1); 163 | 164 | return eflags.reg32; 165 | } 166 | 167 | bool Eflags::chk_parity(uint8_t v){ 168 | bool p = true; 169 | 170 | for(int i=0; i<8; i++) 171 | p ^= (v>>i) & 1; 172 | 173 | return p; 174 | } 175 | -------------------------------------------------------------------------------- /hardware/io.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "hardware/io.hpp" 4 | 5 | IO::~IO(){ 6 | std::unordered_map::iterator it_p; 7 | std::unordered_map::iterator it_m; 8 | 9 | // for(it_p = port_io.begin(); it_p != port_io.end(); it_p++) 10 | // delete it_p->second; 11 | port_io.clear(); 12 | 13 | // for(it_m = mem_io.begin(); it_m != mem_io.end(); it_m++) 14 | // delete it_m->second; 15 | mem_io.clear(); 16 | mem_io_map.clear(); 17 | } 18 | 19 | /* port IO */ 20 | void IO::set_portio(uint16_t addr, size_t len, PortIO *dev) { 21 | addr &= ~1; 22 | 23 | port_io[addr] = dev; 24 | port_io_map[addr] = len; 25 | } 26 | 27 | uint16_t IO::get_portio_base(uint16_t addr){ 28 | for(int i=0; i<5; i++){ // max_mask : 0xfff0 29 | uint16_t base = (addr&(~1)) - (2*i); 30 | if(port_io_map.count(base)) 31 | return addr < base+port_io_map[base] ? base : 0; 32 | } 33 | return 0; 34 | } 35 | 36 | uint32_t IO::in_io32(uint16_t addr){ 37 | uint32_t v = 0; 38 | 39 | for(int i=0; i<4; i++) 40 | v += in_io8(addr+i) << (8*i); 41 | return v; 42 | } 43 | 44 | uint16_t IO::in_io16(uint16_t addr){ 45 | uint16_t v = 0; 46 | 47 | for(int i=0; i<2; i++) 48 | v += in_io8(addr+i) << (8*i); 49 | return v; 50 | } 51 | 52 | uint8_t IO::in_io8(uint16_t addr){ 53 | uint8_t v = 0; 54 | uint16_t base = get_portio_base(addr); 55 | if(base) 56 | v = port_io[base]->in8(addr); 57 | else 58 | ERROR("no device connected at port : 0x%04x", addr); 59 | INFO(4, "in [0x%04x] (0x%04x)", addr, v); 60 | return v; 61 | } 62 | 63 | void IO::out_io32(uint16_t addr, uint32_t value){ 64 | for(int i=0; i<4; i++) 65 | out_io8(addr+i, (value >> (8*i)) & 0xff); 66 | } 67 | 68 | void IO::out_io16(uint16_t addr, uint16_t value){ 69 | for(int i=0; i<2; i++) 70 | out_io8(addr+i, (value >> (8*i)) & 0xff); 71 | } 72 | 73 | void IO::out_io8(uint16_t addr, uint8_t value){ 74 | uint16_t base = get_portio_base(addr); 75 | if(base) 76 | port_io[base]->out8(addr, value); 77 | else 78 | ERROR("no device connected at port : 0x%04x", addr); 79 | INFO(4, "out [0x%04x] (0x%04x)", addr, value); 80 | } 81 | 82 | /* memory mapped IO */ 83 | void IO::set_memio(uint32_t base, size_t len, MemoryIO *dev) { 84 | uint32_t addr; 85 | 86 | ASSERT(!(base&((1<<12)-1))); 87 | 88 | dev->set_mem(memory, base, len); 89 | mem_io[base] = dev; 90 | 91 | for(addr=base; addrread32(offset); 103 | } 104 | 105 | uint16_t IO::read_memio16(uint32_t base, uint32_t offset){ 106 | ASSERT(mem_io.count(base)); 107 | return mem_io[base]->read16(offset); 108 | } 109 | 110 | uint8_t IO::read_memio8(uint32_t base, uint32_t offset){ 111 | ASSERT(mem_io.count(base)); 112 | return mem_io[base]->read8(offset); 113 | } 114 | 115 | void IO::write_memio32(uint32_t base, uint32_t offset, uint32_t value){ 116 | ASSERT(mem_io.count(base)); 117 | mem_io[base]->write32(offset, value); 118 | } 119 | 120 | void IO::write_memio16(uint32_t base, uint32_t offset, uint16_t value){ 121 | ASSERT(mem_io.count(base)); 122 | mem_io[base]->write16(offset, value); 123 | } 124 | 125 | void IO::write_memio8(uint32_t base, uint32_t offset, uint8_t value){ 126 | ASSERT(mem_io.count(base)); 127 | mem_io[base]->write8(offset, value); 128 | } 129 | -------------------------------------------------------------------------------- /hardware/memory.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "hardware/memory.hpp" 4 | 5 | Memory::Memory(size_t size){ 6 | mem_size = size; 7 | memory = new uint8_t[size]; 8 | a20gate = false; 9 | } 10 | 11 | Memory::~Memory(){ 12 | delete[] memory; 13 | mem_size = 0; 14 | } 15 | 16 | void Memory::dump_mem(uint32_t addr, size_t size){ 17 | addr &= ~(0x10-1); 18 | 19 | for(uint32_t idx=0; idx*0x10 2 | #include "hardware/processor.hpp" 3 | 4 | Processor::Processor(void){ 5 | memset(gpregs, 0, sizeof(gpregs)); 6 | memset(sgregs, 0, sizeof(sgregs)); 7 | 8 | set_eip(0x0000fff0); 9 | set_crn(0, 0x60000010); 10 | set_eflags(0x00000002); 11 | 12 | sgregs[CS].raw = 0xf000; 13 | sgregs[CS].cache.base = 0xffff0000; 14 | sgregs[CS].cache.flags.type.segc = 1; 15 | for(int i=0; i 5 | #include "util/debug.hpp" 6 | 7 | #define KB 1024 8 | #define MB (KB*1024) 9 | #define GB (MB*1024) 10 | 11 | #endif 12 | -------------------------------------------------------------------------------- /include/device/com.hpp: -------------------------------------------------------------------------------- 1 | #ifndef _COM_H 2 | #define _COM_H 3 | 4 | #include "common.hpp" 5 | #include "dev_io.hpp" 6 | 7 | class COM : public PortIO { 8 | public: 9 | uint8_t in8(uint16_t addr); 10 | void out8(uint16_t addr, uint8_t v); 11 | }; 12 | 13 | #endif 14 | -------------------------------------------------------------------------------- /include/device/dev_io.hpp: -------------------------------------------------------------------------------- 1 | #ifndef _DEV_IO_H 2 | #define _DEV_IO_H 3 | 4 | #include "common.hpp" 5 | #include "hardware/memory.hpp" 6 | 7 | class PortIO { 8 | public: 9 | virtual ~PortIO() {}; 10 | virtual uint8_t in8(uint16_t addr) = 0; 11 | virtual void out8(uint16_t addr, uint8_t v) = 0; 12 | }; 13 | 14 | class MemoryIO { 15 | protected: 16 | Memory *memory; 17 | uint32_t paddr; 18 | size_t size; 19 | 20 | public: 21 | virtual ~MemoryIO() {}; 22 | 23 | void set_mem(Memory *mem, uint32_t addr, size_t len) { memory = mem; paddr = addr; size = len; }; 24 | 25 | virtual uint32_t read32(uint32_t offset){ 26 | uint32_t v = 0; 27 | for(int i=0; i<4; i++) 28 | v += read8(offset+i)<<(8*i); 29 | return v; 30 | } 31 | virtual uint16_t read16(uint32_t offset){ 32 | uint16_t v = 0; 33 | for(int i=0; i<2; i++) 34 | v += read8(offset+i)<<(8*i); 35 | return v; 36 | } 37 | virtual uint8_t read8(uint32_t offset) = 0; 38 | 39 | virtual void write32(uint32_t offset, uint32_t v){ 40 | for(int i=0; i<4; i++) 41 | write8(offset+i, (v>>(8*i))&0xff); 42 | } 43 | virtual void write16(uint32_t offset, uint16_t v){ 44 | for(int i=0; i<2; i++) 45 | write8(offset+i, (v>>(8*i))&0xff); 46 | } 47 | virtual void write8(uint32_t offset, uint8_t v) = 0; 48 | }; 49 | 50 | #endif 51 | -------------------------------------------------------------------------------- /include/device/dev_irq.hpp: -------------------------------------------------------------------------------- 1 | #ifndef _DEV_IRQ_H 2 | #define _DEV_IRQ_H 3 | 4 | #include "common.hpp" 5 | 6 | class IRQ { 7 | protected: 8 | bool intr; 9 | public: 10 | IRQ() { intr = false; }; 11 | virtual bool chk_intreq(void) { if(intr){ intr = false; return true; } return false; }; 12 | }; 13 | 14 | #endif 15 | -------------------------------------------------------------------------------- /include/device/devices.hpp: -------------------------------------------------------------------------------- 1 | #ifndef _DEVICES_H 2 | #define _DEVICES_H 3 | 4 | #include "com.hpp" 5 | #include "syscontrol.hpp" 6 | #include "pic.hpp" 7 | #include "pit.hpp" 8 | #include "fdd.hpp" 9 | #include "vga.hpp" 10 | #include "keyboard.hpp" 11 | #include "mouse.hpp" 12 | 13 | #endif 14 | -------------------------------------------------------------------------------- /include/device/dma.hpp: -------------------------------------------------------------------------------- 1 | #ifndef _DMA_H 2 | #define _DMA_H 3 | 4 | #include "common.hpp" 5 | #include "dev_drq.hpp" 6 | #include "dev_io.hpp" 7 | 8 | class DMA : public DRQ, public PortIO { 9 | private: 10 | DRQ *drq[4]; 11 | 12 | uint16_t adrr[4]; 13 | uint8_t xpadrr[4]; 14 | uint16_t cntr[4]; 15 | 16 | union { 17 | uint8_t raw; 18 | struct { 19 | uint8_t NMT : 1; 20 | uint8_t ADHE : 1; 21 | uint8_t COND : 1; 22 | uint8_t COMP : 1; 23 | uint8_t PRIO : 1; 24 | uint8_t EXTW : 1; 25 | uint8_t DRQP : 1; 26 | uint8_t DACKP : 1; 27 | }; 28 | } cmnr; 29 | 30 | union { 31 | uint8_t raw; 32 | struct { 33 | uint8_t SEL : 2; 34 | uint8_t TRA : 2; 35 | uint8_t AUTO : 1; 36 | uint8_t DOWN : 1; 37 | uint8_t MOD : 2; 38 | }; 39 | } modr; 40 | 41 | union { 42 | uint8_t raw; 43 | struct { 44 | uint8_t SEL : 2; 45 | uint8_t REQ : 1; 46 | }; 47 | } reqr; 48 | 49 | union { 50 | uint8_t raw; 51 | struct { 52 | uint8_t SEL : 2; 53 | uint8_t MASK : 1; 54 | }; 55 | } scmr; 56 | 57 | union { 58 | uint8_t raw; 59 | struct { 60 | uint8_t CH0 : 1; 61 | uint8_t CH1 : 1; 62 | uint8_t CH2 : 1; 63 | uint8_t CH3 : 1; 64 | }; 65 | } amr; 66 | 67 | union { 68 | uint8_t raw; 69 | struct { 70 | uint8_t TC0 : 1; 71 | uint8_t TC1 : 1; 72 | uint8_t TC2 : 1; 73 | uint8_t TC3 : 1; 74 | uint8_t CH0 : 1; 75 | uint8_t CH1 : 1; 76 | uint8_t CH2 : 1; 77 | uint8_t CH3 : 1; 78 | }; 79 | } statr; 80 | 81 | public: 82 | uint8_t in8(uint16_t addr); 83 | void out8(uint16_t addr, uint8_t v); 84 | }; 85 | 86 | #endif 87 | -------------------------------------------------------------------------------- /include/device/fdd.hpp: -------------------------------------------------------------------------------- 1 | #ifndef _FDD_H 2 | #define _FDD_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include "common.hpp" 9 | #include "dev_io.hpp" 10 | #include "dev_irq.hpp" 11 | 12 | #define MAX_FDD 4 13 | #define SIZE_SECTOR 0x200 14 | #define N_SpH 18 15 | #define N_HpC 2 16 | 17 | #define FDD_READ_TRACK 0x02 18 | #define FDD_SENSE_DRIVE_STATUS 0x04 19 | #define FDD_WRITE_DATA 0x05 20 | #define FDD_READ_DATA 0x06 21 | #define FDD_RECALIBRATE 0x07 22 | #define FDD_READ_ID 0x0a 23 | #define FDD_FORMAT_TRACK 0x0d 24 | #define FDD_SEEK 0x0f 25 | #define FDD_CONFIGURE 0x13 26 | 27 | struct DRIVE { 28 | FILE *disk; 29 | uint8_t cylinder : 7; // 0 ~ 79 30 | uint8_t head : 1; // 0 or 1 31 | uint8_t sector : 5; // 1 ~ 18 32 | bool write; 33 | uint16_t progress; 34 | }; 35 | 36 | struct QUEUE { 37 | std::queue queue; 38 | std::mutex mtx; 39 | uint16_t max; 40 | }; 41 | 42 | class FDD : public IRQ, public PortIO { 43 | private: 44 | typedef void (FDD::*fddfunc_t)(void); 45 | std::unordered_map fddfuncs; 46 | DRIVE *drive[MAX_FDD]; 47 | 48 | union { 49 | uint8_t raw; 50 | struct { 51 | uint8_t FIFOTHR : 4; 52 | uint8_t POLL : 1; 53 | uint8_t EFIFO : 1; 54 | uint8_t EIS : 1; 55 | }; 56 | } conf; 57 | 58 | union { 59 | uint8_t raw; 60 | struct { 61 | uint8_t DIR : 1; 62 | uint8_t nWP : 1; 63 | uint8_t nINDX : 1; 64 | uint8_t HDSEL : 1; 65 | uint8_t nTRK0 : 1; 66 | uint8_t STEP : 1; 67 | uint8_t nDRV2 : 1; 68 | uint8_t INT : 1; 69 | }; 70 | } sra; 71 | 72 | union { 73 | uint8_t raw; 74 | struct { 75 | uint8_t MOT0 : 1; 76 | uint8_t MOT1 : 1; 77 | uint8_t WE : 1; 78 | uint8_t RD : 1; 79 | uint8_t WR : 1; 80 | uint8_t SEL0 : 1; 81 | }; 82 | } srb; 83 | 84 | union { 85 | uint8_t raw; 86 | struct { 87 | uint8_t SEL0 : 1; 88 | uint8_t SEL1 : 1; 89 | uint8_t nRESET : 1; 90 | uint8_t nDMA : 1; 91 | uint8_t MOT : 4; 92 | }; 93 | } dor; 94 | 95 | union { 96 | uint8_t raw; 97 | } tdr; 98 | 99 | union { 100 | uint8_t raw; 101 | struct { 102 | uint8_t DRV_BSY : 4; 103 | uint8_t CMD_BSY : 1; 104 | uint8_t NON_DMA : 1; 105 | uint8_t DIO : 1; 106 | uint8_t RQM : 1; 107 | }; 108 | } msr; 109 | 110 | union { 111 | uint8_t raw; 112 | } dsr; 113 | 114 | uint8_t data; 115 | QUEUE data_q; 116 | 117 | union { 118 | uint8_t raw; 119 | } ccr; 120 | 121 | union { 122 | uint8_t raw; 123 | } dir; 124 | 125 | union { 126 | uint8_t raw; 127 | struct { 128 | uint8_t DS0 : 1; 129 | uint8_t DS1 : 1; 130 | uint8_t H : 1; 131 | uint8_t : 1; 132 | uint8_t EC : 1; 133 | uint8_t SE : 1; 134 | uint8_t IC0 : 1; 135 | uint8_t IC1 : 1; 136 | }; 137 | } st0; 138 | 139 | union { 140 | uint8_t raw; 141 | struct { 142 | uint8_t MA : 1; 143 | uint8_t NW : 1; 144 | uint8_t ND : 1; 145 | uint8_t : 1; 146 | uint8_t OR : 1; 147 | uint8_t DE : 1; 148 | uint8_t : 1; 149 | uint8_t EN : 1; 150 | }; 151 | } st1; 152 | 153 | union { 154 | uint8_t raw; 155 | struct { 156 | uint8_t MD : 1; 157 | uint8_t BC : 1; 158 | uint8_t SN : 1; 159 | uint8_t SH : 1; 160 | uint8_t WC : 1; 161 | uint8_t DD : 1; 162 | uint8_t CM : 1; 163 | }; 164 | } st2; 165 | 166 | union { 167 | uint8_t raw; 168 | struct { 169 | uint8_t DS0 : 1; 170 | uint8_t DS1 : 1; 171 | uint8_t HD : 1; 172 | uint8_t : 1; 173 | uint8_t T0 : 1; 174 | uint8_t : 1; 175 | uint8_t WP : 1; 176 | }; 177 | } str3; 178 | 179 | std::thread th; 180 | 181 | public: 182 | FDD(); 183 | ~FDD(); 184 | bool insert_disk(uint8_t slot, const char *fname, bool write); 185 | bool eject_disk(uint8_t slot); 186 | uint8_t in8(uint16_t addr); 187 | void out8(uint16_t addr, uint8_t v); 188 | //bool chk_intreq(void) { if(sra.INT){ sra.INT = false; return true; } return false; }; 189 | private: 190 | void worker(void); 191 | void fdd_read_track(void); 192 | void fdd_write_data(void); 193 | void fdd_read_data(void); 194 | void fdd_configure(void); 195 | 196 | int32_t seek(uint8_t slot, uint8_t c, uint8_t h, uint8_t s); 197 | uint8_t read(uint8_t slot); 198 | void write(uint8_t slot, uint8_t v); 199 | void sync_position(uint8_t slot); 200 | 201 | void write_datareg(uint8_t v); 202 | uint8_t read_datareg(void); 203 | void enqueue(QUEUE *q, uint8_t v); 204 | uint8_t dequeue(QUEUE *q); 205 | }; 206 | 207 | #endif 208 | -------------------------------------------------------------------------------- /include/device/keyboard.hpp: -------------------------------------------------------------------------------- 1 | #ifndef _KEYBOARD_H 2 | #define _KEYBOARD_H 3 | 4 | #include "common.hpp" 5 | #include "dev_irq.hpp" 6 | #include "dev_io.hpp" 7 | #include "mouse.hpp" 8 | #include "hardware/memory.hpp" 9 | 10 | struct CCB { 11 | uint8_t KIE : 1; 12 | uint8_t MIE : 1; 13 | uint8_t SYSF : 1; 14 | uint8_t IGNLK : 1; 15 | uint8_t KE : 1; 16 | uint8_t ME : 1; 17 | uint8_t XLATE : 1; 18 | }; 19 | 20 | class Keyboard : public IRQ, public PortIO { 21 | friend Mouse; 22 | private: 23 | Mouse *mouse; 24 | Memory *mem; // A20 gate 25 | uint8_t mode; 26 | 27 | union { 28 | uint8_t raw; 29 | struct { 30 | uint8_t OBF : 1; 31 | uint8_t IBF : 1; 32 | uint8_t F0 : 1; 33 | uint8_t F1 : 1; 34 | uint8_t ST4 : 1; 35 | uint8_t ST5 : 1; 36 | uint8_t ST6 : 1; 37 | uint8_t ST7 : 1; 38 | }; 39 | } kcsr; 40 | 41 | uint8_t out_buf; 42 | uint8_t in_buf; 43 | uint8_t controller_ram[0x20]; 44 | CCB *ccb = (CCB*)&controller_ram[0]; 45 | 46 | public: 47 | Keyboard(Memory *m) { mouse = new Mouse(this); kcsr.raw = 0; mem = m; }; 48 | Mouse *get_mouse(void) const { return mouse; }; 49 | 50 | uint8_t in8(uint16_t addr); 51 | void out8(uint16_t addr, uint8_t v); 52 | void command(uint8_t v); 53 | uint8_t read_outbuf(void); 54 | void write_outbuf(uint8_t v); 55 | void send_code(uint8_t scancode); 56 | void swt_a20gate(uint8_t v); 57 | }; 58 | 59 | #endif 60 | -------------------------------------------------------------------------------- /include/device/mouse.hpp: -------------------------------------------------------------------------------- 1 | #ifndef _MOUSE_H 2 | #define _MOUSE_H 3 | 4 | #include "common.hpp" 5 | #include "dev_irq.hpp" 6 | 7 | class Keyboard; 8 | class Mouse : public IRQ { 9 | private: 10 | Keyboard *keyboard; 11 | bool enable; 12 | 13 | public: 14 | Mouse(Keyboard *kb) { keyboard = kb; enable = false; }; 15 | void command(uint8_t code); 16 | void send_code(uint8_t code); 17 | }; 18 | 19 | #endif 20 | -------------------------------------------------------------------------------- /include/device/pic.hpp: -------------------------------------------------------------------------------- 1 | #ifndef _PIC_H 2 | #define _PIC_H 3 | 4 | #include "common.hpp" 5 | #include "dev_irq.hpp" 6 | #include "dev_io.hpp" 7 | 8 | #define MAX_IRQ 8 9 | 10 | union OCW2 { 11 | uint8_t raw; 12 | struct { 13 | uint8_t L : 3; 14 | uint8_t : 2; 15 | uint8_t EOI : 1; 16 | uint8_t SL : 1; 17 | uint8_t R : 1; 18 | }; 19 | }; 20 | 21 | class PIC : public IRQ, public PortIO { 22 | private: 23 | PIC *pic_m; 24 | IRQ *irq[MAX_IRQ]; 25 | uint8_t irr; 26 | uint8_t isr; 27 | uint8_t imr; 28 | 29 | union { 30 | uint8_t raw; 31 | struct { 32 | uint8_t IC4 : 1; 33 | uint8_t SNGL : 1; 34 | uint8_t ADI : 1; 35 | uint8_t LTIM : 1; 36 | uint8_t : 1; 37 | uint8_t IVA_l : 3; // MCS-80/85 38 | }; 39 | } ic1; 40 | 41 | union { 42 | uint8_t raw; 43 | struct { 44 | uint8_t IVA_h : 3; // MCS-80/85 45 | uint8_t IVA_x86 : 5; 46 | }; 47 | } ic2; 48 | 49 | union { 50 | uint8_t raw; 51 | struct { 52 | uint8_t S0 : 1; 53 | uint8_t S1 : 1; 54 | uint8_t S2 : 1; 55 | uint8_t S3 : 1; 56 | uint8_t S4 : 1; 57 | uint8_t S5 : 1; 58 | uint8_t S6 : 1; 59 | uint8_t S7 : 1; 60 | }; 61 | 62 | struct { 63 | uint8_t ID : 3; 64 | }; 65 | } ic3; 66 | 67 | union { 68 | uint8_t raw; 69 | struct { 70 | uint8_t PM : 1; 71 | uint8_t AEOI : 1; 72 | uint8_t MS : 1; 73 | uint8_t BUF : 1; 74 | uint8_t SFNM : 1; 75 | }; 76 | } ic4; 77 | 78 | int8_t init_icn; 79 | 80 | public: 81 | PIC(PIC* master = NULL); 82 | void set_irq(uint8_t n, IRQ *dev) { if(n 6 | #include "dev_irq.hpp" 7 | #include "dev_io.hpp" 8 | 9 | struct Timer { 10 | uint8_t mode; 11 | uint16_t count; 12 | uint16_t def; 13 | 14 | bool running; 15 | std::thread th; 16 | }; 17 | 18 | class PIT : public IRQ, public PortIO { 19 | private: 20 | union { 21 | uint8_t raw; 22 | struct { 23 | uint8_t BCD : 1; 24 | uint8_t mode : 3; 25 | uint8_t RL : 2; 26 | uint8_t SC : 2; 27 | }; 28 | } cwr; 29 | 30 | Timer timer[3]; 31 | 32 | public: 33 | PIT(); 34 | ~PIT(); 35 | uint8_t in8(uint16_t addr); 36 | void out8(uint16_t addr, uint8_t v); 37 | //bool chk_intreq(void); 38 | void counter(Timer *t); 39 | }; 40 | 41 | #endif 42 | -------------------------------------------------------------------------------- /include/device/syscontrol.hpp: -------------------------------------------------------------------------------- 1 | #ifndef _SYSCONTROL_H 2 | #define _SYSCONTROL_H 3 | 4 | #include "common.hpp" 5 | #include "dev_io.hpp" 6 | #include "hardware/memory.hpp" 7 | 8 | class SysControl : public PortIO { 9 | private: 10 | Memory *mem; 11 | public: 12 | SysControl(Memory *m) { mem = m; }; 13 | uint8_t in8(uint16_t addr); 14 | void out8(uint16_t addr, uint8_t v); 15 | }; 16 | 17 | #endif 18 | -------------------------------------------------------------------------------- /include/device/vga.hpp: -------------------------------------------------------------------------------- 1 | #ifndef _VGA_H 2 | #define _VGA_H 3 | 4 | #include "common.hpp" 5 | #include "dev_io.hpp" 6 | 7 | #define r(reg) (®.raw) 8 | 9 | enum gmode_t {MODE_TEXT, MODE_GRAPHIC, MODE_GRAPHIC256}; 10 | 11 | class VGA : public PortIO, public MemoryIO { 12 | private: 13 | // General Register 14 | union { 15 | uint8_t raw; 16 | struct { 17 | uint8_t IO : 1; 18 | uint8_t ER : 1; 19 | uint8_t CLK0 : 1; 20 | uint8_t CLK1 : 1; 21 | uint8_t : 1; 22 | uint8_t PS : 1; 23 | uint8_t HSP : 1; 24 | uint8_t VSA : 1; 25 | }; 26 | } mor; 27 | 28 | uint8_t *plane[4]; 29 | bool refresh; 30 | 31 | class Sequencer : public PortIO { 32 | private: 33 | VGA *vga; 34 | 35 | union { 36 | uint8_t raw; 37 | struct { 38 | uint8_t INDX : 3; 39 | }; 40 | } sar; 41 | 42 | union { 43 | uint8_t raw; 44 | struct { 45 | uint8_t _89DC : 1; 46 | uint8_t : 1; 47 | uint8_t SL : 1; 48 | uint8_t DC : 1; 49 | uint8_t S4 : 1; 50 | uint8_t SO : 1; 51 | }; 52 | } cmr; 53 | 54 | union { 55 | uint8_t raw; 56 | struct { 57 | uint8_t MAP0E : 1; 58 | uint8_t MAP1E : 1; 59 | uint8_t MAP2E : 1; 60 | uint8_t MAP3E : 1; 61 | }; 62 | } map_mr; 63 | 64 | union { 65 | uint8_t raw; 66 | struct { 67 | uint8_t CMB : 2; 68 | uint8_t CMA : 2; 69 | uint8_t CMBM : 1; 70 | uint8_t CMAM : 1; 71 | }; 72 | } cmsr; 73 | 74 | union { 75 | uint8_t raw; 76 | struct { 77 | uint8_t : 1; 78 | uint8_t EM : 1; 79 | uint8_t OE : 1; 80 | uint8_t C4 : 1; 81 | }; 82 | } mem_mr; 83 | 84 | uint8_t *regs[8] = {NULL, r(cmr), r(map_mr), r(cmsr), r(mem_mr), NULL, NULL, NULL}; 85 | 86 | public: 87 | Sequencer(VGA *v) { 88 | vga = v; 89 | for(uint8_t i=0; i 6 | #include "hardware/hardware.hpp" 7 | 8 | struct PDE { 9 | uint32_t P : 1; 10 | uint32_t RW : 1; 11 | uint32_t US : 1; 12 | uint32_t PWT : 1; 13 | uint32_t PCD : 1; 14 | uint32_t A : 1; 15 | uint32_t : 1; 16 | uint32_t PS : 1; 17 | uint32_t G : 1; 18 | uint32_t : 3; 19 | uint32_t ptbl_base : 20; 20 | }; 21 | 22 | struct PTE { 23 | uint32_t P : 1; 24 | uint32_t RW : 1; 25 | uint32_t US : 1; 26 | uint32_t PWT : 1; 27 | uint32_t PCD : 1; 28 | uint32_t A : 1; 29 | uint32_t D : 1; 30 | uint32_t PAT : 1; 31 | uint32_t G : 1; 32 | uint32_t : 3; 33 | uint32_t page_base : 20; 34 | }; 35 | 36 | enum acsmode_t { MODE_READ, MODE_WRITE, MODE_EXEC }; 37 | 38 | class DataAccess : public virtual Hardware { 39 | private: 40 | std::vector tlb; 41 | 42 | public: 43 | void set_segment(sgreg_t seg, uint16_t v); 44 | uint16_t get_segment(sgreg_t seg); 45 | 46 | uint8_t get_data8(sgreg_t seg, uint32_t addr){ return read_mem8_seg(seg, addr); }; 47 | uint16_t get_data16(sgreg_t seg, uint32_t addr){ return read_mem16_seg(seg, addr); }; 48 | uint32_t get_data32(sgreg_t seg, uint32_t addr){ return read_mem32_seg(seg, addr); }; 49 | 50 | void put_data8(sgreg_t seg, uint32_t addr, uint8_t v){ write_mem8_seg(seg, addr, v); }; 51 | void put_data16(sgreg_t seg, uint32_t addr, uint16_t v){ write_mem16_seg(seg, addr, v); }; 52 | void put_data32(sgreg_t seg, uint32_t addr, uint32_t v){ write_mem32_seg(seg, addr, v); }; 53 | 54 | uint8_t get_code8(int index){ return exec_mem8_seg(CS, get_eip() + index); }; 55 | uint16_t get_code16(int index){ return exec_mem16_seg(CS, get_eip() + index); }; 56 | uint32_t get_code32(int index){ return exec_mem32_seg(CS, get_eip() + index); }; 57 | 58 | void push32(uint32_t v); 59 | uint32_t pop32(void); 60 | void push16(uint16_t v); 61 | uint16_t pop16(void); 62 | 63 | private: 64 | uint32_t trans_v2p(acsmode_t mode, sgreg_t seg, uint32_t vaddr); 65 | uint32_t trans_v2l(acsmode_t mode, sgreg_t seg, uint32_t vaddr); 66 | 67 | bool search_tlb(uint32_t vpn, PTE *pte); 68 | void cache_tlb(uint32_t vpn, PTE pte); 69 | 70 | uint32_t read_mem32_seg(sgreg_t seg, uint32_t addr); 71 | uint16_t read_mem16_seg(sgreg_t seg, uint32_t addr); 72 | uint8_t read_mem8_seg(sgreg_t seg, uint32_t addr); 73 | void write_mem32_seg(sgreg_t seg, uint32_t addr, uint32_t v); 74 | void write_mem16_seg(sgreg_t seg, uint32_t addr, uint16_t v); 75 | void write_mem8_seg(sgreg_t seg, uint32_t addr, uint8_t v); 76 | uint32_t exec_mem32_seg(sgreg_t seg, uint32_t addr) { return read_mem32(trans_v2p(MODE_EXEC, seg, addr)); }; 77 | uint16_t exec_mem16_seg(sgreg_t seg, uint32_t addr) { return read_mem16(trans_v2p(MODE_EXEC, seg, addr)); }; 78 | uint8_t exec_mem8_seg(sgreg_t seg, uint32_t addr) { return read_mem8(trans_v2p(MODE_EXEC, seg, addr)); }; 79 | }; 80 | 81 | #endif 82 | -------------------------------------------------------------------------------- /include/emulator/descriptor.hpp: -------------------------------------------------------------------------------- 1 | #ifndef _DESCRIPTOR_H 2 | #define _DESCRIPTOR_H 3 | 4 | #define TYPE_TSS 0x01 5 | #define TYPE_LDT 0x02 6 | #define TYPE_CALL 0x04 7 | #define TYPE_TASK 0x05 8 | #define TYPE_INTERRUPT 0x06 9 | #define TYPE_TRAP 0x07 10 | 11 | #define TYPE_DATA 0x10 12 | #define TYPE_CODE 0x18 13 | 14 | struct Descriptor { 15 | uint16_t limit_l; 16 | uint16_t base_l; 17 | uint8_t base_m; 18 | uint8_t type : 3; 19 | uint8_t D : 1; 20 | uint8_t S : 1; 21 | uint8_t DPL : 2; 22 | uint8_t P : 1; 23 | uint8_t limit_h : 4; 24 | uint8_t AVL : 1; 25 | uint8_t : 2; 26 | uint8_t G : 1; 27 | uint8_t base_h; 28 | }; 29 | 30 | // Segment Descriptor 31 | struct SegDesc { 32 | uint16_t limit_l; 33 | uint16_t base_l; 34 | uint8_t base_m; 35 | union { 36 | union { 37 | struct { 38 | uint8_t : 1; 39 | uint8_t w : 1; // 0:r, 1:rw 40 | uint8_t exd: 1; 41 | uint8_t : 5; 42 | } data; 43 | struct { 44 | uint8_t : 1; 45 | uint8_t r : 1; // 0:x, 1;xr 46 | uint8_t cnf : 1; 47 | uint8_t : 5; 48 | } code; 49 | struct{ 50 | uint8_t A : 1; 51 | uint8_t : 2; 52 | uint8_t segc : 1; 53 | uint8_t : 4; 54 | }; 55 | } type; 56 | 57 | struct { 58 | uint8_t : 4; 59 | uint8_t S : 1; // 1 60 | uint8_t DPL : 2; 61 | uint8_t P : 1; 62 | }; 63 | }; 64 | uint8_t limit_h : 4; 65 | uint8_t AVL : 1; 66 | uint8_t : 1; 67 | uint8_t DB : 1; 68 | uint8_t G : 1; 69 | uint8_t base_h; 70 | }; 71 | 72 | // System Segment Descriptor 73 | struct TSSDesc { 74 | uint16_t limit_l; 75 | uint16_t base_l; 76 | uint8_t base_m; 77 | union { 78 | struct { 79 | uint8_t : 1; 80 | uint8_t B : 1; 81 | }; 82 | 83 | struct { 84 | uint8_t type : 3; // 1 or 3 85 | uint8_t D : 1; // 0:16bit, 1:32bit 86 | uint8_t S : 1; // 0 87 | uint8_t DPL : 2; 88 | uint8_t P : 1; 89 | }; 90 | }; 91 | uint8_t limit_h : 4; 92 | uint8_t AVL : 1; 93 | uint8_t : 2; 94 | uint8_t G : 1; 95 | uint8_t base_h; 96 | }; 97 | 98 | struct LDTDesc { 99 | uint16_t limit_l; 100 | uint16_t base_l; 101 | uint8_t base_m; 102 | uint8_t type : 3; // 2 103 | uint8_t D : 1; 104 | uint8_t S : 1; // 0 105 | uint8_t DPL : 2; 106 | uint8_t P : 1; 107 | uint8_t limit_h : 4; 108 | uint8_t AVL : 1; 109 | uint8_t : 2; 110 | uint8_t G : 1; 111 | uint8_t base_h; 112 | }; 113 | 114 | // Gate Descriptor 115 | struct CallGateDesc { 116 | uint16_t offset_l; 117 | uint16_t seg_sel; 118 | uint8_t pc : 5; 119 | uint8_t : 3; 120 | uint8_t type : 3; // 4 121 | uint8_t D : 1; 122 | uint8_t S : 1; // 0 123 | uint8_t DPL : 2; 124 | uint8_t P : 1; 125 | uint16_t offset_h; 126 | }; 127 | 128 | struct TaskGateDesc { 129 | uint16_t : 16; 130 | uint16_t tss_sel; 131 | uint8_t : 8; 132 | uint8_t type : 3; // 5 133 | uint8_t : 1; 134 | uint8_t S : 1; // 0 135 | uint8_t DPL : 2; 136 | uint8_t P : 1; 137 | uint16_t : 16; 138 | }; 139 | 140 | struct IntGateDesc { 141 | uint16_t offset_l; 142 | uint16_t seg_sel; 143 | uint8_t : 8; 144 | uint8_t type : 3; // 6 145 | uint8_t D : 1; 146 | uint8_t S : 1; // 0 147 | uint8_t DPL : 2; 148 | uint8_t P : 1; 149 | uint16_t offset_h; 150 | }; 151 | 152 | struct TrapGateDesc { 153 | uint16_t offset_l; 154 | uint16_t seg_sel; 155 | uint8_t : 8; 156 | uint8_t type : 3; // 7 157 | uint8_t D : 1; 158 | uint8_t S : 1; // 0 159 | uint8_t DPL : 2; 160 | uint8_t P : 1; 161 | uint16_t offset_h; 162 | }; 163 | 164 | struct TSS { 165 | uint16_t prev_sel; 166 | uint16_t : 16; 167 | uint32_t esp0; 168 | uint16_t ss0; 169 | uint16_t : 16; 170 | uint32_t esp1; 171 | uint16_t ss1; 172 | uint16_t : 16; 173 | uint32_t esp2; 174 | uint16_t ss2; 175 | uint16_t : 16; 176 | uint32_t cr3; 177 | uint32_t eip; 178 | uint32_t eflags; 179 | uint32_t eax; 180 | uint32_t ecx; 181 | uint32_t edx; 182 | uint32_t ebx; 183 | uint32_t esp; 184 | uint32_t ebp; 185 | uint32_t esi; 186 | uint32_t edi; 187 | uint16_t es; 188 | uint16_t : 16; 189 | uint16_t cs; 190 | uint16_t : 16; 191 | uint16_t ss; 192 | uint16_t : 16; 193 | uint16_t ds; 194 | uint16_t : 16; 195 | uint16_t fs; 196 | uint16_t : 16; 197 | uint16_t gs; 198 | uint16_t : 16; 199 | uint16_t ldtr; 200 | uint16_t : 16; 201 | uint16_t T : 1; 202 | uint16_t : 15; 203 | uint16_t io_base; 204 | }; 205 | 206 | #endif 207 | -------------------------------------------------------------------------------- /include/emulator/emulator.hpp: -------------------------------------------------------------------------------- 1 | #ifndef _EMULATOR_H 2 | #define _EMULATOR_H 3 | 4 | #include "common.hpp" 5 | #include "access.hpp" 6 | #include "interrupt.hpp" 7 | #include "ui.hpp" 8 | #include "device/devices.hpp" 9 | 10 | struct EmuSetting { 11 | size_t mem_size; 12 | UISetting uiset; 13 | }; 14 | 15 | class Emulator : public virtual DataAccess, public Interrupt { 16 | private: 17 | UI *ui; 18 | FDD *fdd; 19 | public: 20 | Emulator(EmuSetting set); 21 | bool is_running(void) const { return ui ? ui->get_status() : false; }; 22 | void stop(void) { delete ui; ui = NULL; }; 23 | 24 | void load_binary(const char* fname, uint32_t addr, uint32_t offset, size_t size); 25 | bool insert_floppy(uint8_t slot, const char* disk, bool write) { 26 | return fdd ? fdd->insert_disk(slot, disk, write) : false; }; 27 | bool eject_floppy(uint8_t slot) { return fdd ? fdd->eject_disk(slot) : false; }; 28 | }; 29 | 30 | #endif 31 | -------------------------------------------------------------------------------- /include/emulator/exception.hpp: -------------------------------------------------------------------------------- 1 | #ifndef _EXCEPTION_H 2 | #define _EXCEPTION_H 3 | 4 | enum exception_t { 5 | EXP_DE = 0, 6 | EXP_DB = 1, 7 | EXP_BP = 3, 8 | EXP_OF = 4, 9 | EXP_BR = 5, 10 | EXP_UD = 6, 11 | EXP_NM = 7, 12 | EXP_DF = 8, 13 | EXP_TS = 10, 14 | EXP_NP = 11, 15 | EXP_SS = 12, 16 | EXP_GP = 13, 17 | EXP_PF = 14, 18 | EXP_MF = 16, 19 | EXP_AC = 17, 20 | EXP_MC = 18, 21 | EXP_XF = 19, 22 | EXP_VE = 20, 23 | EXP_SX = 30 24 | }; 25 | 26 | #define EXCEPTION(n, c) if(c){ WARN("exception interrupt %d (%s)", n, #c); throw n; } 27 | #define EXCEPTION_WITH(n, c, e) if(c){ WARN("exception interrupt %d (%s)", n, #c); e; throw n; } 28 | 29 | #endif 30 | -------------------------------------------------------------------------------- /include/emulator/interrupt.hpp: -------------------------------------------------------------------------------- 1 | #ifndef _INTERRUPT_H 2 | #define _INTERRUPT_H 3 | 4 | #include 5 | #include 6 | #include "common.hpp" 7 | #include "access.hpp" 8 | #include "device/pic.hpp" 9 | 10 | union IVT { // Real Mode 11 | uint32_t raw; 12 | struct { 13 | uint16_t offset; 14 | uint16_t segment; 15 | }; 16 | }; 17 | 18 | class Interrupt : public virtual DataAccess { 19 | private: 20 | std::queue< std::pair > intr_q; 21 | PIC *pic_m, *pic_s; 22 | 23 | public: 24 | void set_pic(PIC *pic, bool master) { (master ? pic_m : pic_s) = pic; }; 25 | void hundle_interrupt(void); 26 | void queue_interrupt(uint8_t n, bool hard) { intr_q.push(std::make_pair(n, hard)); } ; 27 | void iret(void); 28 | bool chk_irq(void); 29 | private: 30 | void save_regs(bool chpl, uint16_t cs); 31 | void restore_regs(void); 32 | }; 33 | 34 | #endif 35 | -------------------------------------------------------------------------------- /include/emulator/ui.hpp: -------------------------------------------------------------------------------- 1 | #ifndef _UI_H 2 | #define _UI_H 3 | 4 | #include 5 | #include "common.hpp" 6 | #include "device/vga.hpp" 7 | #include "device/keyboard.hpp" 8 | #include "device/mouse.hpp" 9 | #include "hardware/memory.hpp" // A20 gate 10 | 11 | struct UISetting { 12 | bool enable; 13 | bool full; 14 | bool vm; 15 | }; 16 | 17 | class UI { 18 | private: 19 | UISetting set; 20 | VGA *vga; 21 | Keyboard *keyboard; 22 | 23 | bool working; 24 | bool capture; 25 | uint16_t size_x, size_y; 26 | uint8_t *image; 27 | 28 | struct { 29 | int16_t X, Y; 30 | bool click[2]; 31 | }; 32 | 33 | public: 34 | UI(Memory *m, UISetting set); 35 | ~UI(); 36 | VGA *get_vga(void) const { return vga; }; 37 | Keyboard *get_keyboard(void) const { return keyboard; }; 38 | bool get_status(void) const { return working; }; 39 | private: 40 | void ui_main(void); 41 | static void keyboard_callback(GLFWwindow *window, int key, int scancode, int action, int mods); 42 | static void mouse_callback(GLFWwindow *window, int button, int action, int mods); 43 | static void cursorpos_callback(GLFWwindow *window, double xpos, double ypos); 44 | static void window_size_callback(GLFWwindow* window, int width, int height); 45 | //static void cursorenter_callback(GLFWwindow *window, int entered); 46 | }; 47 | 48 | #endif 49 | -------------------------------------------------------------------------------- /include/hardware/cr.hpp: -------------------------------------------------------------------------------- 1 | #ifndef _CR_H 2 | #define _CR_H 3 | 4 | #include "common.hpp" 5 | 6 | class CR { 7 | private: 8 | union { 9 | uint32_t raw; 10 | struct { 11 | uint32_t PE : 1; 12 | uint32_t MP : 1; 13 | uint32_t EM : 1; 14 | uint32_t TS : 1; 15 | uint32_t ET : 1; 16 | uint32_t NE : 1; 17 | uint32_t : 10; 18 | uint32_t WP : 1; 19 | uint32_t : 1; 20 | uint32_t AM : 1; 21 | uint32_t : 10; 22 | uint32_t NW : 1; 23 | uint32_t CD : 1; 24 | uint32_t PG : 1; 25 | }; 26 | } cr0; 27 | 28 | union { 29 | uint32_t raw; 30 | } cr1; 31 | 32 | union { 33 | uint32_t raw; 34 | } cr2; 35 | 36 | union { 37 | uint32_t raw; 38 | struct { 39 | uint32_t : 3; 40 | uint32_t PWT : 1; 41 | uint32_t PCD : 1; 42 | uint32_t : 7; 43 | uint32_t PageDirBase : 20; 44 | }; 45 | } cr3; 46 | 47 | union { 48 | uint32_t raw; 49 | struct { 50 | uint32_t VME : 1; 51 | uint32_t PVI : 1; 52 | uint32_t TSD : 1; 53 | uint32_t DE : 1; 54 | uint32_t PSE: 1; 55 | uint32_t PAE: 1; 56 | uint32_t MCE: 1; 57 | uint32_t PGE: 1; 58 | uint32_t PCE: 1; 59 | uint32_t OSFXSR: 1; 60 | uint32_t OSXMMEXCPT: 1; 61 | uint32_t : 21; 62 | }; 63 | } cr4; 64 | 65 | uint32_t* cr[5]; 66 | 67 | public: 68 | CR() { 69 | cr[0] = &cr0.raw; 70 | cr[1] = &cr1.raw; 71 | cr[2] = &cr2.raw; 72 | cr[3] = &cr3.raw; 73 | cr[4] = &cr4.raw; 74 | for(int i=0; i<5; i++) 75 | set_crn(i, 0); 76 | }; 77 | 78 | uint32_t get_crn(uint8_t n) { if(n >= sizeof(cr)) ERROR(""); return *cr[n]; }; 79 | void set_crn(uint8_t n, uint32_t v) { if(n >= sizeof(cr)) ERROR(""); *cr[n] = v; }; 80 | protected: 81 | bool is_protected(void) { return cr0.PE; }; 82 | bool is_ena_paging(void) { return cr0.PG; }; 83 | uint32_t get_pdir_base(void) { return cr3.PageDirBase; }; 84 | }; 85 | 86 | #endif 87 | -------------------------------------------------------------------------------- /include/hardware/eflags.hpp: -------------------------------------------------------------------------------- 1 | #ifndef _EFLAGS_H 2 | #define _EFLAGS_H 3 | 4 | #include "common.hpp" 5 | 6 | union EFLAGS { 7 | uint32_t reg32; 8 | uint16_t reg16; 9 | 10 | struct { 11 | uint32_t CF : 1; 12 | uint32_t : 1; // 1 13 | uint32_t PF : 1; 14 | uint32_t : 1; // 0 15 | uint32_t AF : 1; 16 | uint32_t : 1; // 0 17 | uint32_t ZF : 1; 18 | uint32_t SF : 1; 19 | uint32_t TF : 1; 20 | uint32_t IF : 1; 21 | uint32_t DF : 1; 22 | uint32_t OF : 1; 23 | uint32_t IOPL : 2; 24 | uint32_t NT : 1; 25 | uint32_t : 1; // 0 26 | uint32_t RF : 1; 27 | uint32_t VM : 1; 28 | uint32_t AC : 1; 29 | uint32_t VIF : 1; 30 | uint32_t VIP : 1; 31 | uint32_t ID : 1; 32 | }; 33 | }; 34 | 35 | class Eflags { 36 | private: 37 | EFLAGS eflags; 38 | 39 | public: 40 | uint32_t get_eflags(void){ return eflags.reg32; }; 41 | void set_eflags(uint32_t v){ eflags.reg32 = v; }; 42 | uint16_t get_flags(void){ return eflags.reg16; }; 43 | void set_flags(uint16_t v){ eflags.reg16 = v; }; 44 | 45 | bool is_carry(void){ return eflags.CF; }; 46 | bool is_parity(void){ return eflags.PF; }; 47 | bool is_zero(void){ return eflags.ZF; }; 48 | bool is_sign(void){ return eflags.SF; }; 49 | bool is_overflow(void){ return eflags.OF; }; 50 | bool is_interrupt(void){ return eflags.IF; }; 51 | bool is_direction(void){ return eflags.DF; }; 52 | void set_carry(bool carry){ eflags.CF = carry; }; 53 | void set_parity(bool parity){ eflags.PF = parity; }; 54 | void set_zero(bool zero){ eflags.ZF = zero; }; 55 | void set_sign(bool sign){ eflags.SF = sign; }; 56 | void set_overflow(bool over){ eflags.OF = over; }; 57 | void set_interrupt(bool interrupt){ eflags.IF = interrupt; }; 58 | void set_direction(bool dir){ eflags.DF = dir; }; 59 | 60 | template uint32_t update_eflags_add(T v1, uint32_t v2); 61 | template uint32_t update_eflags_or(T v1, uint32_t v2); 62 | template uint32_t update_eflags_and(T v1, uint32_t v2); 63 | template uint32_t update_eflags_sub(T v1, uint32_t v2); 64 | template uint32_t update_eflags_mul(T v1, uint32_t v2); 65 | template uint32_t update_eflags_imul(T v1, int32_t v2); 66 | template uint32_t update_eflags_shl(T v, uint8_t c); 67 | template uint32_t update_eflags_shr(T v, uint8_t c); 68 | private: 69 | bool chk_parity(uint8_t v); 70 | }; 71 | 72 | #endif 73 | -------------------------------------------------------------------------------- /include/hardware/hardware.hpp: -------------------------------------------------------------------------------- 1 | #ifndef _HARDWARE_H 2 | #define _HARDWARE_H 3 | 4 | #include "common.hpp" 5 | #include "processor.hpp" 6 | #include "memory.hpp" 7 | #include "io.hpp" 8 | 9 | class Hardware : public Processor, public Memory, public IO { 10 | public: 11 | Hardware(size_t size = 0) : Memory(size), IO(this) {}; 12 | }; 13 | 14 | #endif 15 | -------------------------------------------------------------------------------- /include/hardware/io.hpp: -------------------------------------------------------------------------------- 1 | #ifndef _IO_H 2 | #define _IO_H 3 | 4 | #include 5 | #include "common.hpp" 6 | #include "memory.hpp" 7 | #include "device/dev_io.hpp" 8 | 9 | class IO { 10 | private: 11 | Memory *memory; 12 | std::unordered_map port_io; 13 | std::unordered_map port_io_map; 14 | std::unordered_map mem_io; 15 | std::unordered_map mem_io_map; 16 | 17 | public: 18 | IO(Memory *mem) { memory = mem; }; 19 | ~IO(); 20 | 21 | void set_portio(uint16_t addr, size_t len, PortIO *dev); 22 | uint32_t in_io32(uint16_t addr); 23 | uint16_t in_io16(uint16_t addr); 24 | uint8_t in_io8(uint16_t addr); 25 | void out_io32(uint16_t addr, uint32_t v); 26 | void out_io16(uint16_t addr, uint16_t v); 27 | void out_io8(uint16_t addr, uint8_t v); 28 | 29 | void set_memio(uint32_t addr, size_t len, MemoryIO *dev); 30 | uint32_t chk_memio(uint32_t addr) { return get_memio_base(addr); }; 31 | uint32_t read_memio32(uint32_t base, uint32_t offset); 32 | uint16_t read_memio16(uint32_t base, uint32_t offset); 33 | uint8_t read_memio8(uint32_t base, uint32_t offset); 34 | void write_memio32(uint32_t base, uint32_t offset, uint32_t v); 35 | void write_memio16(uint32_t base, uint32_t offset, uint16_t v); 36 | void write_memio8(uint32_t base, uint32_t offset, uint8_t v); 37 | private: 38 | uint16_t get_portio_base(uint16_t addr); 39 | uint32_t get_memio_base(uint32_t addr); 40 | }; 41 | 42 | #endif 43 | -------------------------------------------------------------------------------- /include/hardware/memory.hpp: -------------------------------------------------------------------------------- 1 | #ifndef _MEMORY_H 2 | #define _MEMORY_H 3 | 4 | #include "common.hpp" 5 | 6 | #define DEFAULT_MEMORY_SIZE (1*KB) 7 | #define ASSERT_RANGE(addr, len) ASSERT(addr+len-1 < mem_size) 8 | #define IN_RANGE(addr, len) (addr+len-1 < mem_size) 9 | 10 | class Memory { 11 | private: 12 | uint32_t mem_size; 13 | uint8_t *memory; 14 | bool a20gate; 15 | 16 | public: 17 | Memory(size_t size = DEFAULT_MEMORY_SIZE); 18 | ~Memory(); 19 | 20 | void dump_mem(uint32_t addr, size_t size); 21 | 22 | size_t read_data(void *dst, uint32_t src_addr, size_t size); 23 | size_t write_data(uint32_t dst_addr, void *src, size_t size); 24 | 25 | uint32_t read_mem32(uint32_t addr){ return IN_RANGE(addr, 4) ? *((uint32_t*)&memory[addr]) : 0; }; 26 | uint16_t read_mem16(uint32_t addr){ return IN_RANGE(addr, 2) ? *((uint16_t*)&memory[addr]) : 0; }; 27 | uint8_t read_mem8(uint32_t addr){ return IN_RANGE(addr, 1) ? memory[addr] : 0; }; 28 | 29 | void write_mem32(uint32_t addr, uint32_t v){ if(IN_RANGE(addr, 4)) *((uint32_t*)&memory[addr]) = v; }; 30 | void write_mem16(uint32_t addr, uint16_t v){ if(IN_RANGE(addr, 2)) *((uint16_t*)&memory[addr]) = v; }; 31 | void write_mem8(uint32_t addr, uint8_t v){ if(IN_RANGE(addr, 1)) memory[addr] = v; }; 32 | 33 | bool is_ena_a20gate(void) { return a20gate; }; 34 | void set_a20gate(bool ena) { a20gate = ena; }; 35 | }; 36 | 37 | #endif 38 | -------------------------------------------------------------------------------- /include/hardware/processor.hpp: -------------------------------------------------------------------------------- 1 | #ifndef _PROCESSOR_H 2 | #define _PROCESSOR_H 3 | 4 | #include "common.hpp" 5 | #include "eflags.hpp" 6 | #include "cr.hpp" 7 | 8 | enum reg32_t { EAX, ECX, EDX, EBX, ESP, EBP, ESI, EDI, GPREGS_COUNT }; 9 | enum reg16_t { AX, CX, DX, BX, SP, BP, SI, DI }; 10 | enum reg8_t { AL, CL, DL, BL, AH, CH, DH, BH }; 11 | //enum reg8l_t { AL, CL, DL, BL, SPL, BPL, SIL, DIL }; 12 | enum sgreg_t { ES, CS, SS, DS, FS, GS, SGREGS_COUNT }; 13 | enum dtreg_t { GDTR, IDTR, LDTR, TR, DTREGS_COUNT }; 14 | 15 | union GPRegister { 16 | uint32_t reg32; 17 | uint16_t reg16; 18 | struct { 19 | uint8_t reg8_l; 20 | uint8_t reg8_h; 21 | }; 22 | }; 23 | 24 | struct SGRegCache { 25 | uint32_t base; 26 | uint32_t limit : 20; 27 | 28 | union { 29 | uint16_t raw : 12; 30 | 31 | union { 32 | struct { 33 | uint8_t : 1; 34 | uint8_t w : 1; // 0:r, 1:rw 35 | uint8_t exd: 1; 36 | uint8_t : 1; 37 | } data; 38 | struct { 39 | uint8_t : 1; 40 | uint8_t r : 1; // 0:x, 1;xr 41 | uint8_t cnf : 1; 42 | uint8_t : 1; 43 | } code; 44 | struct{ 45 | uint8_t A : 1; 46 | uint8_t : 2; 47 | uint8_t segc : 1; 48 | }; 49 | } type; 50 | 51 | struct { 52 | uint8_t : 4; 53 | uint8_t S : 1; 54 | uint8_t DPL : 2; 55 | uint8_t P : 1; 56 | 57 | uint8_t AVL : 1; 58 | uint8_t : 1; 59 | uint8_t DB : 1; 60 | uint8_t G : 1; 61 | }; 62 | } flags; 63 | }; 64 | 65 | struct SGRegister { 66 | union { 67 | uint16_t raw; 68 | struct { 69 | uint16_t RPL : 2; 70 | uint16_t TI : 1; 71 | uint16_t index : 13; 72 | }; 73 | }; 74 | 75 | SGRegCache cache; 76 | }; 77 | 78 | struct DTRegister { 79 | uint16_t selector; // LDTR, TR 80 | uint32_t base; 81 | uint16_t limit; 82 | }; 83 | 84 | class Processor : public Eflags, public CR { 85 | private: 86 | union { 87 | uint32_t eip; 88 | uint16_t ip; 89 | }; 90 | 91 | GPRegister gpregs[GPREGS_COUNT]; 92 | SGRegister sgregs[SGREGS_COUNT]; 93 | DTRegister dtregs[DTREGS_COUNT]; 94 | 95 | bool halt; 96 | 97 | public: 98 | Processor(); 99 | void dump_regs(void); 100 | 101 | uint32_t get_eip(void){ return eip; }; 102 | uint32_t get_ip(void){ return ip; }; 103 | uint32_t get_gpreg(enum reg32_t n){ ASSERT(n 5 | #include "common.hpp" 6 | #include "instruction.hpp" 7 | 8 | class InstrBase : public ExecInstr, public ParseInstr, public EmuInstr { 9 | public: 10 | InstrBase(); 11 | void set_chsz_ad(bool ad){ chsz_ad = ad; }; 12 | protected: 13 | void set_funcflag(uint16_t opcode, instrfunc_t func, uint8_t flags); 14 | 15 | void add_rm8_r8(void); 16 | void add_r8_rm8(void); 17 | void add_al_imm8(void); 18 | void or_rm8_r8(void); 19 | void or_r8_rm8(void); 20 | void or_al_imm8(void); 21 | void and_rm8_r8(void); 22 | void and_r8_rm8(void); 23 | void and_al_imm8(void); 24 | void sub_rm8_r8(void); 25 | void sub_r8_rm8(void); 26 | void sub_al_imm8(void); 27 | void xor_rm8_r8(void); 28 | void xor_r8_rm8(void); 29 | void xor_al_imm8(void); 30 | void cmp_rm8_r8(void); 31 | void cmp_r8_rm8(void); 32 | void cmp_al_imm8(void); 33 | void jo_rel8(void); 34 | void jno_rel8(void); 35 | void jb_rel8(void); 36 | void jnb_rel8(void); 37 | void jz_rel8(void); 38 | void jnz_rel8(void); 39 | void jbe_rel8(void); 40 | void ja_rel8(void); 41 | void js_rel8(void); 42 | void jns_rel8(void); 43 | void jp_rel8(void); 44 | void jnp_rel8(void); 45 | void jl_rel8(void); 46 | void jnl_rel8(void); 47 | void jle_rel8(void); 48 | void jnle_rel8(void); 49 | void test_rm8_r8(void); 50 | void xchg_r8_rm8(void); 51 | void mov_rm8_r8(void); 52 | void mov_r8_rm8(void); 53 | void mov_sreg_rm16(void); 54 | void nop(void); 55 | void mov_al_moffs8(void); 56 | void mov_moffs8_al(void); 57 | void test_al_imm8(void); 58 | void mov_r8_imm8(void); 59 | void mov_rm8_imm8(void); 60 | void retf(void); 61 | void int3(void); 62 | void int_imm8(void); 63 | void iret(void); 64 | void in_al_imm8(void); 65 | void out_imm8_al(void); 66 | void jmp(void); 67 | void in_al_dx(void); 68 | void out_dx_al(void); 69 | void cli(void); 70 | void sti(void); 71 | void cld(void); 72 | void std(void); 73 | void hlt(void); 74 | void ltr_rm16(void); 75 | void mov_r32_crn(void); 76 | void mov_crn_r32(void); 77 | void seto_rm8(void); 78 | void setno_rm8(void); 79 | void setb_rm8(void); 80 | void setnb_rm8(void); 81 | void setz_rm8(void); 82 | void setnz_rm8(void); 83 | void setbe_rm8(void); 84 | void seta_rm8(void); 85 | void sets_rm8(void); 86 | void setns_rm8(void); 87 | void setp_rm8(void); 88 | void setnp_rm8(void); 89 | void setl_rm8(void); 90 | void setnl_rm8(void); 91 | void setle_rm8(void); 92 | void setnle_rm8(void); 93 | 94 | void code_80(void); 95 | virtual void code_81(void) = 0; 96 | void code_82(void); 97 | virtual void code_83(void) = 0; 98 | void code_c0(void); 99 | void code_f6(void); 100 | virtual void code_f7(void) = 0; 101 | virtual void code_ff(void) = 0; 102 | virtual void code_0f00(void) = 0; 103 | virtual void code_0f01(void) = 0; 104 | 105 | // 0x80, 0x82 106 | void add_rm8_imm8(void); 107 | void or_rm8_imm8(void); 108 | void adc_rm8_imm8(void); 109 | void sbb_rm8_imm8(void); 110 | void and_rm8_imm8(void); 111 | void sub_rm8_imm8(void); 112 | void xor_rm8_imm8(void); 113 | void cmp_rm8_imm8(void); 114 | 115 | //0xc0 116 | void shl_rm8_imm8(void); 117 | void shr_rm8_imm8(void); 118 | void sal_rm8_imm8(void); 119 | void sar_rm8_imm8(void); 120 | 121 | //0xf6 122 | void test_rm8_imm8(void); 123 | void not_rm8(void); 124 | void neg_rm8(void); 125 | void mul_ax_al_rm8(void); 126 | void imul_ax_al_rm8(void); 127 | void div_al_ah_rm8(void); 128 | void idiv_al_ah_rm8(void); 129 | }; 130 | 131 | class Instr16 : public InstrBase { 132 | public: 133 | Instr16(Emulator *e, InstrData *id); 134 | private: 135 | void add_rm16_r16(void); 136 | void add_r16_rm16(void); 137 | void add_ax_imm16(void); 138 | void push_es(void); 139 | void pop_es(void); 140 | void or_rm16_r16(void); 141 | void or_r16_rm16(void); 142 | void or_ax_imm16(void); 143 | void push_ss(void); 144 | void pop_ss(void); 145 | void push_ds(void); 146 | void pop_ds(void); 147 | void and_rm16_r16(void); 148 | void and_r16_rm16(void); 149 | void and_ax_imm16(void); 150 | void sub_rm16_r16(void); 151 | void sub_r16_rm16(void); 152 | void sub_ax_imm16(void); 153 | void xor_rm16_r16(void); 154 | void xor_r16_rm16(void); 155 | void xor_ax_imm16(void); 156 | void cmp_rm16_r16(void); 157 | void cmp_r16_rm16(void); 158 | void cmp_ax_imm16(void); 159 | void inc_r16(void); 160 | void dec_r16(void); 161 | void push_r16(void); 162 | void pop_r16(void); 163 | void pusha(void); 164 | void popa(void); 165 | void push_imm16(void); 166 | void imul_r16_rm16_imm16(void); 167 | void push_imm8(void); 168 | void imul_r16_rm16_imm8(void); 169 | void test_rm16_r16(void); 170 | void xchg_r16_rm16(void); 171 | void mov_rm16_r16(void); 172 | void mov_r16_rm16(void); 173 | void mov_rm16_sreg(void); 174 | void lea_r16_m16(void); 175 | void xchg_r16_ax(void); 176 | void cbw(void); 177 | void cwd(void); 178 | void callf_ptr16_16(void); 179 | void pushf(void); 180 | void popf(void); 181 | void mov_ax_moffs16(void); 182 | void mov_moffs16_ax(void); 183 | void cmps_m8_m8(void); 184 | void cmps_m16_m16(void); 185 | void test_ax_imm16(void); 186 | void mov_r16_imm16(void); 187 | void ret(void); 188 | void leave(void); 189 | void mov_rm16_imm16(void); 190 | void in_ax_imm8(void); 191 | void out_imm8_ax(void); 192 | void call_rel16(void); 193 | void jmp_rel16(void); 194 | void jmpf_ptr16_16(void); 195 | void in_ax_dx(void); 196 | void out_dx_ax(void); 197 | void jo_rel16(void); 198 | void jno_rel16(void); 199 | void jb_rel16(void); 200 | void jnb_rel16(void); 201 | void jz_rel16(void); 202 | void jnz_rel16(void); 203 | void jbe_rel16(void); 204 | void ja_rel16(void); 205 | void js_rel16(void); 206 | void jns_rel16(void); 207 | void jp_rel16(void); 208 | void jnp_rel16(void); 209 | void jl_rel16(void); 210 | void jnl_rel16(void); 211 | void jle_rel16(void); 212 | void jnle_rel16(void); 213 | void imul_r16_rm16(void); 214 | void movzx_r16_rm8(void); 215 | void movzx_r16_rm16(void); 216 | void movsx_r16_rm8(void); 217 | void movsx_r16_rm16(void); 218 | 219 | void code_81(void); 220 | void code_83(void); 221 | void code_c1(void); 222 | void code_d3(void); 223 | void code_f7(void); 224 | void code_ff(void); 225 | void code_0f00(void); 226 | void code_0f01(void); 227 | 228 | // 0x81 229 | void add_rm16_imm16(void); 230 | void or_rm16_imm16(void); 231 | void adc_rm16_imm16(void); 232 | void sbb_rm16_imm16(void); 233 | void and_rm16_imm16(void); 234 | void sub_rm16_imm16(void); 235 | void xor_rm16_imm16(void); 236 | void cmp_rm16_imm16(void); 237 | 238 | // 0x83 239 | void add_rm16_imm8(void); 240 | void or_rm16_imm8(void); 241 | void adc_rm16_imm8(void); 242 | void sbb_rm16_imm8(void); 243 | void and_rm16_imm8(void); 244 | void sub_rm16_imm8(void); 245 | void xor_rm16_imm8(void); 246 | void cmp_rm16_imm8(void); 247 | 248 | //0xc1 249 | void shl_rm16_imm8(void); 250 | void shr_rm16_imm8(void); 251 | void sal_rm16_imm8(void); 252 | void sar_rm16_imm8(void); 253 | 254 | //0xd3 255 | void shl_rm16_cl(void); 256 | void shr_rm16_cl(void); 257 | void sal_rm16_cl(void); 258 | void sar_rm16_cl(void); 259 | 260 | //0xf7 261 | void test_rm16_imm16(void); 262 | void not_rm16(void); 263 | void neg_rm16(void); 264 | void mul_dx_ax_rm16(void); 265 | void imul_dx_ax_rm16(void); 266 | void div_dx_ax_rm16(void); 267 | void idiv_dx_ax_rm16(void); 268 | 269 | //0xff 270 | void inc_rm16(void); 271 | void dec_rm16(void); 272 | void call_rm16(void); 273 | void callf_m16_16(void); 274 | void jmp_rm16(void); 275 | void jmpf_m16_16(void); 276 | void push_rm16(void); 277 | 278 | //0x0f01 279 | void lgdt_m24(void); 280 | void lidt_m24(void); 281 | }; 282 | 283 | class Instr32 : public InstrBase { 284 | public: 285 | Instr32(Emulator *e, InstrData *id); 286 | private: 287 | void add_rm32_r32(void); 288 | void add_r32_rm32(void); 289 | void add_eax_imm32(void); 290 | void push_es(void); 291 | void pop_es(void); 292 | void or_rm32_r32(void); 293 | void or_r32_rm32(void); 294 | void or_eax_imm32(void); 295 | void push_ss(void); 296 | void pop_ss(void); 297 | void push_ds(void); 298 | void pop_ds(void); 299 | void and_rm32_r32(void); 300 | void and_r32_rm32(void); 301 | void and_eax_imm32(void); 302 | void sub_rm32_r32(void); 303 | void sub_r32_rm32(void); 304 | void sub_eax_imm32(void); 305 | void xor_rm32_r32(void); 306 | void xor_r32_rm32(void); 307 | void xor_eax_imm32(void); 308 | void cmp_rm32_r32(void); 309 | void cmp_r32_rm32(void); 310 | void cmp_eax_imm32(void); 311 | void inc_r32(void); 312 | void dec_r32(void); 313 | void push_r32(void); 314 | void pop_r32(void); 315 | void pushad(void); 316 | void popad(void); 317 | void push_imm32(void); 318 | void imul_r32_rm32_imm32(void); 319 | void push_imm8(void); 320 | void imul_r32_rm32_imm8(void); 321 | void test_rm32_r32(void); 322 | void xchg_r32_rm32(void); 323 | void mov_rm32_r32(void); 324 | void mov_r32_rm32(void); 325 | void mov_rm32_sreg(void); 326 | void lea_r32_m32(void); 327 | void xchg_r32_eax(void); 328 | void cwde(void); 329 | void cdq(void); 330 | void callf_ptr16_32(void); 331 | void pushf(void); 332 | void popf(void); 333 | void mov_eax_moffs32(void); 334 | void mov_moffs32_eax(void); 335 | void cmps_m8_m8(void); 336 | void cmps_m32_m32(void); 337 | void test_eax_imm32(void); 338 | void mov_r32_imm32(void); 339 | void ret(void); 340 | void leave(void); 341 | void mov_rm32_imm32(void); 342 | void in_eax_imm8(void); 343 | void out_imm8_eax(void); 344 | void call_rel32(void); 345 | void jmp_rel32(void); 346 | void jmpf_ptr16_32(void); 347 | void in_eax_dx(void); 348 | void out_dx_eax(void); 349 | void jo_rel32(void); 350 | void jno_rel32(void); 351 | void jb_rel32(void); 352 | void jnb_rel32(void); 353 | void jz_rel32(void); 354 | void jnz_rel32(void); 355 | void jbe_rel32(void); 356 | void ja_rel32(void); 357 | void js_rel32(void); 358 | void jns_rel32(void); 359 | void jp_rel32(void); 360 | void jnp_rel32(void); 361 | void jl_rel32(void); 362 | void jnl_rel32(void); 363 | void jle_rel32(void); 364 | void jnle_rel32(void); 365 | void imul_r32_rm32(void); 366 | void movzx_r32_rm8(void); 367 | void movzx_r32_rm16(void); 368 | void movsx_r32_rm8(void); 369 | void movsx_r32_rm16(void); 370 | 371 | void code_81(void); 372 | void code_83(void); 373 | void code_c1(void); 374 | void code_d3(void); 375 | void code_f7(void); 376 | void code_ff(void); 377 | void code_0f00(void); 378 | void code_0f01(void); 379 | 380 | // 0x81 381 | void add_rm32_imm32(void); 382 | void or_rm32_imm32(void); 383 | void adc_rm32_imm32(void); 384 | void sbb_rm32_imm32(void); 385 | void and_rm32_imm32(void); 386 | void sub_rm32_imm32(void); 387 | void xor_rm32_imm32(void); 388 | void cmp_rm32_imm32(void); 389 | 390 | // 0x83 391 | void add_rm32_imm8(void); 392 | void or_rm32_imm8(void); 393 | void adc_rm32_imm8(void); 394 | void sbb_rm32_imm8(void); 395 | void and_rm32_imm8(void); 396 | void sub_rm32_imm8(void); 397 | void xor_rm32_imm8(void); 398 | void cmp_rm32_imm8(void); 399 | 400 | //0xc1 401 | void shl_rm32_imm8(void); 402 | void shr_rm32_imm8(void); 403 | void sal_rm32_imm8(void); 404 | void sar_rm32_imm8(void); 405 | 406 | //0xd3 407 | void shl_rm32_cl(void); 408 | void shr_rm32_cl(void); 409 | void sal_rm32_cl(void); 410 | void sar_rm32_cl(void); 411 | 412 | //0xf7 413 | void test_rm32_imm32(void); 414 | void not_rm32(void); 415 | void neg_rm32(void); 416 | void mul_edx_eax_rm32(void); 417 | void imul_edx_eax_rm32(void); 418 | void div_edx_eax_rm32(void); 419 | void idiv_edx_eax_rm32(void); 420 | 421 | //0xff 422 | void inc_rm32(void); 423 | void dec_rm32(void); 424 | void call_rm32(void); 425 | void callf_m16_32(void); 426 | void jmp_rm32(void); 427 | void jmpf_m16_32(void); 428 | void push_rm32(void); 429 | 430 | //0x0f01 431 | void lgdt_m32(void); 432 | void lidt_m32(void); 433 | }; 434 | 435 | #endif 436 | -------------------------------------------------------------------------------- /include/instruction/instruction.hpp: -------------------------------------------------------------------------------- 1 | #ifndef _INSTRUCTION_H 2 | #define _INSTRUCTION_H 3 | 4 | #include 5 | #include "common.hpp" 6 | #include "emulator/emulator.hpp" 7 | 8 | #define EMU get_emu() 9 | #define GET_EIP() EMU->get_eip() 10 | #define GET_IP() EMU->get_ip() 11 | #define SET_EIP(v) EMU->set_eip(v) 12 | #define SET_IP(v) EMU->set_ip(v) 13 | #define UPDATE_EIP(v) EMU->update_eip(v) 14 | #define UPDATE_IP(v) EMU->update_ip(v) 15 | #define GET_GPREG(reg) EMU->get_gpreg(reg) 16 | #define SET_GPREG(reg, v) EMU->set_gpreg(reg, v) 17 | #define UPDATE_GPREG(reg, v) EMU->update_gpreg(reg, v) 18 | #define EFLAGS_UPDATE_ADD(v1, v2) EMU->update_eflags_add(v1, v2) 19 | #define EFLAGS_UPDATE_OR(v1, v2) EMU->update_eflags_or(v1, v2) 20 | #define EFLAGS_UPDATE_AND(v1, v2) EMU->update_eflags_and(v1, v2) 21 | #define EFLAGS_UPDATE_SUB(v1, v2) EMU->update_eflags_sub(v1, v2) 22 | #define EFLAGS_UPDATE_MUL(v1, v2) EMU->update_eflags_mul(v1, v2) 23 | #define EFLAGS_UPDATE_IMUL(v1, v2) EMU->update_eflags_imul(v1, v2) 24 | #define EFLAGS_UPDATE_SHL(v1, v2) EMU->update_eflags_shl(v1, v2) 25 | #define EFLAGS_UPDATE_SHR(v1, v2) EMU->update_eflags_shr(v1, v2) 26 | #define EFLAGS_CF EMU->is_carry() 27 | #define EFLAGS_PF EMU->is_parity() 28 | #define EFLAGS_ZF EMU->is_zero() 29 | #define EFLAGS_SF EMU->is_sign() 30 | #define EFLAGS_OF EMU->is_overflow() 31 | #define EFLAGS_DF EMU->is_direction() 32 | #define READ_MEM32(addr) EMU->get_data32(select_segment(), addr) 33 | #define READ_MEM16(addr) EMU->get_data16(select_segment(), addr) 34 | #define READ_MEM8(addr) EMU->get_data8(select_segment(), addr) 35 | #define WRITE_MEM32(addr, v) EMU->put_data32(select_segment(), addr, v) 36 | #define WRITE_MEM16(addr, v) EMU->put_data16(select_segment(), addr, v) 37 | #define WRITE_MEM8(addr, v) EMU->put_data8(select_segment(), addr, v) 38 | #define PUSH32(v) EMU->push32(v) 39 | #define PUSH16(v) EMU->push16(v) 40 | #define POP32() EMU->pop32() 41 | #define POP16() EMU->pop16() 42 | 43 | #define PREFIX (instr->prefix) 44 | #define OPCODE (instr->opcode) 45 | #define _MODRM (instr->_modrm) 46 | #define MOD (instr->modrm.mod) 47 | #define REG (instr->modrm.reg) 48 | #define RM (instr->modrm.rm) 49 | #define _SIB (instr->_sib) 50 | #define SCALE (instr->sib.scale) 51 | #define INDEX (instr->sib.index) 52 | #define BASE (instr->sib.base) 53 | #define DISP32 (instr->disp32) 54 | #define DISP16 (instr->disp16) 55 | #define DISP8 (instr->disp8) 56 | #define IMM32 (instr->imm32) 57 | #define IMM16 (instr->imm16) 58 | #define IMM8 (instr->imm8) 59 | #define PTR16 (instr->ptr16) 60 | #define MOFFS (instr->moffs) 61 | #define PRE_SEGMENT (instr->pre_segment) 62 | #define PRE_REPEAT (instr->pre_repeat) 63 | #define SEGMENT (instr->segment) 64 | 65 | #define MAX_OPCODE 0x200 66 | 67 | struct ModRM { 68 | uint8_t rm : 3; 69 | uint8_t reg : 3; 70 | uint8_t mod : 2; 71 | }; 72 | 73 | struct SIB { 74 | uint8_t base : 3; 75 | uint8_t index : 3; 76 | uint8_t scale : 2; 77 | }; 78 | 79 | enum rep_t { NONE, REPZ, REPNZ }; 80 | 81 | struct InstrData { 82 | uint16_t prefix; 83 | sgreg_t pre_segment; 84 | rep_t pre_repeat; 85 | 86 | sgreg_t segment; 87 | uint16_t opcode; 88 | union { 89 | uint8_t _modrm; 90 | struct ModRM modrm; 91 | }; 92 | union { 93 | uint8_t _sib; 94 | struct SIB sib; 95 | }; 96 | union { 97 | int8_t disp8; 98 | int16_t disp16; 99 | int32_t disp32; 100 | }; 101 | union { 102 | int8_t imm8; 103 | int16_t imm16; 104 | int32_t imm32; 105 | }; 106 | int16_t ptr16; 107 | uint32_t moffs; 108 | }; 109 | 110 | class Instruction { 111 | protected: 112 | InstrData *instr; 113 | bool chsz_ad; 114 | private: 115 | Emulator *emu; 116 | bool mode32; 117 | 118 | public: 119 | Instruction() {}; 120 | Instruction(Emulator *e, InstrData *i, bool m) { emu = e; instr = i; mode32 = m; }; 121 | protected: 122 | Emulator* get_emu(void) { return emu; }; 123 | bool is_mode32(void) { return mode32; }; 124 | sgreg_t select_segment(void) { return instr->prefix ? PRE_SEGMENT : SEGMENT; }; 125 | }; 126 | 127 | 128 | class ExecInstr : protected virtual Instruction { 129 | protected: 130 | typedef void (ExecInstr::*instrfunc_t)(void); 131 | //std::map instrfuncs; 132 | instrfunc_t instrfuncs[MAX_OPCODE]; 133 | 134 | public: 135 | bool exec(void); 136 | protected: 137 | //ExecInstr(Emulator *e) : Instruction(e) {}; 138 | ExecInstr() { for(int i=0; i chk; 203 | InstrFlags chk[MAX_OPCODE]; 204 | 205 | public: 206 | //ParseInstr(Emulator *e) : Instruction(e) {}; 207 | void parse(void); 208 | uint8_t parse_prefix(void); 209 | private: 210 | void parse_opcode(void); 211 | void parse_modrm_sib_disp(void); 212 | void parse_modrm16(void); 213 | void parse_modrm32(void); 214 | void parse_moffs(void); 215 | }; 216 | 217 | class EmuInstr : protected virtual Instruction { 218 | public: 219 | void set_gdtr(uint32_t base, uint16_t limit){ EMU->set_dtreg(GDTR, 0, base, limit); }; 220 | void set_idtr(uint32_t base, uint16_t limit){ EMU->set_dtreg(IDTR, 0, base, limit); }; 221 | 222 | void set_ldtr(uint16_t sel); 223 | uint16_t get_ldtr(void) { return EMU->get_dtreg_selector(LDTR); }; 224 | void set_tr(uint16_t sel); 225 | uint16_t get_tr(void) { return EMU->get_dtreg_selector(TR); }; 226 | 227 | uint8_t type_descriptor(uint16_t sel); 228 | void switch_task(uint16_t sel); 229 | void jmpf(uint16_t sel, uint32_t eip); 230 | void callf(uint16_t sel, uint32_t eip); 231 | void retf(void); 232 | void iret(void); 233 | 234 | bool chk_ring(uint8_t DPL); 235 | }; 236 | 237 | #endif 238 | -------------------------------------------------------------------------------- /include/util/debug.hpp: -------------------------------------------------------------------------------- 1 | #ifndef _DEBUG_H 2 | #define _DEBUG_H 3 | 4 | #include 5 | #include 6 | 7 | #define DEBUG 8 | 9 | enum {F_ASSERT, F_ERROR, F_WARN, F_INFO, F_MSG}; 10 | 11 | #define DEBUG_PRINT(type, lv, fmt, ...) debug_print(type, __FILE__, __FUNCTION__, __LINE__, lv, fmt, ##__VA_ARGS__) 12 | 13 | #ifdef DEBUG 14 | #define ON_DEBUG(type, lv, fmt, ...) DEBUG_PRINT(type, lv, fmt, ##__VA_ARGS__) 15 | #define DEBUG_OPT "v:" 16 | #else 17 | #define ON_DEBUG(type, lv, fmt, ...) 18 | #define DEBUG_OPT 19 | #endif 20 | 21 | #define ASSERT(cond) if(!(cond)) DEBUG_PRINT(F_ASSERT, 0, #cond) 22 | #define ERROR(fmt, ...) DEBUG_PRINT(F_ERROR, 0, fmt, ##__VA_ARGS__) 23 | #define WARN(fmt, ...) ON_DEBUG(F_WARN, 0, fmt, ##__VA_ARGS__) 24 | #define INFO(lv, fmt, ...) ON_DEBUG(F_INFO, lv, fmt, ##__VA_ARGS__) 25 | #define DEBUG_MSG(lv, fmt, ...) ON_DEBUG(F_MSG, lv, fmt, ##__VA_ARGS__) 26 | #define MSG(fmt, ...) fprintf(stdout, fmt, ##__VA_ARGS__) 27 | 28 | void debug_print(const int type, const char *file, const char *function, int line, unsigned level, const char *fmt, ...); 29 | void set_debuglv(const char *verbose); 30 | 31 | #endif 32 | -------------------------------------------------------------------------------- /include/util/lru.hpp: -------------------------------------------------------------------------------- 1 | #ifndef _LRU_H 2 | #define _LRU_H 3 | 4 | #include "common.hpp" 5 | #include 6 | #include 7 | 8 | template class LRU { 9 | private: 10 | std::list< std::pair > item_list; 11 | std::unordered_map item_map; 12 | uint16_t size; 13 | 14 | public: 15 | LRU(uint16_t s){ size = s; }; 16 | void put(K key, V val); 17 | V get(K key); 18 | bool exist(K key){ return item_map.count(key) > 0;}; 19 | }; 20 | 21 | template void LRU::put(K key, V val){ 22 | auto it = item_map.find(key); 23 | 24 | if(it != item_map.end()){ 25 | item_list.erase(it->second); 26 | item_map.erase(it); 27 | } 28 | item_list.push_front(std::make_pair(key, val)); 29 | item_map.insert(make_pair(key, item_list.begin())); 30 | 31 | if(item_map.size() > size){ 32 | auto it = item_list.end(); 33 | item_map.erase((--it)->first); 34 | item_list.pop_back(); 35 | } 36 | } 37 | 38 | template V LRU::get(K key){ 39 | ASSERT(exist(key)); 40 | 41 | auto it = item_map[key]; 42 | item_list.splice(item_list.begin(), item_list, it); 43 | 44 | return it->second; 45 | } 46 | 47 | #endif 48 | -------------------------------------------------------------------------------- /instruction/Makefile: -------------------------------------------------------------------------------- 1 | TARGET := instruction.a 2 | 3 | SRCS := parse.cpp exec.cpp emu.cpp instr_base.cpp instr16.cpp instr32.cpp 4 | OBJS := $(SRCS:.cpp=.o) 5 | DEPS := $(SRCS:.cpp=.d) 6 | 7 | CXXFLAGS := -Wall -MMD -std=c++11 -I../include $(DEBUG) 8 | 9 | .PHONY: all 10 | all: $(TARGET) 11 | 12 | -include $(DEPS) 13 | 14 | $(TARGET): $(OBJS) 15 | $(AR) rcs $@ $^ 16 | 17 | .PHONY: clean 18 | clean: 19 | $(RM) $(DEPS) $(OBJS) $(TARGET) 20 | 21 | -------------------------------------------------------------------------------- /instruction/emu.cpp: -------------------------------------------------------------------------------- 1 | #include "instruction/instruction.hpp" 2 | #include "emulator/exception.hpp" 3 | #include "emulator/descriptor.hpp" 4 | 5 | uint8_t EmuInstr::type_descriptor(uint16_t sel){ 6 | uint32_t gdt_base; 7 | uint16_t gdt_limit; 8 | Descriptor desc; 9 | 10 | gdt_base = EMU->get_dtreg_base(GDTR); 11 | gdt_limit = EMU->get_dtreg_limit(GDTR); 12 | EXCEPTION(EXP_GP, sel > gdt_limit); 13 | 14 | EMU->read_data(&desc, gdt_base + sel, sizeof(Descriptor)); 15 | if(desc.S){ 16 | if(((SegDesc*)&desc)->type.segc) 17 | return TYPE_CODE; 18 | else 19 | return TYPE_DATA; 20 | } 21 | else if(desc.type == 3) 22 | return TYPE_TSS; 23 | 24 | return desc.type; 25 | } 26 | 27 | void EmuInstr::set_ldtr(uint16_t sel){ 28 | uint32_t gdt_base, base; 29 | uint16_t gdt_limit, limit; 30 | LDTDesc ldt; 31 | 32 | gdt_base = EMU->get_dtreg_base(GDTR); 33 | gdt_limit = EMU->get_dtreg_limit(GDTR); 34 | EXCEPTION(EXP_GP, sel > gdt_limit); 35 | 36 | EMU->read_data(&ldt, gdt_base + sel, sizeof(LDTDesc)); 37 | 38 | base = (ldt.base_h << 24) + (ldt.base_m << 16) + ldt.base_l; 39 | limit = (ldt.limit_h << 16) + ldt.limit_l; 40 | EMU->set_dtreg(LDTR, sel, base, limit); 41 | } 42 | 43 | void EmuInstr::set_tr(uint16_t sel){ 44 | uint32_t gdt_base, base; 45 | uint16_t gdt_limit, limit; 46 | TSSDesc tssdesc; 47 | 48 | gdt_base = EMU->get_dtreg_base(GDTR); 49 | gdt_limit = EMU->get_dtreg_limit(GDTR); 50 | EXCEPTION(EXP_GP, sel > gdt_limit); 51 | 52 | EMU->read_data(&tssdesc, gdt_base + sel, sizeof(TSSDesc)); 53 | EXCEPTION(EXP_GP, tssdesc.type != TYPE_TSS); 54 | 55 | base = (tssdesc.base_h << 24) + (tssdesc.base_m << 16) + tssdesc.base_l; 56 | limit = (tssdesc.limit_h << 16) + tssdesc.limit_l; 57 | 58 | EMU->set_dtreg(TR, sel, base, limit); 59 | } 60 | 61 | void EmuInstr::switch_task(uint16_t sel){ 62 | uint32_t base; 63 | uint16_t prev, limit; 64 | TSS old_tss, new_tss; 65 | 66 | prev = EMU->get_dtreg_selector(TR); 67 | base = EMU->get_dtreg_base(TR); 68 | limit = EMU->get_dtreg_limit(TR); 69 | EXCEPTION(EXP_GP, limit < sizeof(TSS)-1); 70 | 71 | EMU->read_data(&old_tss, base, sizeof(TSS)); 72 | old_tss.cr3 = EMU->get_crn(3); 73 | old_tss.eip = EMU->get_eip(); 74 | old_tss.eflags = EMU->get_eflags(); 75 | old_tss.eax = EMU->get_gpreg(EAX); 76 | old_tss.ecx = EMU->get_gpreg(ECX); 77 | old_tss.edx = EMU->get_gpreg(EDX); 78 | old_tss.ebx = EMU->get_gpreg(EBX); 79 | old_tss.esp = EMU->get_gpreg(ESP); 80 | old_tss.ebp = EMU->get_gpreg(EBP); 81 | old_tss.esi = EMU->get_gpreg(ESI); 82 | old_tss.edi = EMU->get_gpreg(EDI); 83 | old_tss.es = EMU->get_segment(ES); 84 | old_tss.cs = EMU->get_segment(CS); 85 | old_tss.ss = EMU->get_segment(SS); 86 | old_tss.ds = EMU->get_segment(DS); 87 | old_tss.fs = EMU->get_segment(FS); 88 | old_tss.gs = EMU->get_segment(GS); 89 | old_tss.ldtr = EMU->get_dtreg_selector(LDTR); 90 | EMU->write_data(base, &old_tss, sizeof(TSS)); 91 | 92 | set_tr(sel); 93 | 94 | base = EMU->get_dtreg_base(TR); 95 | limit = EMU->get_dtreg_limit(TR); 96 | EXCEPTION(EXP_GP, limit < sizeof(TSS)-1); 97 | 98 | EMU->read_data(&new_tss, base, sizeof(TSS)); 99 | new_tss.prev_sel = prev; 100 | EMU->write_data(base, &new_tss, sizeof(TSS)); 101 | EMU->set_crn(3, new_tss.cr3); 102 | EMU->set_eip(new_tss.eip); 103 | EMU->set_eflags(new_tss.eflags); 104 | EMU->set_gpreg(EAX, new_tss.eax); 105 | EMU->set_gpreg(ECX, new_tss.ecx); 106 | EMU->set_gpreg(EDX, new_tss.edx); 107 | EMU->set_gpreg(EBX, new_tss.ebx); 108 | EMU->set_gpreg(ESP, new_tss.esp); 109 | EMU->set_gpreg(EBP, new_tss.ebp); 110 | EMU->set_gpreg(ESI, new_tss.esi); 111 | EMU->set_gpreg(EDI, new_tss.edi); 112 | EMU->set_segment(ES, new_tss.es); 113 | EMU->set_segment(CS, new_tss.cs); 114 | EMU->set_segment(SS, new_tss.ss); 115 | EMU->set_segment(DS, new_tss.ds); 116 | EMU->set_segment(FS, new_tss.fs); 117 | EMU->set_segment(GS, new_tss.gs); 118 | set_ldtr(new_tss.ldtr); 119 | } 120 | 121 | void EmuInstr::jmpf(uint16_t sel, uint32_t eip){ 122 | if(EMU->is_protected()){ 123 | switch(type_descriptor(sel)){ 124 | case TYPE_CODE: 125 | goto jmp; 126 | case TYPE_TSS: 127 | switch_task(sel); 128 | return; 129 | } 130 | } 131 | 132 | jmp: 133 | INFO(2, "cs = 0x%04x, eip = 0x%08x", sel, eip); 134 | EMU->set_segment(CS, sel); 135 | EMU->set_eip(eip); 136 | } 137 | 138 | void EmuInstr::callf(uint16_t sel, uint32_t eip){ 139 | /* 140 | if(EMU->is_protected()){ 141 | switch(type_descriptor(sel)){ 142 | case TYPE_CODE: 143 | goto jmp; 144 | case TYPE_TSS: 145 | switch_task(sel); 146 | return; 147 | } 148 | } 149 | 150 | jmp: 151 | */ 152 | SGRegister cs; 153 | uint8_t RPL; 154 | 155 | cs.raw = EMU->get_segment(CS); 156 | RPL = sel & 3; 157 | 158 | if(cs.RPL ^ RPL){ 159 | EXCEPTION(EXP_GP, RPL < cs.RPL); 160 | EMU->push32(EMU->get_segment(SS)); 161 | EMU->push32(EMU->get_gpreg(ESP)); 162 | } 163 | 164 | EMU->push32(cs.raw); 165 | EMU->push32(EMU->get_eip()); 166 | 167 | EMU->set_segment(CS, sel); 168 | EMU->set_eip(eip); 169 | } 170 | 171 | void EmuInstr::retf(void){ 172 | SGRegister cs; 173 | uint8_t CPL; 174 | 175 | CPL = EMU->get_segment(CS) & 3; 176 | 177 | EMU->set_eip(EMU->pop32()); 178 | cs.raw = EMU->pop32(); 179 | 180 | if(cs.RPL ^ CPL){ 181 | uint32_t esp; 182 | uint16_t ss; 183 | 184 | esp = EMU->pop32(); 185 | ss = EMU->pop32(); 186 | EMU->set_gpreg(ESP, esp); 187 | EMU->set_segment(SS, ss); 188 | } 189 | 190 | EMU->set_segment(CS, cs.raw); 191 | } 192 | 193 | void EmuInstr::iret(void){ 194 | if(is_mode32()){ 195 | SGRegister cs; 196 | uint8_t CPL; 197 | EFLAGS eflags; 198 | 199 | CPL = EMU->get_segment(CS) & 3; 200 | 201 | EMU->set_eip(EMU->pop32()); 202 | cs.raw = EMU->pop32(); 203 | eflags.reg32 = EMU->pop32(); 204 | EMU->set_eflags(eflags.reg32); 205 | 206 | if(eflags.NT){ 207 | uint32_t base; 208 | TSS tss; 209 | 210 | base = EMU->get_dtreg_base(TR); 211 | EMU->read_data(&tss, base, sizeof(TSS)); 212 | switch_task(tss.prev_sel); 213 | } 214 | else{ 215 | if(cs.RPL > CPL){ 216 | uint32_t esp; 217 | uint16_t ss; 218 | 219 | esp = EMU->pop32(); 220 | ss = EMU->pop32(); 221 | EMU->set_gpreg(ESP, esp); 222 | EMU->set_segment(SS, ss); 223 | } 224 | } 225 | 226 | EMU->set_segment(CS, cs.raw); 227 | INFO(4, "iret (EIP : 0x%08x, CS : 0x%04x)", EMU->get_eip(), EMU->get_segment(CS)); 228 | } 229 | else{ 230 | uint16_t cs; 231 | EMU->set_ip(EMU->pop16()); 232 | cs = EMU->pop16(); 233 | EMU->set_flags(EMU->pop16()); 234 | 235 | EMU->set_segment(CS, cs); 236 | INFO(4, "iret (IP : 0x%04x, CS : 0x%04x)", EMU->get_ip(), EMU->get_segment(CS)); 237 | } 238 | } 239 | 240 | bool EmuInstr::chk_ring(uint8_t DPL){ 241 | uint8_t CPL; 242 | CPL = EMU->get_segment(CS) & 3; 243 | 244 | return CPL<=DPL; 245 | } 246 | -------------------------------------------------------------------------------- /instruction/exec.cpp: -------------------------------------------------------------------------------- 1 | #include "instruction/instruction.hpp" 2 | 3 | bool ExecInstr::exec(void){ 4 | uint16_t opcode = OPCODE; 5 | 6 | if(opcode>>8 == 0x0f) 7 | opcode = (opcode & 0xff) | 0x0100; 8 | 9 | //if(!instrfuncs.count(opcode)){ 10 | if(!instrfuncs[opcode]){ 11 | ERROR("not implemented OPCODE 0x%02x", OPCODE); 12 | return false; 13 | } 14 | 15 | (this->*instrfuncs[opcode])(); 16 | return true; 17 | } 18 | 19 | void ExecInstr::set_rm32(uint32_t value){ 20 | if(MOD == 3) 21 | SET_GPREG(static_cast(RM), value); 22 | else 23 | WRITE_MEM32(calc_modrm(), value); 24 | } 25 | 26 | uint32_t ExecInstr::get_rm32(void){ 27 | if(MOD == 3) 28 | return GET_GPREG(static_cast(RM)); 29 | else 30 | return READ_MEM32(calc_modrm()); 31 | } 32 | 33 | void ExecInstr::set_r32(uint32_t value){ 34 | SET_GPREG(static_cast(REG), value); 35 | } 36 | 37 | uint32_t ExecInstr::get_r32(void){ 38 | return GET_GPREG(static_cast(REG)); 39 | } 40 | 41 | void ExecInstr::set_moffs32(uint32_t value){ 42 | SEGMENT = DS; 43 | return WRITE_MEM32(MOFFS, value); 44 | } 45 | 46 | uint32_t ExecInstr::get_moffs32(void){ 47 | SEGMENT = DS; 48 | return READ_MEM32(MOFFS); 49 | } 50 | 51 | void ExecInstr::set_rm16(uint16_t value){ 52 | if(MOD == 3) 53 | SET_GPREG(static_cast(RM), value); 54 | else 55 | WRITE_MEM16(calc_modrm(), value); 56 | } 57 | 58 | uint16_t ExecInstr::get_rm16(void){ 59 | if(MOD == 3) 60 | return GET_GPREG(static_cast(RM)); 61 | else 62 | return READ_MEM16(calc_modrm()); 63 | } 64 | 65 | void ExecInstr::set_r16(uint16_t value){ 66 | SET_GPREG(static_cast(REG), value); 67 | } 68 | 69 | uint16_t ExecInstr::get_r16(void){ 70 | return GET_GPREG(static_cast(REG)); 71 | } 72 | 73 | void ExecInstr::set_moffs16(uint16_t value){ 74 | SEGMENT = DS; 75 | return WRITE_MEM16(MOFFS, value); 76 | } 77 | 78 | uint16_t ExecInstr::get_moffs16(void){ 79 | SEGMENT = DS; 80 | return READ_MEM16(MOFFS); 81 | } 82 | 83 | void ExecInstr::set_rm8(uint8_t value){ 84 | if(MOD == 3) 85 | SET_GPREG(static_cast(RM), value); 86 | else 87 | WRITE_MEM8(calc_modrm(), value); 88 | } 89 | 90 | uint8_t ExecInstr::get_rm8(void){ 91 | if(MOD == 3) 92 | return GET_GPREG(static_cast(RM)); 93 | else 94 | return READ_MEM8(calc_modrm()); 95 | } 96 | 97 | void ExecInstr::set_r8(uint8_t value){ 98 | SET_GPREG(static_cast(REG), value); 99 | } 100 | 101 | void ExecInstr::set_moffs8(uint8_t value){ 102 | SEGMENT = DS; 103 | return WRITE_MEM8(MOFFS, value); 104 | } 105 | 106 | uint8_t ExecInstr::get_moffs8(void){ 107 | SEGMENT = DS; 108 | return READ_MEM8(MOFFS); 109 | } 110 | 111 | uint8_t ExecInstr::get_r8(void){ 112 | return GET_GPREG(static_cast(REG)); 113 | } 114 | 115 | uint32_t ExecInstr::get_m(void){ 116 | return calc_modrm(); 117 | } 118 | 119 | void ExecInstr::set_sreg(uint16_t value){ 120 | EMU->set_segment(static_cast(REG), value); 121 | } 122 | 123 | uint16_t ExecInstr::get_sreg(void){ 124 | return EMU->get_segment(static_cast(REG)); 125 | } 126 | 127 | void ExecInstr::set_crn(uint32_t value){ 128 | INFO(2, "set CR%d = %x", REG, value); 129 | EMU->set_crn(REG, value); 130 | } 131 | 132 | uint32_t ExecInstr::get_crn(void){ 133 | return EMU->get_crn(REG); 134 | } 135 | 136 | uint32_t ExecInstr::calc_modrm(void){ 137 | ASSERT(MOD != 3); 138 | 139 | SEGMENT = DS; 140 | if(is_mode32() ^ chsz_ad) 141 | return calc_modrm32(); 142 | else 143 | return calc_modrm16(); 144 | } 145 | 146 | uint32_t ExecInstr::calc_modrm16(void){ 147 | uint32_t addr = 0; 148 | 149 | switch(MOD){ 150 | case 1: 151 | addr += DISP8; 152 | break; 153 | case 2: 154 | addr += DISP16; 155 | break; 156 | } 157 | 158 | switch(RM){ 159 | case 0: 160 | case 1: 161 | case 7: 162 | addr += GET_GPREG(BX); 163 | break; 164 | case 2: 165 | case 3: 166 | case 6: 167 | if(MOD == 0 && RM == 6) 168 | addr += DISP16; 169 | else{ 170 | addr += GET_GPREG(BP); 171 | SEGMENT = SS; 172 | } 173 | break; 174 | } 175 | 176 | if(RM < 6){ 177 | if(RM % 2) 178 | addr += GET_GPREG(DI); 179 | else 180 | addr += GET_GPREG(SI); 181 | } 182 | 183 | return addr; 184 | } 185 | 186 | uint32_t ExecInstr::calc_modrm32(void){ 187 | uint32_t addr = 0; 188 | 189 | switch(MOD){ 190 | case 1: 191 | addr += DISP8; 192 | break; 193 | case 2: 194 | addr += DISP32; 195 | break; 196 | } 197 | 198 | switch(RM){ 199 | case 4: 200 | addr += calc_sib(); 201 | break; 202 | case 5: 203 | if(MOD == 0){ 204 | addr += DISP32; 205 | break; 206 | } 207 | default: 208 | SEGMENT = (RM == 5) ? SS : DS; 209 | addr += GET_GPREG(static_cast(RM)); 210 | } 211 | 212 | return addr; 213 | } 214 | 215 | uint32_t ExecInstr::calc_sib(void){ 216 | uint32_t base; 217 | 218 | if(BASE == 5 && MOD == 0) 219 | base = DISP32; 220 | else if(BASE == 4){ 221 | if(SCALE == 0){ // BASE == 4, INDEX ==4, SCALE == 0 : [esp] 222 | SEGMENT = SS; 223 | base = 0; 224 | } 225 | else 226 | ERROR("not implemented SIB (base = %d, index = %d, scale = %d)\n", BASE, INDEX, SCALE); 227 | } 228 | else{ 229 | SEGMENT = (RM == 5) ? SS : DS; 230 | base = GET_GPREG(static_cast(BASE)); 231 | } 232 | 233 | return base + GET_GPREG(static_cast(INDEX)) * (1<(BASE)) + GET_GPREG(static_cast(INDEX)) * (1<(ESP)); 239 | // else if(BASE==5 && MOD==0) 240 | // return DISP32 + GET_GPREG(static_cast(INDEX)) * (1< 2 | #include "instruction/base.hpp" 3 | #include "emulator/exception.hpp" 4 | 5 | #define instrbase(f) ((instrfunc_t)&InstrBase::f) 6 | 7 | InstrBase::InstrBase() { 8 | int i; 9 | 10 | set_funcflag(0x00, instrbase(add_rm8_r8), CHK_MODRM); 11 | set_funcflag(0x02, instrbase(add_r8_rm8), CHK_MODRM); 12 | set_funcflag(0x04, instrbase(add_al_imm8), CHK_IMM8); 13 | set_funcflag(0x08, instrbase(or_rm8_r8), CHK_MODRM); 14 | set_funcflag(0x0a, instrbase(or_r8_rm8), CHK_MODRM); 15 | set_funcflag(0x0c, instrbase(or_al_imm8), CHK_IMM8); 16 | set_funcflag(0x20, instrbase(and_rm8_r8), CHK_MODRM); 17 | set_funcflag(0x22, instrbase(and_r8_rm8), CHK_MODRM); 18 | set_funcflag(0x24, instrbase(and_al_imm8), CHK_IMM8); 19 | set_funcflag(0x28, instrbase(sub_rm8_r8), CHK_MODRM); 20 | set_funcflag(0x2a, instrbase(sub_r8_rm8), CHK_MODRM); 21 | set_funcflag(0x2c, instrbase(sub_al_imm8), CHK_IMM8); 22 | set_funcflag(0x30, instrbase(xor_rm8_r8), CHK_MODRM); 23 | set_funcflag(0x32, instrbase(xor_r8_rm8), CHK_MODRM); 24 | set_funcflag(0x34, instrbase(xor_al_imm8), CHK_IMM8); 25 | set_funcflag(0x38, instrbase(cmp_rm8_r8), CHK_MODRM); 26 | set_funcflag(0x3a, instrbase(cmp_r8_rm8), CHK_MODRM); 27 | set_funcflag(0x3c, instrbase(cmp_al_imm8), CHK_IMM8); 28 | set_funcflag(0x70, instrbase(jo_rel8), CHK_IMM8); 29 | set_funcflag(0x71, instrbase(jno_rel8), CHK_IMM8); 30 | set_funcflag(0x72, instrbase(jb_rel8), CHK_IMM8); 31 | set_funcflag(0x73, instrbase(jnb_rel8), CHK_IMM8); 32 | set_funcflag(0x74, instrbase(jz_rel8), CHK_IMM8); 33 | set_funcflag(0x75, instrbase(jnz_rel8), CHK_IMM8); 34 | set_funcflag(0x76, instrbase(jbe_rel8), CHK_IMM8); 35 | set_funcflag(0x77, instrbase(ja_rel8), CHK_IMM8); 36 | set_funcflag(0x78, instrbase(js_rel8), CHK_IMM8); 37 | set_funcflag(0x79, instrbase(jns_rel8), CHK_IMM8); 38 | set_funcflag(0x7a, instrbase(jp_rel8), CHK_IMM8); 39 | set_funcflag(0x7b, instrbase(jnp_rel8), CHK_IMM8); 40 | set_funcflag(0x7c, instrbase(jl_rel8), CHK_IMM8); 41 | set_funcflag(0x7d, instrbase(jnl_rel8), CHK_IMM8); 42 | set_funcflag(0x7e, instrbase(jle_rel8), CHK_IMM8); 43 | set_funcflag(0x7f, instrbase(jnle_rel8), CHK_IMM8); 44 | set_funcflag(0x84, instrbase(test_rm8_r8), CHK_MODRM); 45 | set_funcflag(0x86, instrbase(xchg_r8_rm8), CHK_MODRM); 46 | set_funcflag(0x88, instrbase(mov_rm8_r8), CHK_MODRM); 47 | set_funcflag(0x8a, instrbase(mov_r8_rm8), CHK_MODRM); 48 | set_funcflag(0x8e, instrbase(mov_sreg_rm16), CHK_MODRM); 49 | set_funcflag(0x90, instrbase(nop), 0); 50 | set_funcflag(0xa0, instrbase(mov_al_moffs8), CHK_MOFFS); 51 | set_funcflag(0xa2, instrbase(mov_moffs8_al), CHK_MOFFS); 52 | set_funcflag(0xa8, instrbase(test_al_imm8), CHK_IMM8); 53 | for (i=0; i<8; i++) set_funcflag(0xb0+i, instrbase(mov_r8_imm8) ,CHK_IMM8); 54 | set_funcflag(0xc6, instrbase(mov_rm8_imm8), CHK_MODRM | CHK_IMM8); 55 | set_funcflag(0xcb, instrbase(retf), 0); 56 | set_funcflag(0xcc, instrbase(int3), 0); 57 | set_funcflag(0xcd, instrbase(int_imm8), CHK_IMM8); 58 | set_funcflag(0xcf, instrbase(iret), 0); 59 | set_funcflag(0xe4, instrbase(in_al_imm8), CHK_IMM8); 60 | set_funcflag(0xe6, instrbase(out_imm8_al), CHK_IMM8); 61 | set_funcflag(0xeb, instrbase(jmp), CHK_IMM8); 62 | set_funcflag(0xec, instrbase(in_al_dx), 0); 63 | set_funcflag(0xee, instrbase(out_dx_al), 0); 64 | set_funcflag(0xfa, instrbase(cli), 0); 65 | set_funcflag(0xfb, instrbase(sti), 0); 66 | set_funcflag(0xfc, instrbase(cld), 0); 67 | set_funcflag(0xfd, instrbase(std), 0); 68 | set_funcflag(0xf4, instrbase(hlt), 0); 69 | 70 | set_funcflag(0x0f20, instrbase(mov_r32_crn), CHK_MODRM); 71 | set_funcflag(0x0f22, instrbase(mov_crn_r32), CHK_MODRM); 72 | set_funcflag(0x0f90, instrbase(seto_rm8), CHK_MODRM); 73 | set_funcflag(0x0f91, instrbase(setno_rm8), CHK_MODRM); 74 | set_funcflag(0x0f92, instrbase(setb_rm8), CHK_MODRM); 75 | set_funcflag(0x0f93, instrbase(setnb_rm8), CHK_MODRM); 76 | set_funcflag(0x0f94, instrbase(setz_rm8), CHK_MODRM); 77 | set_funcflag(0x0f95, instrbase(setnz_rm8), CHK_MODRM); 78 | set_funcflag(0x0f96, instrbase(setbe_rm8), CHK_MODRM); 79 | set_funcflag(0x0f97, instrbase(seta_rm8), CHK_MODRM); 80 | set_funcflag(0x0f98, instrbase(sets_rm8), CHK_MODRM); 81 | set_funcflag(0x0f99, instrbase(setns_rm8), CHK_MODRM); 82 | set_funcflag(0x0f9a, instrbase(setp_rm8), CHK_MODRM); 83 | set_funcflag(0x0f9b, instrbase(setnp_rm8), CHK_MODRM); 84 | set_funcflag(0x0f9c, instrbase(setl_rm8), CHK_MODRM); 85 | set_funcflag(0x0f9d, instrbase(setnl_rm8), CHK_MODRM); 86 | set_funcflag(0x0f9e, instrbase(setle_rm8), CHK_MODRM); 87 | set_funcflag(0x0f9f, instrbase(setnle_rm8), CHK_MODRM); 88 | 89 | 90 | set_funcflag(0x80, instrbase(code_80), CHK_MODRM | CHK_IMM8); 91 | set_funcflag(0x82, instrbase(code_82), CHK_MODRM | CHK_IMM8); 92 | set_funcflag(0xc0, instrbase(code_c0), CHK_MODRM | CHK_IMM8); 93 | set_funcflag(0xf6, instrbase(code_f6), CHK_MODRM); 94 | } 95 | 96 | void InstrBase::set_funcflag(uint16_t opcode, instrfunc_t func, uint8_t flags){ 97 | if(opcode>>8 == 0x0f) 98 | opcode = (opcode & 0xff) | 0x0100; 99 | ASSERT(opcode < MAX_OPCODE); 100 | 101 | instrfuncs[opcode] = func; chk[opcode].flags = flags; 102 | }; 103 | 104 | void InstrBase::add_rm8_r8(void){ 105 | uint8_t rm8, r8; 106 | 107 | rm8 = get_rm8(); 108 | r8 = get_r8(); 109 | set_rm8(rm8+r8); 110 | EFLAGS_UPDATE_ADD(rm8, r8); 111 | } 112 | 113 | void InstrBase::add_r8_rm8(void){ 114 | uint8_t r8, rm8; 115 | 116 | r8 = get_r8(); 117 | rm8 = get_rm8(); 118 | set_r8(r8+rm8); 119 | EFLAGS_UPDATE_ADD(r8, rm8); 120 | } 121 | 122 | void InstrBase::add_al_imm8(void){ 123 | uint8_t al; 124 | 125 | al = GET_GPREG(AL); 126 | SET_GPREG(AL, al+IMM8); 127 | EFLAGS_UPDATE_ADD(al, IMM8); 128 | } 129 | 130 | void InstrBase::or_rm8_r8(void){ 131 | uint8_t rm8, r8; 132 | 133 | rm8 = get_rm8(); 134 | r8 = get_r8(); 135 | set_rm8(rm8|r8); 136 | EFLAGS_UPDATE_OR(rm8, r8); 137 | } 138 | 139 | void InstrBase::or_al_imm8(void){ 140 | uint8_t al; 141 | 142 | al = GET_GPREG(AL); 143 | SET_GPREG(AL, al|IMM8); 144 | EFLAGS_UPDATE_OR(al, IMM8); 145 | } 146 | 147 | void InstrBase::or_r8_rm8(void){ 148 | uint8_t r8, rm8; 149 | 150 | r8 = get_r8(); 151 | rm8 = get_rm8(); 152 | set_r8(r8|rm8); 153 | EFLAGS_UPDATE_OR(r8, rm8); 154 | } 155 | 156 | void InstrBase::and_rm8_r8(void){ 157 | uint8_t rm8, r8; 158 | 159 | rm8 = get_rm8(); 160 | r8 = get_r8(); 161 | set_rm8(rm8&r8); 162 | EFLAGS_UPDATE_AND(rm8, r8); 163 | } 164 | 165 | void InstrBase::and_r8_rm8(void){ 166 | uint8_t r8, rm8; 167 | 168 | r8 = get_r8(); 169 | rm8 = get_rm8(); 170 | set_r8(r8&rm8); 171 | EFLAGS_UPDATE_AND(r8, rm8); 172 | } 173 | 174 | void InstrBase::and_al_imm8(void){ 175 | uint8_t al; 176 | 177 | al = GET_GPREG(AL); 178 | SET_GPREG(AL, al&IMM8); 179 | EFLAGS_UPDATE_AND(al, IMM8); 180 | } 181 | 182 | void InstrBase::sub_rm8_r8(void){ 183 | uint8_t rm8, r8; 184 | 185 | rm8 = get_rm8(); 186 | r8 = get_r8(); 187 | set_rm8(rm8-r8); 188 | EFLAGS_UPDATE_SUB(rm8, r8); 189 | } 190 | 191 | void InstrBase::sub_r8_rm8(void){ 192 | uint8_t r8, rm8; 193 | 194 | r8 = get_r8(); 195 | rm8 = get_rm8(); 196 | set_r8(r8-rm8); 197 | EFLAGS_UPDATE_SUB(r8, rm8); 198 | } 199 | 200 | void InstrBase::sub_al_imm8(void){ 201 | uint8_t al; 202 | 203 | al = GET_GPREG(AL); 204 | SET_GPREG(AL, al-IMM8); 205 | EFLAGS_UPDATE_SUB(al, IMM8); 206 | } 207 | 208 | void InstrBase::xor_rm8_r8(void){ 209 | uint8_t rm8, r8; 210 | 211 | rm8 = get_rm8(); 212 | r8 = get_r8(); 213 | set_rm8(rm8^r8); 214 | } 215 | 216 | void InstrBase::xor_r8_rm8(void){ 217 | uint8_t r8, rm8; 218 | 219 | r8 = get_r8(); 220 | rm8 = get_rm8(); 221 | set_r8(r8^rm8); 222 | } 223 | 224 | void InstrBase::xor_al_imm8(void){ 225 | uint8_t al; 226 | 227 | al = GET_GPREG(AL); 228 | SET_GPREG(AL, al^IMM8); 229 | } 230 | 231 | void InstrBase::cmp_rm8_r8(void){ 232 | uint8_t rm8, r8; 233 | 234 | rm8 = get_rm8(); 235 | r8 = get_r8(); 236 | EFLAGS_UPDATE_SUB(rm8, r8); 237 | } 238 | 239 | void InstrBase::cmp_r8_rm8(void){ 240 | uint8_t r8, rm8; 241 | 242 | r8 = get_r8(); 243 | rm8 = get_rm8(); 244 | EFLAGS_UPDATE_SUB(r8, rm8); 245 | } 246 | 247 | void InstrBase::cmp_al_imm8(void){ 248 | uint8_t al; 249 | 250 | al = GET_GPREG(AL); 251 | EFLAGS_UPDATE_SUB(al, IMM8); 252 | } 253 | 254 | #define JCC_REL8(cc, is_flag) \ 255 | void InstrBase::j ## cc ## _rel8(void){ \ 256 | if(is_flag) \ 257 | UPDATE_IP(IMM8); \ 258 | } 259 | 260 | JCC_REL8(o, EFLAGS_OF) 261 | JCC_REL8(no, !EFLAGS_OF) 262 | JCC_REL8(b, EFLAGS_CF) 263 | JCC_REL8(nb, !EFLAGS_CF) 264 | JCC_REL8(z, EFLAGS_ZF) 265 | JCC_REL8(nz, !EFLAGS_ZF) 266 | JCC_REL8(be, EFLAGS_CF || EFLAGS_ZF) 267 | JCC_REL8(a, !(EFLAGS_CF || EFLAGS_ZF)) 268 | JCC_REL8(s, EFLAGS_SF) 269 | JCC_REL8(ns, !EFLAGS_SF) 270 | JCC_REL8(p, EFLAGS_PF) 271 | JCC_REL8(np, !EFLAGS_PF) 272 | JCC_REL8(l, EFLAGS_SF != EFLAGS_OF) 273 | JCC_REL8(nl, EFLAGS_SF == EFLAGS_OF) 274 | JCC_REL8(le, EFLAGS_ZF || (EFLAGS_SF != EFLAGS_OF)) 275 | JCC_REL8(nle, !EFLAGS_ZF && (EFLAGS_SF == EFLAGS_OF)) 276 | 277 | void InstrBase::test_rm8_r8(void){ 278 | uint8_t rm8, r8; 279 | 280 | rm8 = get_rm8(); 281 | r8 = get_r8(); 282 | EFLAGS_UPDATE_AND(rm8, r8); 283 | } 284 | 285 | void InstrBase::xchg_r8_rm8(void){ 286 | uint8_t r8, rm8; 287 | 288 | r8 = get_r8(); 289 | rm8 = get_rm8(); 290 | set_r8(rm8); 291 | set_rm8(r8); 292 | } 293 | 294 | void InstrBase::mov_rm8_r8(void){ 295 | uint8_t r8; 296 | 297 | r8 = get_r8(); 298 | set_rm8(r8); 299 | } 300 | 301 | void InstrBase::mov_r8_rm8(void){ 302 | uint8_t rm8; 303 | 304 | rm8 = get_rm8(); 305 | set_r8(rm8); 306 | } 307 | 308 | void InstrBase::mov_sreg_rm16(void){ 309 | uint16_t rm16; 310 | 311 | rm16 = get_rm16(); 312 | set_sreg(rm16); 313 | } 314 | 315 | void InstrBase::nop(void){} // xchg eax, eax 316 | 317 | void InstrBase::mov_al_moffs8(void){ 318 | SET_GPREG(AL, get_moffs8()); 319 | } 320 | 321 | void InstrBase::mov_moffs8_al(void){ 322 | set_moffs8(GET_GPREG(AL)); 323 | } 324 | 325 | void InstrBase::test_al_imm8(void){ 326 | uint8_t al; 327 | 328 | al = GET_GPREG(AL); 329 | EFLAGS_UPDATE_AND(al, IMM8); 330 | } 331 | 332 | void InstrBase::mov_r8_imm8(void){ 333 | uint8_t reg; 334 | 335 | reg = OPCODE & ((1<<3)-1); 336 | SET_GPREG(static_cast(reg), IMM8); 337 | } 338 | 339 | void InstrBase::mov_rm8_imm8(void){ 340 | set_rm8(IMM8); 341 | } 342 | 343 | void InstrBase::retf(void){ 344 | EmuInstr::retf(); 345 | } 346 | 347 | void InstrBase::int3(void){ 348 | EMU->dump_regs(); 349 | EMU->dump_mem((EMU->get_segment(SS)<<4)+EMU->get_gpreg(ESP)-0x40, 0x80); 350 | } 351 | 352 | void InstrBase::int_imm8(void){ 353 | EMU->queue_interrupt(IMM8, false); 354 | } 355 | 356 | void InstrBase::iret(void){ 357 | EmuInstr::iret(); 358 | } 359 | 360 | void InstrBase::in_al_imm8(void){ 361 | SET_GPREG(AL, EMU->in_io8((uint8_t)IMM8)); 362 | } 363 | 364 | void InstrBase::out_imm8_al(void){ 365 | uint8_t al; 366 | 367 | al = GET_GPREG(AL); 368 | EMU->out_io8((uint8_t)IMM8, al); 369 | } 370 | 371 | void InstrBase::jmp(void){ 372 | UPDATE_IP(IMM8); 373 | } 374 | 375 | void InstrBase::in_al_dx(void){ 376 | uint16_t dx; 377 | 378 | dx = GET_GPREG(DX); 379 | SET_GPREG(AL, EMU->in_io8(dx)); 380 | } 381 | 382 | void InstrBase::out_dx_al(void){ 383 | uint16_t dx; 384 | uint8_t al; 385 | 386 | dx = GET_GPREG(DX); 387 | al = GET_GPREG(AL); 388 | EMU->out_io8(dx, al); 389 | } 390 | 391 | void InstrBase::cli(void){ 392 | EMU->set_interrupt(false); 393 | } 394 | 395 | void InstrBase::sti(void){ 396 | EMU->set_interrupt(true); 397 | } 398 | 399 | void InstrBase::cld(void){ 400 | EMU->set_direction(false); 401 | } 402 | 403 | void InstrBase::std(void){ 404 | EMU->set_direction(true); 405 | } 406 | 407 | void InstrBase::hlt(void){ 408 | EXCEPTION(EXP_GP, !chk_ring(0)); 409 | EMU->do_halt(true); 410 | //EMU->dump_regs(); 411 | } 412 | 413 | void InstrBase::ltr_rm16(void){ 414 | uint16_t rm16; 415 | 416 | EXCEPTION(EXP_GP, !chk_ring(0)); 417 | rm16 = get_rm16(); 418 | set_tr(rm16); 419 | } 420 | 421 | void InstrBase::mov_r32_crn(void){ 422 | uint32_t crn; 423 | 424 | crn = get_crn(); 425 | SET_GPREG(static_cast(RM), crn); // set_r32 426 | } 427 | 428 | void InstrBase::mov_crn_r32(void){ 429 | uint32_t r32; 430 | 431 | EXCEPTION(EXP_GP, !chk_ring(0)); 432 | r32 = GET_GPREG(static_cast(RM)); // get_r32 433 | set_crn(r32); 434 | } 435 | 436 | #define SETCC_RM8(cc, is_flag) \ 437 | void InstrBase::set ## cc ## _rm8(void){ \ 438 | SET_GPREG(static_cast(RM), is_flag); \ 439 | } 440 | 441 | SETCC_RM8(o, EFLAGS_OF) 442 | SETCC_RM8(no, !EFLAGS_OF) 443 | SETCC_RM8(b, EFLAGS_CF) 444 | SETCC_RM8(nb, !EFLAGS_CF) 445 | SETCC_RM8(z, EFLAGS_ZF) 446 | SETCC_RM8(nz, !EFLAGS_ZF) 447 | SETCC_RM8(be, EFLAGS_CF || EFLAGS_ZF) 448 | SETCC_RM8(a, !(EFLAGS_CF || EFLAGS_ZF)) 449 | SETCC_RM8(s, EFLAGS_SF) 450 | SETCC_RM8(ns, !EFLAGS_SF) 451 | SETCC_RM8(p, EFLAGS_PF) 452 | SETCC_RM8(np, !EFLAGS_PF) 453 | SETCC_RM8(l, EFLAGS_SF != EFLAGS_OF) 454 | SETCC_RM8(nl, EFLAGS_SF == EFLAGS_OF) 455 | SETCC_RM8(le, EFLAGS_ZF || (EFLAGS_SF != EFLAGS_OF)) 456 | SETCC_RM8(nle, !EFLAGS_ZF && (EFLAGS_SF == EFLAGS_OF)) 457 | 458 | /******************************************************************/ 459 | 460 | void InstrBase::code_80(void){ 461 | switch(REG){ 462 | case 0: add_rm8_imm8(); break; 463 | case 1: or_rm8_imm8(); break; 464 | case 2: adc_rm8_imm8(); break; 465 | case 3: sbb_rm8_imm8(); break; 466 | case 4: and_rm8_imm8(); break; 467 | case 5: sub_rm8_imm8(); break; 468 | case 6: xor_rm8_imm8(); break; 469 | case 7: cmp_rm8_imm8(); break; 470 | default: 471 | ERROR("not implemented: 0x80 /%d\n", REG); 472 | } 473 | } 474 | 475 | void InstrBase::code_82(void){ 476 | code_80(); 477 | } 478 | 479 | void InstrBase::code_c0(void){ 480 | switch(REG){ 481 | // case 0: rol_rm8_imm8(); break; 482 | // case 1: ror_rm8_imm8(); break; 483 | // case 2: rcl_rm8_imm8(); break; 484 | // case 3: rcr_rm8_imm8(); break; 485 | case 4: shl_rm8_imm8(); break; 486 | case 5: shr_rm8_imm8(); break; 487 | case 6: sal_rm8_imm8(); break; 488 | case 7: sar_rm8_imm8(); break; 489 | default: 490 | ERROR("not implemented: 0xc0 /%d\n", REG); 491 | } 492 | } 493 | 494 | void InstrBase::code_f6(void){ 495 | switch(REG){ 496 | case 0: test_rm8_imm8(); break; 497 | case 2: not_rm8(); break; 498 | case 3: neg_rm8(); break; 499 | case 4: mul_ax_al_rm8(); break; 500 | case 5: imul_ax_al_rm8(); break; 501 | case 6: div_al_ah_rm8(); break; 502 | case 7: idiv_al_ah_rm8(); break; 503 | default: 504 | ERROR("not implemented: 0xf6 /%d\n", REG); 505 | } 506 | } 507 | 508 | /******************************************************************/ 509 | 510 | void InstrBase::add_rm8_imm8(void){ 511 | uint8_t rm8; 512 | 513 | rm8 = get_rm8(); 514 | set_rm8(rm8+IMM8); 515 | EFLAGS_UPDATE_ADD(rm8, IMM8); 516 | } 517 | 518 | void InstrBase::or_rm8_imm8(void){ 519 | uint8_t rm8; 520 | 521 | rm8 = get_rm8(); 522 | set_rm8(rm8|IMM8); 523 | EFLAGS_UPDATE_OR(rm8, IMM8); 524 | } 525 | 526 | void InstrBase::adc_rm8_imm8(void){ 527 | uint8_t rm8, cf; 528 | 529 | rm8 = get_rm8(); 530 | cf = EFLAGS_CF; 531 | set_rm8(rm8+IMM8+cf); 532 | EFLAGS_UPDATE_ADD(rm8, IMM8+cf); 533 | } 534 | 535 | void InstrBase::sbb_rm8_imm8(void){ 536 | uint8_t rm8, cf; 537 | 538 | rm8 = get_rm8(); 539 | cf = EFLAGS_CF; 540 | set_rm8(rm8-IMM8-cf); 541 | EFLAGS_UPDATE_SUB(rm8, IMM8+cf); 542 | } 543 | 544 | void InstrBase::and_rm8_imm8(void){ 545 | uint8_t rm8; 546 | 547 | rm8 = get_rm8(); 548 | set_rm8(rm8&IMM8); 549 | EFLAGS_UPDATE_AND(rm8, IMM8); 550 | } 551 | 552 | void InstrBase::sub_rm8_imm8(void){ 553 | uint8_t rm8; 554 | 555 | rm8 = get_rm8(); 556 | set_rm8(rm8-IMM8); 557 | EFLAGS_UPDATE_SUB(rm8, IMM8); 558 | } 559 | 560 | void InstrBase::xor_rm8_imm8(void){ 561 | uint8_t rm8; 562 | 563 | rm8 = get_rm8(); 564 | set_rm8(rm8^IMM8); 565 | } 566 | 567 | void InstrBase::cmp_rm8_imm8(void){ 568 | uint8_t rm8; 569 | 570 | rm8 = get_rm8(); 571 | EFLAGS_UPDATE_SUB(rm8, IMM8); 572 | } 573 | 574 | /******************************************************************/ 575 | 576 | void InstrBase::shl_rm8_imm8(void){ 577 | uint8_t rm8; 578 | 579 | rm8 = get_rm8(); 580 | set_rm8(rm8<>IMM8); 589 | EFLAGS_UPDATE_SHR(rm8, IMM8); 590 | } 591 | 592 | void InstrBase::sal_rm8_imm8(void){ 593 | int8_t rm8_s; 594 | 595 | rm8_s = get_rm8(); 596 | set_rm8(rm8_s<>IMM8); 605 | // EFLAGS_UPDATE_SAR(rm8_s, IMM8); 606 | } 607 | 608 | /******************************************************************/ 609 | 610 | void InstrBase::test_rm8_imm8(void){ 611 | uint8_t rm8, imm8; 612 | 613 | rm8 = get_rm8(); 614 | imm8 = EMU->get_code8(0); 615 | UPDATE_EIP(1); 616 | EFLAGS_UPDATE_AND(rm8, imm8); 617 | } 618 | 619 | void InstrBase::not_rm8(void){ 620 | uint8_t rm8; 621 | 622 | rm8 = get_rm8(); 623 | set_rm8(~rm8); 624 | } 625 | 626 | void InstrBase::neg_rm8(void){ 627 | int8_t rm8_s; 628 | 629 | rm8_s = get_rm8(); 630 | set_rm8(-rm8_s); 631 | EFLAGS_UPDATE_SUB((uint8_t)0, rm8_s); 632 | } 633 | 634 | void InstrBase::mul_ax_al_rm8(void){ 635 | uint8_t rm8, al; 636 | uint16_t val; 637 | 638 | rm8 = get_rm8(); 639 | al = GET_GPREG(AL); 640 | val = al*rm8; 641 | 642 | SET_GPREG(AX, val); 643 | 644 | EFLAGS_UPDATE_MUL(al, rm8); 645 | } 646 | 647 | void InstrBase::imul_ax_al_rm8(void){ 648 | int8_t rm8_s, al_s; 649 | int16_t val_s; 650 | 651 | rm8_s = get_rm8(); 652 | al_s = GET_GPREG(AL); 653 | val_s = al_s*rm8_s; 654 | 655 | SET_GPREG(AX, val_s); 656 | 657 | EFLAGS_UPDATE_IMUL(al_s, rm8_s); 658 | } 659 | 660 | void InstrBase::div_al_ah_rm8(void){ 661 | uint8_t rm8; 662 | uint16_t ax; 663 | 664 | rm8 = get_rm8(); 665 | ax = GET_GPREG(AX); 666 | 667 | SET_GPREG(AL, ax/rm8); 668 | SET_GPREG(AH, ax%rm8); 669 | } 670 | 671 | void InstrBase::idiv_al_ah_rm8(void){ 672 | int8_t rm8_s; 673 | int16_t ax_s; 674 | 675 | rm8_s = get_rm8(); 676 | ax_s = GET_GPREG(AX); 677 | 678 | SET_GPREG(AL, ax_s/rm8_s); 679 | SET_GPREG(AH, ax_s%rm8_s); 680 | } 681 | 682 | -------------------------------------------------------------------------------- /instruction/parse.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "instruction/instruction.hpp" 3 | 4 | uint8_t ParseInstr::parse_prefix(void){ 5 | uint8_t code, chsz = 0; 6 | 7 | while(true){ 8 | code = get_emu()->get_code8(0); 9 | switch(code){ 10 | case 0x26: 11 | PRE_SEGMENT = ES; 12 | goto set_pre; 13 | case 0x2e: 14 | PRE_SEGMENT = CS; 15 | goto set_pre; 16 | case 0x36: 17 | PRE_SEGMENT = SS; 18 | goto set_pre; 19 | case 0x3e: 20 | PRE_SEGMENT = DS; 21 | goto set_pre; 22 | case 0x64: 23 | PRE_SEGMENT = FS; 24 | goto set_pre; 25 | case 0x65: 26 | PRE_SEGMENT = GS; 27 | goto set_pre; 28 | case 0x66: 29 | chsz |= CHSZ_OP; 30 | goto next; 31 | case 0x67: 32 | chsz |= CHSZ_AD; 33 | goto next; 34 | case 0xf2: 35 | PRE_REPEAT = REPNZ; 36 | goto next; 37 | case 0xf3: 38 | PRE_REPEAT = REPZ; 39 | goto next; 40 | default: 41 | return chsz; 42 | 43 | set_pre: PREFIX = code; 44 | next: UPDATE_EIP(1); 45 | break; 46 | } 47 | } 48 | } 49 | 50 | void ParseInstr::parse(void){ 51 | uint16_t opcode; 52 | 53 | parse_opcode(); 54 | 55 | opcode = OPCODE; 56 | if(opcode>>8 == 0x0f) 57 | opcode = (opcode & 0xff) | 0x0100; 58 | 59 | /* 60 | if(!chk.count(opcode)){ 61 | DEBUG_MSG(5, "\n"); 62 | ERROR("no opecode : %x", opcode); 63 | } 64 | */ 65 | if(chk[opcode].modrm) 66 | parse_modrm_sib_disp(); 67 | 68 | if(chk[opcode].imm32){ 69 | IMM32 = get_emu()->get_code32(0); 70 | DEBUG_MSG(5, "imm32:0x%08x ", IMM32); 71 | UPDATE_EIP(4); 72 | } 73 | else if(chk[opcode].imm16){ 74 | IMM16 = get_emu()->get_code16(0); 75 | DEBUG_MSG(5, "imm16:0x%04x ", IMM16); 76 | UPDATE_EIP(2); 77 | } 78 | else if(chk[opcode].imm8){ 79 | IMM8 = (int8_t)get_emu()->get_code8(0); 80 | DEBUG_MSG(5, "imm8:0x%02x ", IMM8); 81 | UPDATE_EIP(1); 82 | } 83 | if(chk[opcode].ptr16){ 84 | PTR16 = get_emu()->get_code16(0); 85 | DEBUG_MSG(5, "ptr16:0x%04x", PTR16); 86 | UPDATE_EIP(2); 87 | } 88 | 89 | if(chk[opcode].moffs) 90 | parse_moffs(); 91 | 92 | DEBUG_MSG(5, "\n"); 93 | } 94 | 95 | void ParseInstr::parse_opcode(void){ 96 | OPCODE = get_emu()->get_code8(0); 97 | UPDATE_EIP(1); 98 | 99 | // two byte opcode 100 | if(OPCODE == 0x0f){ 101 | OPCODE = (OPCODE << 8) + get_emu()->get_code8(0); 102 | UPDATE_EIP(1); 103 | } 104 | 105 | if(is_mode32()) 106 | DEBUG_MSG(5, "CS:%04x EIP:0x%04x opcode:%02x ", EMU->get_segment(CS), GET_EIP()-1, OPCODE); 107 | else 108 | DEBUG_MSG(5, "CS:%04x IP:0x%04x opcode:%02x ", EMU->get_segment(CS), GET_IP()-1, OPCODE); 109 | } 110 | 111 | void ParseInstr::parse_modrm_sib_disp(void){ 112 | _MODRM = get_emu()->get_code8(0); 113 | UPDATE_EIP(1); 114 | 115 | DEBUG_MSG(5, "[mod:0x%02x reg:0x%02x rm:0x%02x] ", MOD, REG, RM); 116 | 117 | if(is_mode32() ^ chsz_ad) 118 | parse_modrm32(); 119 | else 120 | parse_modrm16(); 121 | } 122 | 123 | void ParseInstr::parse_modrm32(void){ 124 | if (MOD != 3 && RM == 4) { 125 | _SIB = get_emu()->get_code8(0); 126 | UPDATE_EIP(1); 127 | DEBUG_MSG(5, "[scale:0x%02x index:0x%02x base:0x%02x] ", SCALE, INDEX, BASE); 128 | } 129 | 130 | if (MOD == 2 || (MOD == 0 && RM == 5) || (MOD == 0 && BASE == 5)) { 131 | DISP32 = get_emu()->get_code32(0); 132 | UPDATE_EIP(4); 133 | DEBUG_MSG(5, "disp32:0x%08x ", DISP32); 134 | } 135 | else if (MOD == 1) { 136 | DISP8 = (int8_t)get_emu()->get_code8(0); 137 | UPDATE_EIP(1); 138 | DEBUG_MSG(5, "disp8:0x%02x ", DISP8); 139 | } 140 | } 141 | 142 | void ParseInstr::parse_modrm16(void){ 143 | if ((MOD == 0 && RM == 6) || MOD == 2) { 144 | DISP16 = get_emu()->get_code32(0); 145 | UPDATE_EIP(2); 146 | DEBUG_MSG(5, "disp16:0x%04x ", DISP16); 147 | } 148 | else if (MOD == 1) { 149 | DISP8 = (int8_t)get_emu()->get_code8(0); 150 | UPDATE_EIP(1); 151 | DEBUG_MSG(5, "disp8:0x%02x ", DISP8); 152 | } 153 | } 154 | 155 | void ParseInstr::parse_moffs(void){ 156 | if(is_mode32() ^ chsz_ad){ 157 | MOFFS = get_emu()->get_code32(0); 158 | UPDATE_EIP(4); 159 | } 160 | else{ 161 | MOFFS = get_emu()->get_code16(0); 162 | UPDATE_EIP(2); 163 | } 164 | DEBUG_MSG(5, "moffs:0x%04x ", MOFFS); 165 | } 166 | 167 | -------------------------------------------------------------------------------- /main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include "common.hpp" 7 | #include "instruction/base.hpp" 8 | #include "emulator/emulator.hpp" 9 | #include "emulator/exception.hpp" 10 | 11 | #define MEMORY_SIZE (4*MB) 12 | 13 | struct Setting { 14 | size_t mem_size; 15 | const char *image_name; 16 | uint32_t load_addr; 17 | size_t load_size; 18 | bool ui_enable; 19 | bool ui_full; 20 | bool ui_vm; 21 | }; 22 | 23 | void run_emulator(const Setting set); 24 | void help(const char *name); 25 | 26 | __attribute__((constructor)) 27 | void init(void){ 28 | setbuf(stdout, NULL); 29 | setbuf(stderr, NULL); 30 | } 31 | 32 | int main(int argc, char *argv[]){ 33 | Setting set = { 34 | .mem_size = MEMORY_SIZE, 35 | .image_name = "sample/kernel.img", 36 | .load_addr = 0x0, 37 | .load_size = (size_t)-1, 38 | .ui_enable = true, 39 | .ui_full = false, 40 | .ui_vm = false, 41 | }; 42 | 43 | char opt; 44 | struct option long_options[] = { 45 | {"memory", required_argument, NULL, 1}, 46 | {"load_addr", required_argument, NULL, 3}, 47 | {"load_size", required_argument, NULL, 4}, 48 | {"full", no_argument, NULL, 5}, 49 | {"VM", no_argument, NULL, 6}, 50 | {"no_graphic", no_argument, NULL, 7}, 51 | {"help", no_argument, NULL, 'h'}, 52 | {0, 0, 0, 0}}; 53 | 54 | while((opt=getopt_long(argc, argv, DEBUG_OPT"m:z:a:s:h", long_options, NULL)) != -1){ 55 | switch(opt){ 56 | uint32_t v; 57 | case 'm': 58 | case 1: 59 | v = atoi(optarg); 60 | 61 | if(v) 62 | set.mem_size = v*MB; 63 | else 64 | WARN("memory size is zero"); 65 | break; 66 | case 'a': 67 | case 3: 68 | set.load_addr = strtol(optarg, NULL, 0); 69 | break; 70 | case 's': 71 | case 4: 72 | set.load_size = strtol(optarg, NULL, 0); 73 | break; 74 | case 5: 75 | set.ui_full = true; 76 | break; 77 | case 6: 78 | set.ui_vm = true; 79 | break; 80 | case 7: 81 | set.ui_enable = false; 82 | break; 83 | #ifdef DEBUG 84 | case 'v': 85 | set_debuglv(optarg); 86 | break; 87 | #endif 88 | case 'h': 89 | case '?': 90 | help(argv[0]); 91 | } 92 | } 93 | 94 | if(argc > optind) 95 | set.image_name = argv[optind]; 96 | 97 | /* 98 | std::thread th1 = std::thread(set); 99 | std::thread th2 = std::thread(set); 100 | th1.join(); 101 | th2.join(); 102 | */ 103 | run_emulator(set); 104 | } 105 | 106 | void run_emulator(const Setting set){ 107 | EmuSetting emuset = { 108 | .mem_size = set.mem_size, 109 | .uiset = { 110 | .enable = set.ui_enable, 111 | .full = set.ui_full, 112 | .vm = set.ui_vm, 113 | }, 114 | }; 115 | Emulator emu = Emulator(emuset); 116 | InstrData instr; 117 | 118 | Instr16 instr16(&emu, &instr); 119 | Instr32 instr32(&emu, &instr); 120 | 121 | if(!emu.insert_floppy(0, set.image_name, false)){ 122 | WARN("cannot load image '%s'", set.image_name); 123 | return; 124 | } 125 | 126 | emu.load_binary("bios/bios.bin", 0xf0000, 0, 0x2800); 127 | emu.load_binary("bios/crt0.bin", 0xffff0, 0, 0x10); 128 | if(set.load_addr) 129 | emu.load_binary(set.image_name, set.load_addr, 0x200, set.load_size); 130 | 131 | 132 | //while(!emu.is_halt()){ 133 | //while(true){ 134 | while(emu.is_running()){ 135 | bool is_mode32; 136 | uint8_t prefix; 137 | bool chsz_op, chsz_ad; 138 | 139 | memset(&instr, 0, sizeof(InstrData)); 140 | try{ 141 | if(emu.chk_irq()) emu.do_halt(false); 142 | if(emu.is_halt()){ 143 | std::this_thread::sleep_for(std::chrono::milliseconds(10)); 144 | continue; 145 | } 146 | emu.hundle_interrupt(); 147 | 148 | is_mode32 = emu.is_mode32(); 149 | prefix = (is_mode32 ? instr32.parse_prefix() : instr16.parse_prefix()); 150 | chsz_op = prefix & CHSZ_OP; 151 | chsz_ad = prefix & CHSZ_AD; 152 | 153 | if(is_mode32 ^ chsz_op){ 154 | instr32.set_chsz_ad(!(is_mode32 ^ chsz_ad)); 155 | instr32.parse(); 156 | instr32.exec(); 157 | } 158 | else{ 159 | instr16.set_chsz_ad(is_mode32 ^ chsz_ad); 160 | instr16.parse(); 161 | instr16.exec(); 162 | } 163 | } 164 | catch(exception_t n){ 165 | emu.queue_interrupt(n, true); 166 | //INFO(3, "Exception %d", n); 167 | ERROR("Exception %d", n); 168 | } 169 | catch(...){ 170 | emu.dump_regs(); 171 | emu.stop(); 172 | } 173 | } 174 | } 175 | 176 | __attribute__((noreturn)) 177 | void help(const char *name){ 178 | MSG( "Simple x86 Emulator\n\n" 179 | 180 | "Usage :\n" 181 | "\t%s [options] \n\n", name); 182 | 183 | MSG( "Options : \n" 184 | "\t-m MB, --memory=MB\n" 185 | "\t\tMemory size (MB)\n\n" 186 | "\t-a ADDR, --load_addr=ADDR\n" 187 | "\t\tAddress to preload disk image\n\n" 188 | "\t-s SIZE, --load_size=SIZE\n" 189 | "\t\tSize to load (Enabled when 'load_addr' is specified)\n\n" 190 | "\t--full\n" 191 | "\t\tfull screen\n\n" 192 | "\t--VM\n" 193 | "\t\trunning on VMware or VirtualBox\n\n" 194 | #ifdef DEBUG 195 | "\t-v [1..4]\n" 196 | "\t\tverbose level\n\n" 197 | #endif 198 | "\t-h, --help\n" 199 | "\t\tshow this help\n"); 200 | 201 | _exit(0); 202 | } 203 | 204 | -------------------------------------------------------------------------------- /run.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | ./x86emu -v 2 --VM sample/kernel.img 4 | # ./x86emu -m 8 -v 1 --VM haribote_21h.img 5 | -------------------------------------------------------------------------------- /sample/.gitignore: -------------------------------------------------------------------------------- 1 | *.bin 2 | -------------------------------------------------------------------------------- /sample/Makefile: -------------------------------------------------------------------------------- 1 | TARGET := kernel.img 2 | 3 | TGT1 := boot.bin 4 | TGT2 := kernel.bin 5 | OBJS := startup.o funcs.o init.o main.o keyboard.o vga.o 6 | 7 | CC := gcc 8 | AS := nasm 9 | CFLAGS += -masm=intel -nostdlib -fno-asynchronous-unwind-tables -fcf-protection=none -fno-stack-protector -fno-pie -m32 10 | LDFLAGS := --entry=start --oformat=binary -Ttext 0x10000 -melf_i386 11 | 12 | all : 13 | make $(TARGET) 14 | 15 | %.o : %.c Makefile 16 | $(CC) $(CFLAGS) -c $< 17 | 18 | %.o : %.asm Makefile 19 | $(AS) -f elf $< 20 | 21 | $(TARGET) : $(TGT1) $(TGT2) 22 | cat $^ > $@ 23 | 24 | $(TGT1) : boot.asm 25 | $(AS) $< -o $@ 26 | 27 | $(TGT2) : $(OBJS) 28 | $(LD) $(LDFLAGS) -o $@ $(OBJS) 29 | 30 | clean : 31 | $(RM) $(OBJS) $(TGT1) $(TGT2) $(TARGET) 32 | -------------------------------------------------------------------------------- /sample/boot.asm: -------------------------------------------------------------------------------- 1 | BITS 16 2 | org 0x7c00 3 | 4 | jmp boot 5 | BS_jmpBoot2 db 0x90 6 | BS_OEMName db "SAMPLE", 0x00, 0x00 7 | BPB_BytsPerSec dw 0x0200 ;BytesPerSector 8 | BPB_SecPerClus db 0x01 ;SectorPerCluster 9 | BPB_RsvdSecCnt dw 0x0001 ;ReservedSectors 10 | BPB_NumFATs db 0x02 ;TotalFATs 11 | BPB_RootEntCnt dw 0x00e0 ;MaxRootEntries 12 | BPB_TotSec16 dw 0x0b40 ;TotalSectors 13 | BPB_Media db 0xf0 ;MediaDescriptor 14 | BPB_FATSz16 dw 0x0009 ;SectorsPerFAT 15 | BPB_SecPerTrk dw 0x0012 ;SectorsPerTrack 16 | BPB_NumHeads dw 0x0002 ;NumHeads 17 | BPB_HiddSec dd 0x00000000 ;HiddenSector 18 | BPB_TotSec32 dd 0x00000000 ;TotalSectors 19 | 20 | BS_DrvNum db 0x00 ;DriveNumber 21 | BS_Reserved1 db 0x00 ;Reserved 22 | BS_BootSig db 0x29 ;BootSignature 23 | BS_VolID dd 0x20170401 ;VolumeSerialNumber 24 | BS_VolLab db "SampleOS " ;VolumeLabel 25 | BS_FilSysType db "FAT12 " ;FileSystemType 26 | 27 | boot: 28 | mov ax, cs 29 | mov ds, ax 30 | mov es, ax 31 | 32 | mov ah, 0x13 33 | mov al, 0x3 34 | mov bl, 0x7 ; attribute 35 | mov dl, 0x00 ; x 36 | mov dh, 0x00 ; y 37 | mov bp, str_loading 38 | int 0x10 39 | 40 | ; read sectors (0x1000:0x0) 41 | push es 42 | mov ax, 0x1000 43 | mov es, ax 44 | mov bx, 0x0 45 | 46 | mov ah, 0x02 ; read 47 | mov al, 0x10 ; sectors 48 | mov ch, 0x00 ; cylinder 49 | mov cl, 0x02 ; sector 50 | mov dh, 0x00 ; head 51 | mov dl, 0x00 ; drive 52 | int 0x13 53 | pop es 54 | 55 | mov ah, 0x13 56 | mov al, 0x3 57 | mov bl, 0x7 ; attribute 58 | mov dl, 0x00 ; x 59 | mov dh, 0x01 ; y 60 | mov bp, str_booting 61 | int 0x10 62 | 63 | ; gdt 64 | lgdt [gdtr] 65 | 66 | ; A20 gate 67 | in al, 0x92 68 | or al, 2 69 | out 0x92, al 70 | 71 | ; Protected mode 72 | mov eax, cr0 73 | or al, 1 74 | mov cr0, eax 75 | 76 | mov ax, 0x10 77 | mov ds, ax 78 | mov ss, ax 79 | mov sp, 0x1000 80 | jmp dword 0x8:0x10000 81 | 82 | align 4 83 | gdtr: 84 | dw gdt_end - gdt -1 85 | dd gdt 86 | gdt: 87 | dq 0 88 | 89 | ; code 90 | dw 0x0000 91 | dw 0x0000 92 | db 0x00 93 | db 0x88 94 | db 0x44 95 | db 0x00 96 | 97 | ; data 98 | dw 0x0000 99 | dw 0x0000 100 | db 0x00 101 | db 0x82 102 | db 0x44 103 | db 0x00 104 | gdt_end: 105 | 106 | str_loading: 107 | db "now loading from floppy disk...", 0x00 108 | str_booting: 109 | db "booting...", 0x00 110 | 111 | times 0x1fe-($-$$) db 0 112 | dw 0xaa55 113 | -------------------------------------------------------------------------------- /sample/common.h: -------------------------------------------------------------------------------- 1 | #ifndef _COMMON_H 2 | #define _COMMON_H 3 | 4 | #define uint8_t unsigned char 5 | #define uint16_t unsigned short 6 | #define uint32_t unsigned long 7 | #define bool uint8_t 8 | #define true 1 9 | #define false 0 10 | 11 | #endif 12 | -------------------------------------------------------------------------------- /sample/funcs.asm: -------------------------------------------------------------------------------- 1 | global _puts, _putc, _gets 2 | global in_port, out_port, _cli, _sti 3 | global sys_puts, sys_gets, irq_timer, irq_keyboard, irq_mouse 4 | 5 | extern print_key, put_text 6 | 7 | BITS 32 8 | _puts: 9 | mov esi, [esp+0x4] 10 | int 0 11 | ret 12 | _putc: 13 | lea esi, [esp+0x4] 14 | int 0 15 | ret 16 | 17 | _gets: 18 | mov edi, [esp+0x4] 19 | int 1 20 | ret 21 | 22 | in_port: 23 | push ebp 24 | mov ebp, esp 25 | push edx 26 | mov edx, dword [ebp+0x8] 27 | xor eax, eax 28 | in al, dx 29 | pop edx 30 | leave 31 | ret 32 | 33 | out_port: 34 | push ebp 35 | mov ebp, esp 36 | push eax 37 | push edx 38 | mov edx, dword [ebp+0x8] 39 | mov eax, dword [ebp+0xc] 40 | out dx, al 41 | pop edx 42 | pop eax 43 | leave 44 | ret 45 | 46 | _cli: 47 | cli 48 | ret 49 | 50 | _sti: 51 | sti 52 | ret 53 | 54 | sys_puts: 55 | pusha 56 | push esi 57 | call dword put_text 58 | add esp, 4 59 | mov edx, 0x03f8 60 | puts_loop: 61 | mov al, [esi] 62 | inc esi 63 | cmp al, 0 64 | je puts_end 65 | out dx, al 66 | jmp puts_loop 67 | puts_end: 68 | popa 69 | iret 70 | 71 | ;sys_puts: 72 | ; pusha 73 | ; mov edx, 0x03f8 74 | ;puts_loop: 75 | ; mov al, [esi] 76 | ; inc esi 77 | ; cmp al, 0 78 | ; je puts_end 79 | ; out dx, al 80 | ; jmp puts_loop 81 | ;puts_end: 82 | ; popa 83 | ; iret 84 | 85 | sys_gets: 86 | mov edx, 0x03f8 87 | gets_loop: 88 | in al, dx 89 | cmp al, 0xa 90 | je puts_end 91 | mov [edi], al 92 | inc edi 93 | jmp gets_loop 94 | gets_end: 95 | mov byte [edi], 0x0 96 | iret 97 | 98 | irq_timer: 99 | mov esi, msg_timer 100 | jmp sys_puts 101 | 102 | irq_keyboard: 103 | pusha 104 | mov al, 0x61 105 | out 0x20, al 106 | in al, 0x60 107 | push ax 108 | call print_key 109 | add esp, 2 110 | popa 111 | iret 112 | 113 | irq_mouse: 114 | push ax 115 | mov al, 0x64 116 | out 0xa0, al 117 | mov al, 0x62 118 | out 0x20, al 119 | in al, 0x60 120 | mov esi, msg_mouse 121 | pop ax 122 | jmp sys_puts 123 | 124 | msg_timer: 125 | db "Tick!", 0xa, 0x0 126 | msg_keyboard: 127 | db "Keyboard Interrupt!", 0xa,0x0 128 | msg_mouse: 129 | db "Mouse Interrupt!", 0xa, 0x0 130 | -------------------------------------------------------------------------------- /sample/init.c: -------------------------------------------------------------------------------- 1 | #include "common.h" 2 | 3 | struct DTReg { 4 | uint16_t limit; 5 | uint16_t base_l; 6 | uint16_t base_h; 7 | }; 8 | 9 | struct IDT { 10 | uint16_t offset_l; 11 | uint16_t selector; 12 | uint8_t : 8; 13 | uint8_t type : 3; 14 | uint8_t D : 1; 15 | uint8_t : 1; 16 | uint8_t DPL : 2; 17 | uint8_t P : 1; 18 | uint16_t offset_h; 19 | }; 20 | 21 | struct PDE { 22 | uint32_t P : 1; 23 | uint32_t RW : 1; 24 | uint32_t US : 1; 25 | uint32_t PWT : 1; 26 | uint32_t PCD : 1; 27 | uint32_t A : 1; 28 | uint32_t : 1; 29 | uint32_t PS : 1; 30 | uint32_t G : 1; 31 | uint32_t : 3; 32 | uint32_t ptbl_base : 20; 33 | }; 34 | 35 | struct PTE { 36 | uint32_t P : 1; 37 | uint32_t RW : 1; 38 | uint32_t US : 1; 39 | uint32_t PWT : 1; 40 | uint32_t PCD : 1; 41 | uint32_t A : 1; 42 | uint32_t D : 1; 43 | uint32_t PAT : 1; 44 | uint32_t G : 1; 45 | uint32_t : 3; 46 | uint32_t page_base : 20; 47 | }; 48 | 49 | void set_idt(struct IDT *idt, void (*off)(), uint8_t type, uint8_t DPL, uint16_t sel); 50 | extern void sys_puts(void); 51 | extern void sys_gets(void); 52 | extern void irq_timer(void); 53 | extern void irq_keyboard(void); 54 | extern void irq_mouse(void); 55 | 56 | uint32_t init_paging(void){ 57 | struct PDE *pde = (struct PDE*)0x20000; 58 | struct PTE *pte = (struct PTE*)0x21000; 59 | 60 | pde[0].ptbl_base = ((uint32_t)pte)>>12; 61 | pde[0].P = 1; 62 | pde[0].RW = 1; 63 | pde[0].US = 1; 64 | for(int i=0; i<20; i++){ 65 | pte[i].page_base = i; 66 | pte[i].P = 1; 67 | pte[i].RW = 1; 68 | pte[i].US = 1; 69 | } 70 | for(int i=0xa0; i<0xc0; i++){ 71 | pte[i].page_base = i; 72 | pte[i].P = 1; 73 | pte[i].RW = 1; 74 | pte[i].US = 1; 75 | } 76 | 77 | return (uint32_t)pde; 78 | } 79 | 80 | uint32_t init_idt(void){ 81 | struct DTReg *idtr = (struct DTReg*)0x28000; 82 | struct IDT *idt = (struct IDT*)0x28030; 83 | 84 | idtr->limit = sizeof(struct IDT)*255 - 1; 85 | idtr->base_l = (uint32_t)idt & 0xffff; 86 | idtr->base_h = (uint32_t)idt >> 16; 87 | 88 | set_idt(&idt[0x00], sys_puts, 7, 3, 0x8); 89 | set_idt(&idt[0x01], sys_gets, 7, 3, 0x8); 90 | set_idt(&idt[0x20], irq_timer, 6, 0, 0x8); 91 | set_idt(&idt[0x21], irq_keyboard, 6, 0, 0x8); 92 | set_idt(&idt[0x2c], irq_mouse, 6, 0, 0x8); 93 | 94 | return (uint32_t)idtr; 95 | } 96 | 97 | void set_idt(struct IDT *idt, void (*off)(), uint8_t type, uint8_t DPL, uint16_t sel){ 98 | idt->offset_l = (uint32_t)off & 0xffff; 99 | idt->offset_h = (uint32_t)off >> 16; 100 | idt->selector = sel; 101 | idt->type = type; 102 | idt->D = 1; 103 | idt->DPL = DPL; 104 | idt->P = 1; 105 | } 106 | -------------------------------------------------------------------------------- /sample/kernel.img: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shift-crops/x86emu/fa65d448d71145fd611559a8a037dba211bb31a5/sample/kernel.img -------------------------------------------------------------------------------- /sample/keyboard.c: -------------------------------------------------------------------------------- 1 | #include "common.h" 2 | 3 | extern void _putc(char); 4 | 5 | const uint8_t keytable_n[0x7f] = { 6 | 0x0, 0x0, '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '-', '^', 0x0, 0, 7 | 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p', '@', '[', 0xa, 0x0, 'a', 's', 8 | 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';', ':', ' ', 0x0, ']', 'z', 'x', 'c', 'v', 9 | 'b', 'n', 'm', ',', '.', '/', 0x0, '*', 0x0, ' ', 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 10 | 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, '7', '8', '9', '-', '4', '5', '6', '+', '1', 11 | '2', '3', '0', '.', 0x0, 0x0, 0x0, 0x0, 0x0, '\\', 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 12 | }; 13 | const uint8_t keytable_s[0x7f] = { 14 | 0x0, 0x0, '!', '"', '#', '$', '%', '&', '\'', '(', ')', '~', '=', '~', 0x0, 0, 15 | 'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I', 'O', 'P', '`', '{', 0xa, 0x0, 'A', 'S', 16 | 'D', 'F', 'G', 'H', 'J', 'K', 'L', '+', '*', ' ', 0x0, '}', 'Z', 'X', 'C', 'V', 17 | 'B', 'N', 'M', '<', '>', '?', 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 18 | 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 19 | 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, '_', 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 20 | }; 21 | 22 | void print_key(uint8_t scancode){ 23 | static bool shift = false; 24 | uint8_t buf[2] = {0}; 25 | 26 | 27 | switch(scancode){ 28 | case 0x2a: 29 | case 0x36: 30 | shift = true; 31 | break; 32 | case 0xaa: 33 | case 0xb6: 34 | shift = false; 35 | break; 36 | default: 37 | if(!(scancode&0x80)) 38 | _putc(shift ? keytable_s[scancode] : keytable_n[scancode]); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /sample/main.c: -------------------------------------------------------------------------------- 1 | #include "common.h" 2 | int _puts(char *); 3 | void set_graphicmode(void); 4 | 5 | int main(void){ 6 | uint8_t *vram = (uint8_t*)0xa0000; 7 | 8 | _puts("Hello!\n"); 9 | 10 | _puts("Key or Mouse\n"); 11 | __asm__("hlt"); 12 | 13 | set_graphicmode(); 14 | for(int i=0; i<0x10; i++){ 15 | for(int j=0; j<320*200; j++) 16 | vram[j] = i; 17 | __asm__("hlt"); 18 | } 19 | 20 | for(int i=0; i<320*200; i++) 21 | vram[i] = i % 0x10; 22 | __asm__("hlt"); 23 | 24 | for(int i=0; i<200; i++){ 25 | uint8_t c8 = i % 0x10; 26 | uint32_t c32 = (c8<<24) + (c8<<16) + (c8<<8) + c8; 27 | for(int j=0; j<320/4; j++) 28 | ((uint32_t*)vram)[i*80+j] = c32; 29 | } 30 | 31 | return 0; 32 | } 33 | -------------------------------------------------------------------------------- /sample/main2.c: -------------------------------------------------------------------------------- 1 | #include "common.h" 2 | int _puts(char *); 3 | void set_graphicmode(void); 4 | 5 | int main(void){ 6 | uint8_t *vram = (uint8_t*)0xa0000; 7 | 8 | _puts("Hello!\n"); 9 | 10 | /* 11 | uint8_t *font = (uint8_t*)0x10600; 12 | _puts("hoge"); 13 | 14 | int n = 0; 15 | for(int y=0; y<200; y+=0x10) 16 | for(int x=0; x<320; x+=0x08){ 17 | for(int i=0; i<0x10; i++) 18 | for(int j=1; j<=8; j++) 19 | if((font[n*0x10+i]>>(8-j))&1) 20 | vram[(y+i)*320+(x+j)] = 7; 21 | n++; 22 | } 23 | 24 | _puts("end"); 25 | */ 26 | 27 | _puts("Key or Mouse\n"); 28 | 29 | /* 30 | __asm__("hlt"); 31 | 32 | set_graphicmode(); 33 | for(int i=0; i<0x10; i++){ 34 | for(int j=0; j<320*200; j++) 35 | vram[j] = i; 36 | __asm__("hlt"); 37 | } 38 | 39 | for(int i=0; i<320*200; i++) 40 | vram[i] = i % 0x10; 41 | __asm__("hlt"); 42 | 43 | for(int i=0; i<200; i++){ 44 | uint8_t c8 = i % 0x10; 45 | uint32_t c32 = (c8<<24) + (c8<<16) + (c8<<8) + c8; 46 | for(int j=0; j<320/4; j++) 47 | ((uint32_t*)vram)[i*80+j] = c32; 48 | } 49 | */ 50 | 51 | return 0; 52 | } 53 | -------------------------------------------------------------------------------- /sample/startup.asm: -------------------------------------------------------------------------------- 1 | extern init_idt, init_paging, init_vga 2 | extern main 3 | global start 4 | 5 | BITS 32 6 | start: 7 | ; gdt 8 | lgdt [gdtr] 9 | mov eax, 0x28 10 | ltr ax 11 | 12 | mov ax, 0x10 13 | mov ds, ax 14 | mov ss, ax 15 | call 0x8:next 16 | next: 17 | ; idt 18 | cli 19 | call init_idt 20 | lidt [eax] 21 | sti 22 | 23 | ; paging 24 | call init_paging 25 | mov cr3, eax 26 | 27 | mov eax, cr0 28 | or eax, 0x80000000 29 | mov cr0, eax 30 | 31 | call init_pic 32 | ;call init_timer 33 | call init_key_mouse 34 | call init_vga 35 | 36 | mov ax, 0x23 37 | mov ds, ax 38 | mov ss, ax 39 | call 0x18:main 40 | infinit: 41 | hlt 42 | jmp infinit 43 | 44 | init_pic: 45 | cli 46 | mov al, 0x11 47 | out 0x20, al 48 | out 0xa0, al 49 | 50 | mov al, 0x20 51 | out 0x21, al 52 | mov al, 0x28 53 | out 0xa1, al 54 | 55 | mov al, 0x4 56 | out 0x21, al 57 | mov al, 2 58 | out 0xa1, al 59 | 60 | mov al, 0x3 61 | out 0x21, al 62 | out 0xa1, al 63 | 64 | mov al, 0xfb 65 | out 0x21, al 66 | mov al, 0xff 67 | out 0xa1, al 68 | sti 69 | ret 70 | 71 | init_timer: 72 | ; timer 73 | cli 74 | mov al, 0x34 75 | out 0x43, al 76 | mov al, 0x9c 77 | out 0x40, al 78 | mov al, 0x2e 79 | out 0x40, al 80 | 81 | in al, 0x21 82 | and al, 0xfe 83 | out 0x21, al 84 | sti 85 | ret 86 | 87 | init_key_mouse: 88 | ; keyboard 89 | cli 90 | mov al, 0x60 91 | out 0x64, al 92 | mov al, 0x47 93 | out 0x60, al 94 | 95 | in al, 0x21 96 | and al, 0xfd 97 | out 0x21, al 98 | 99 | ; mouse 100 | mov al, 0xd4 101 | out 0x64, al 102 | mov al, 0xf4 103 | out 0x60, al 104 | 105 | in al, 0xa1 106 | and al, 0xef 107 | out 0xa1, al 108 | sti 109 | ret 110 | 111 | align 8 112 | gdtr: 113 | dw gdt_end - gdt -1 114 | dd gdt 115 | align 8 116 | gdt: 117 | dq 0 118 | 119 | dw 0x0100 120 | dw 0x0000 121 | db 0x00 122 | db 0x88 123 | db 0xc0 124 | db 0x00 125 | 126 | dw 0x0100 127 | dw 0x0000 128 | db 0x00 129 | db 0x82 130 | db 0xc0 131 | db 0x00 132 | 133 | dw 0x0100 134 | dw 0x0000 135 | db 0x00 136 | db 0xf8 137 | db 0xc0 138 | db 0x00 139 | 140 | dw 0x0100 141 | dw 0x0000 142 | db 0x00 143 | db 0xf2 144 | db 0xc0 145 | db 0x00 146 | 147 | dw 0x0080 148 | dw tss - start 149 | db 0x01 150 | db 0x01 151 | db 0x00 152 | db 0x00 153 | gdt_end: 154 | 155 | tss: 156 | dq 0 157 | dq 0 158 | dq 0 159 | dq 0 160 | dq 0 161 | dq 0 162 | dq 0 163 | dq 0 164 | dq 0 165 | dq 0 166 | dq 0 167 | dd 0 168 | dw 0x10 169 | dw 0 170 | dd 0x2000 171 | -------------------------------------------------------------------------------- /sample/vga.c: -------------------------------------------------------------------------------- 1 | #include "common.h" 2 | 3 | typedef struct { 4 | uint8_t red; 5 | uint8_t green; 6 | uint8_t blue; 7 | } rgb_t; 8 | 9 | const rgb_t palette[0x100] = { 10 | // R, G, B 11 | {0x00, 0x00, 0x00}, 12 | {0x00, 0x00, 0x2a}, 13 | {0x00, 0x2a, 0x00}, 14 | {0x00, 0x2a, 0x2a}, 15 | {0x2a, 0x00, 0x00}, 16 | {0x2a, 0x00, 0x2a}, 17 | {0x2a, 0x15, 0x00}, 18 | {0x2a, 0x2a, 0x2a}, 19 | {0x15, 0x15, 0x15}, 20 | {0x15, 0x15, 0x3f}, 21 | {0x15, 0x3f, 0x15}, 22 | {0x15, 0x3f, 0x3f}, 23 | {0x3f, 0x15, 0x15}, 24 | {0x3f, 0x15, 0x3f}, 25 | {0x3f, 0x3f, 0x15}, 26 | {0x3f, 0x3f, 0x3f}, 27 | {0x00, 0x00, 0x00}, 28 | {0x05, 0x05, 0x05}, 29 | {0x08, 0x08, 0x08}, 30 | {0x0b, 0x0b, 0x0b}, 31 | {0x0e, 0x0e, 0x0e}, 32 | {0x11, 0x11, 0x11}, 33 | {0x14, 0x14, 0x14}, 34 | {0x18, 0x18, 0x18}, 35 | {0x1c, 0x1c, 0x1c}, 36 | {0x20, 0x20, 0x20}, 37 | {0x24, 0x24, 0x24}, 38 | {0x28, 0x28, 0x28}, 39 | {0x2d, 0x2d, 0x2d}, 40 | {0x32, 0x32, 0x32}, 41 | {0x38, 0x38, 0x38}, 42 | {0x3f, 0x3f, 0x3f}, 43 | {0x00, 0x00, 0x3f}, 44 | {0x10, 0x00, 0x3f}, 45 | {0x1f, 0x00, 0x3f}, 46 | {0x2f, 0x00, 0x3f}, 47 | {0x3f, 0x00, 0x3f}, 48 | {0x3f, 0x00, 0x2f}, 49 | {0x3f, 0x00, 0x1f}, 50 | {0x3f, 0x00, 0x10}, 51 | {0x3f, 0x00, 0x00}, 52 | {0x3f, 0x10, 0x00}, 53 | {0x3f, 0x1f, 0x00}, 54 | {0x3f, 0x2f, 0x00}, 55 | {0x3f, 0x3f, 0x00}, 56 | {0x2f, 0x3f, 0x00}, 57 | {0x1f, 0x3f, 0x00}, 58 | {0x10, 0x3f, 0x00}, 59 | {0x00, 0x3f, 0x00}, 60 | {0x00, 0x3f, 0x10}, 61 | {0x00, 0x3f, 0x1f}, 62 | {0x00, 0x3f, 0x2f}, 63 | {0x00, 0x3f, 0x3f}, 64 | {0x00, 0x2f, 0x3f}, 65 | {0x00, 0x1f, 0x3f}, 66 | {0x00, 0x10, 0x3f}, 67 | {0x1f, 0x1f, 0x3f}, 68 | {0x27, 0x1f, 0x3f}, 69 | {0x2f, 0x1f, 0x3f}, 70 | {0x37, 0x1f, 0x3f}, 71 | {0x3f, 0x1f, 0x3f}, 72 | {0x3f, 0x1f, 0x37}, 73 | {0x3f, 0x1f, 0x2f}, 74 | {0x3f, 0x1f, 0x27}, 75 | {0x3f, 0x1f, 0x1f}, 76 | {0x3f, 0x27, 0x1f}, 77 | {0x3f, 0x2f, 0x1f}, 78 | {0x3f, 0x37, 0x1f}, 79 | {0x3f, 0x3f, 0x1f}, 80 | {0x37, 0x3f, 0x1f}, 81 | {0x2f, 0x3f, 0x1f}, 82 | {0x27, 0x3f, 0x1f}, 83 | {0x1f, 0x3f, 0x1f}, 84 | {0x1f, 0x3f, 0x27}, 85 | {0x1f, 0x3f, 0x2f}, 86 | {0x1f, 0x3f, 0x37}, 87 | {0x1f, 0x3f, 0x3f}, 88 | {0x1f, 0x37, 0x3f}, 89 | {0x1f, 0x2f, 0x3f}, 90 | {0x1f, 0x27, 0x3f}, 91 | {0x2d, 0x2d, 0x3f}, 92 | {0x31, 0x2d, 0x3f}, 93 | {0x36, 0x2d, 0x3f}, 94 | {0x3a, 0x2d, 0x3f}, 95 | {0x3f, 0x2d, 0x3f}, 96 | {0x3f, 0x2d, 0x3a}, 97 | {0x3f, 0x2d, 0x36}, 98 | {0x3f, 0x2d, 0x31}, 99 | {0x3f, 0x2d, 0x2d}, 100 | {0x3f, 0x31, 0x2d}, 101 | {0x3f, 0x36, 0x2d}, 102 | {0x3f, 0x3a, 0x2d}, 103 | {0x3f, 0x3f, 0x2d}, 104 | {0x3a, 0x3f, 0x2d}, 105 | {0x36, 0x3f, 0x2d}, 106 | {0x31, 0x3f, 0x2d}, 107 | {0x2d, 0x3f, 0x2d}, 108 | {0x2d, 0x3f, 0x31}, 109 | {0x2d, 0x3f, 0x36}, 110 | {0x2d, 0x3f, 0x3a}, 111 | {0x2d, 0x3f, 0x3f}, 112 | {0x2d, 0x3a, 0x3f}, 113 | {0x2d, 0x36, 0x3f}, 114 | {0x2d, 0x31, 0x3f}, 115 | {0x00, 0x00, 0x1c}, 116 | {0x07, 0x00, 0x1c}, 117 | {0x0e, 0x00, 0x1c}, 118 | {0x15, 0x00, 0x1c}, 119 | {0x1c, 0x00, 0x1c}, 120 | {0x1c, 0x00, 0x15}, 121 | {0x1c, 0x00, 0x0e}, 122 | {0x1c, 0x00, 0x07}, 123 | {0x1c, 0x00, 0x00}, 124 | {0x1c, 0x07, 0x00}, 125 | {0x1c, 0x0e, 0x00}, 126 | {0x1c, 0x15, 0x00}, 127 | {0x1c, 0x1c, 0x00}, 128 | {0x15, 0x1c, 0x00}, 129 | {0x0e, 0x1c, 0x00}, 130 | {0x07, 0x1c, 0x00}, 131 | {0x00, 0x1c, 0x00}, 132 | {0x00, 0x1c, 0x07}, 133 | {0x00, 0x1c, 0x0e}, 134 | {0x00, 0x1c, 0x15}, 135 | {0x00, 0x1c, 0x1c}, 136 | {0x00, 0x15, 0x1c}, 137 | {0x00, 0x0e, 0x1c}, 138 | {0x00, 0x07, 0x1c}, 139 | {0x0e, 0x0e, 0x1c}, 140 | {0x11, 0x0e, 0x1c}, 141 | {0x15, 0x0e, 0x1c}, 142 | {0x18, 0x0e, 0x1c}, 143 | {0x1c, 0x0e, 0x1c}, 144 | {0x1c, 0x0e, 0x18}, 145 | {0x1c, 0x0e, 0x15}, 146 | {0x1c, 0x0e, 0x11}, 147 | {0x1c, 0x0e, 0x0e}, 148 | {0x1c, 0x11, 0x0e}, 149 | {0x1c, 0x15, 0x0e}, 150 | {0x1c, 0x18, 0x0e}, 151 | {0x1c, 0x1c, 0x0e}, 152 | {0x18, 0x1c, 0x0e}, 153 | {0x15, 0x1c, 0x0e}, 154 | {0x11, 0x1c, 0x0e}, 155 | {0x0e, 0x1c, 0x0e}, 156 | {0x0e, 0x1c, 0x11}, 157 | {0x0e, 0x1c, 0x15}, 158 | {0x0e, 0x1c, 0x18}, 159 | {0x0e, 0x1c, 0x1c}, 160 | {0x0e, 0x18, 0x1c}, 161 | {0x0e, 0x15, 0x1c}, 162 | {0x0e, 0x11, 0x1c}, 163 | {0x14, 0x14, 0x1c}, 164 | {0x16, 0x14, 0x1c}, 165 | {0x18, 0x14, 0x1c}, 166 | {0x1a, 0x14, 0x1c}, 167 | {0x1c, 0x14, 0x1c}, 168 | {0x1c, 0x14, 0x1a}, 169 | {0x1c, 0x14, 0x18}, 170 | {0x1c, 0x14, 0x16}, 171 | {0x1c, 0x14, 0x14}, 172 | {0x1c, 0x16, 0x14}, 173 | {0x1c, 0x18, 0x14}, 174 | {0x1c, 0x1a, 0x14}, 175 | {0x1c, 0x1c, 0x14}, 176 | {0x1a, 0x1c, 0x14}, 177 | {0x18, 0x1c, 0x14}, 178 | {0x16, 0x1c, 0x14}, 179 | {0x14, 0x1c, 0x14}, 180 | {0x14, 0x1c, 0x16}, 181 | {0x14, 0x1c, 0x18}, 182 | {0x14, 0x1c, 0x1a}, 183 | {0x14, 0x1c, 0x1c}, 184 | {0x14, 0x1a, 0x1c}, 185 | {0x14, 0x18, 0x1c}, 186 | {0x14, 0x16, 0x1c}, 187 | {0x00, 0x00, 0x10}, 188 | {0x04, 0x00, 0x10}, 189 | {0x08, 0x00, 0x10}, 190 | {0x0c, 0x00, 0x10}, 191 | {0x10, 0x00, 0x10}, 192 | {0x10, 0x00, 0x0c}, 193 | {0x10, 0x00, 0x08}, 194 | {0x10, 0x00, 0x04}, 195 | {0x10, 0x00, 0x00}, 196 | {0x10, 0x04, 0x00}, 197 | {0x10, 0x08, 0x00}, 198 | {0x10, 0x0c, 0x00}, 199 | {0x10, 0x10, 0x00}, 200 | {0x0c, 0x10, 0x00}, 201 | {0x08, 0x10, 0x00}, 202 | {0x04, 0x10, 0x00}, 203 | {0x00, 0x10, 0x00}, 204 | {0x00, 0x10, 0x04}, 205 | {0x00, 0x10, 0x08}, 206 | {0x00, 0x10, 0x0c}, 207 | {0x00, 0x10, 0x10}, 208 | {0x00, 0x0c, 0x10}, 209 | {0x00, 0x08, 0x10}, 210 | {0x00, 0x04, 0x10}, 211 | {0x08, 0x08, 0x10}, 212 | {0x0a, 0x08, 0x10}, 213 | {0x0c, 0x08, 0x10}, 214 | {0x0e, 0x08, 0x10}, 215 | {0x10, 0x08, 0x10}, 216 | {0x10, 0x08, 0x0e}, 217 | {0x10, 0x08, 0x0c}, 218 | {0x10, 0x08, 0x0a}, 219 | {0x10, 0x08, 0x08}, 220 | {0x10, 0x0a, 0x08}, 221 | {0x10, 0x0c, 0x08}, 222 | {0x10, 0x0e, 0x08}, 223 | {0x10, 0x10, 0x08}, 224 | {0x0e, 0x10, 0x08}, 225 | {0x0c, 0x10, 0x08}, 226 | {0x0a, 0x10, 0x08}, 227 | {0x08, 0x10, 0x08}, 228 | {0x08, 0x10, 0x0a}, 229 | {0x08, 0x10, 0x0c}, 230 | {0x08, 0x10, 0x0e}, 231 | {0x08, 0x10, 0x10}, 232 | {0x08, 0x0e, 0x10}, 233 | {0x08, 0x0c, 0x10}, 234 | {0x08, 0x0a, 0x10}, 235 | {0x0b, 0x0b, 0x10}, 236 | {0x0c, 0x0b, 0x10}, 237 | {0x0d, 0x0b, 0x10}, 238 | {0x0f, 0x0b, 0x10}, 239 | {0x10, 0x0b, 0x10}, 240 | {0x10, 0x0b, 0x0f}, 241 | {0x10, 0x0b, 0x0d}, 242 | {0x10, 0x0b, 0x0c}, 243 | {0x10, 0x0b, 0x0b}, 244 | {0x10, 0x0c, 0x0b}, 245 | {0x10, 0x0d, 0x0b}, 246 | {0x10, 0x0f, 0x0b}, 247 | {0x10, 0x10, 0x0b}, 248 | {0x0f, 0x10, 0x0b}, 249 | {0x0d, 0x10, 0x0b}, 250 | {0x0c, 0x10, 0x0b}, 251 | {0x0b, 0x10, 0x0b}, 252 | {0x0b, 0x10, 0x0c}, 253 | {0x0b, 0x10, 0x0d}, 254 | {0x0b, 0x10, 0x0f}, 255 | {0x0b, 0x10, 0x10}, 256 | {0x0b, 0x0f, 0x10}, 257 | {0x0b, 0x0d, 0x10}, 258 | {0x0b, 0x0c, 0x10}, 259 | {0x00, 0x00, 0x00}, 260 | {0x00, 0x00, 0x00}, 261 | {0x00, 0x00, 0x00}, 262 | {0x00, 0x00, 0x00}, 263 | {0x00, 0x00, 0x00}, 264 | {0x00, 0x00, 0x00}, 265 | {0x00, 0x00, 0x00}, 266 | {0x00, 0x00, 0x00} 267 | }; 268 | uint16_t cursor_x=0, cursor_y=0; 269 | bool graphic = false; 270 | 271 | void _cli(void); 272 | void _sti(void); 273 | void out_port(uint16_t port, uint8_t v); 274 | 275 | void gc_configure(void){ 276 | _cli(); 277 | out_port(0x3ce, 0x6); 278 | out_port(0x3cf, 0x1); 279 | _sti(); 280 | } 281 | 282 | void dac_configure(void){ 283 | _cli(); 284 | out_port(0x3c8, 0); 285 | for(int i=0; i<0x100; i++){ 286 | out_port(0x3c9, palette[i].red); 287 | out_port(0x3c9, palette[i].green); 288 | out_port(0x3c9, palette[i].blue); 289 | } 290 | _sti(); 291 | } 292 | 293 | void init_vga(void){ 294 | dac_configure(); 295 | //gc_configure(); 296 | } 297 | 298 | void scroll_page(uint8_t n){ 299 | uint16_t i; 300 | uint16_t *vram = (uint16_t*)0xb8000; 301 | 302 | for(i=0; i<(0x19-n)*0x28; i++) 303 | vram[i] = vram[n*0x28+i]; 304 | for(; i<0x19*0x28; i++) 305 | vram[i] = 0x0700; 306 | 307 | cursor_x = 0; 308 | cursor_y -= n; 309 | } 310 | 311 | uint32_t put_text(const uint8_t *s){ 312 | uint16_t i; 313 | uint16_t *vram = (uint16_t*)0xb8000; 314 | 315 | if(graphic) 316 | return 0; 317 | 318 | for(i=0; s[i]; i++){ 319 | vram[cursor_y*0x28 + cursor_x] = 0x0700 + s[i]; 320 | cursor_x++; 321 | if(cursor_x >= 0x28 || !(s[i]^0x0a)){ 322 | cursor_x = 0; 323 | cursor_y++; 324 | } 325 | 326 | if(cursor_y >= 0x19) 327 | scroll_page(1); 328 | } 329 | 330 | return i; 331 | } 332 | 333 | void set_graphicmode(void){ 334 | graphic = true; 335 | 336 | _cli(); 337 | out_port(0x3c4, 2); 338 | out_port(0x3c5, 0x4); 339 | out_port(0x3c4, 4); 340 | out_port(0x3c5, 0x6); 341 | 342 | out_port(0x3ce, 5); 343 | out_port(0x3cf, 0x0); 344 | out_port(0x3ce, 6); 345 | out_port(0x3cf, 0x5); 346 | _sti(); 347 | } 348 | 349 | -------------------------------------------------------------------------------- /util/Makefile: -------------------------------------------------------------------------------- 1 | TARGET := util.a 2 | 3 | SRCS := debug.cpp 4 | OBJS := $(SRCS:.cpp=.o) 5 | DEPS := $(SRCS:.cpp=.d) 6 | 7 | CXXFLAGS := -Wall -MMD -std=c++11 -I../include $(DEBUG) 8 | 9 | .PHONY: all 10 | all: $(TARGET) 11 | 12 | -include $(DEPS) 13 | 14 | $(TARGET): $(OBJS) 15 | $(AR) rcs $@ $^ 16 | 17 | .PHONY: clean 18 | clean: 19 | $(RM) $(DEPS) $(OBJS) $(TARGET) 20 | -------------------------------------------------------------------------------- /util/debug.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include "util/debug.hpp" 6 | 7 | struct TypeSet { 8 | const char *name; 9 | FILE* fp; 10 | bool fatal; 11 | }; 12 | TypeSet typeset[] = { 13 | {"ASSERT", stderr, true}, 14 | {"ERROR", stderr, true}, 15 | {"WARN", stderr, false}, 16 | {"INFO", stdout, false}, 17 | {NULL, stdout, false}, 18 | }; 19 | 20 | unsigned debug_level = 0; 21 | 22 | void debug_print(const int type, const char *file, const char *function, int line, unsigned level, const char *fmt, ...){ 23 | va_list ap; 24 | TypeSet ts = typeset[type]; 25 | 26 | if(ts.fatal) 27 | goto print; 28 | 29 | if(level>0 && !((1<<(level-1)) & debug_level)) 30 | return; 31 | 32 | print: 33 | if(ts.name){ 34 | fprintf(ts.fp, level ? "[%s_%d] " : "[%s] ", ts.name, level); 35 | fprintf(ts.fp, "%s (%s:%d) ", function, file, line); 36 | } 37 | 38 | va_start(ap, fmt); 39 | vfprintf(ts.fp, fmt, ap); 40 | va_end(ap); 41 | 42 | if(ts.name) 43 | fprintf(ts.fp, "\n"); 44 | 45 | if(ts.fatal) 46 | //exit(-1); 47 | throw -1; 48 | } 49 | 50 | void set_debuglv(const char *verbose){ 51 | /* 52 | int i = 0; 53 | 54 | if(verbose) 55 | for(; verbose[i]=='v'; i++); 56 | 57 | debug_level = i+1; 58 | */ 59 | debug_level = atoi(verbose); 60 | } 61 | --------------------------------------------------------------------------------