added source code generation for interrupt handling
This commit is contained in:
parent
e41b942c38
commit
352e211fb0
10 changed files with 369 additions and 1 deletions
2
.gitignore
vendored
2
.gitignore
vendored
|
@ -13,3 +13,5 @@ iso/kernel
|
||||||
*.firm
|
*.firm
|
||||||
html/
|
html/
|
||||||
latex/
|
latex/
|
||||||
|
int.s
|
||||||
|
regs.h
|
||||||
|
|
12
config.py
12
config.py
|
@ -89,3 +89,15 @@ if "ENABLE_FRAMEBUFFER_UNICODE" in config:
|
||||||
p.stdin.write(l.encode("UTF-8"))
|
p.stdin.write(l.encode("UTF-8"))
|
||||||
p.stdin.close()
|
p.stdin.close()
|
||||||
p.wait()
|
p.wait()
|
||||||
|
|
||||||
|
print("Generating sourcecode…")
|
||||||
|
int_handler = open("kernel/arch/"+config["ARCH"]+"/int.s","w")
|
||||||
|
import os
|
||||||
|
try:
|
||||||
|
os.makedirs("kernel/arch/"+config["ARCH"]+"/include")
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
reg_struct = open("kernel/arch/"+config["ARCH"]+"/include/regs.h","w")
|
||||||
|
exec(open("kernel/arch/"+config["ARCH"]+"/sourcegen.py").read())
|
||||||
|
int_handler.close()
|
||||||
|
reg_struct.close()
|
||||||
|
|
87
kernel/arch/arm/sourcegen.py
Normal file
87
kernel/arch/arm/sourcegen.py
Normal file
|
@ -0,0 +1,87 @@
|
||||||
|
int_handler.write(
|
||||||
|
"""\
|
||||||
|
.arm
|
||||||
|
.fpu vfpv2
|
||||||
|
.global branch_macro
|
||||||
|
branch_macro:
|
||||||
|
ldr pc, [pc, #-4] //Load the next word into PC
|
||||||
|
.global data_abort
|
||||||
|
data_abort:
|
||||||
|
sub lr, #4
|
||||||
|
push {r0-r12,lr}
|
||||||
|
ldr r0, =0
|
||||||
|
blx intr_common_handler
|
||||||
|
pop {r0-r12,pc}
|
||||||
|
.global fast_irq
|
||||||
|
fast_irq:
|
||||||
|
sub lr, #4
|
||||||
|
push {r0-r12,lr}
|
||||||
|
ldr r0, =1
|
||||||
|
blx intr_common_handler
|
||||||
|
pop {r0-r12,pc}
|
||||||
|
.global normal_irq
|
||||||
|
normal_irq:
|
||||||
|
sub lr, #4
|
||||||
|
push {r0-r12,lr}
|
||||||
|
ldr r0, =2
|
||||||
|
blx intr_common_handler
|
||||||
|
pop {r0-r12,pc}
|
||||||
|
.global prefetch_abort
|
||||||
|
prefetch_abort:
|
||||||
|
sub lr, #4
|
||||||
|
push {r0-r12,lr}
|
||||||
|
ldr r0, =3
|
||||||
|
blx intr_common_handler
|
||||||
|
pop {r0-r12,pc}
|
||||||
|
.global svc_call
|
||||||
|
svc_call:
|
||||||
|
push {r0-r12,lr}
|
||||||
|
ldr r0, =4
|
||||||
|
blx intr_common_handler
|
||||||
|
pop {r0-r12,pc}
|
||||||
|
.global undefined_op
|
||||||
|
undefined_op:
|
||||||
|
push {r0-r12,lr}
|
||||||
|
ldr r0, =5
|
||||||
|
blx intr_common_handler
|
||||||
|
pop {r0-r12,pc}
|
||||||
|
|
||||||
|
.extern handleINT
|
||||||
|
intr_common_handler:
|
||||||
|
""")
|
||||||
|
push_regs=[]
|
||||||
|
pop_regs=[]
|
||||||
|
if ("ENABLE_HARD" in config) and config["ENABLE_HARD"]:
|
||||||
|
#Save the registers
|
||||||
|
for i,j in enumerate(["fpsid","fpscr","fpexc"]):
|
||||||
|
push_regs.append("fmrx r"+str(i+1)+", "+j)
|
||||||
|
pop_regs.append("fmxr "+j+", r"+str(i+1))
|
||||||
|
push_regs.append("push {r1,r2,r3,r4,r5}")
|
||||||
|
pop_regs.append("pop {r1,r2,r3,r4,r5}")
|
||||||
|
push_regs.append("vpush {d0-d15}")
|
||||||
|
pop_regs.append("vpop {d0-d15}")
|
||||||
|
push_regs.append("mov r1, sp")
|
||||||
|
pop_regs.append("mov sp, r0")
|
||||||
|
|
||||||
|
for opc in push_regs:
|
||||||
|
int_handler.write(" "+opc+"\n")
|
||||||
|
int_handler.write(" blx handleINT\n")
|
||||||
|
for opc in reversed(pop_regs):
|
||||||
|
int_handler.write(" "+opc+"\n")
|
||||||
|
int_handler.write(" bx lr\n")
|
||||||
|
|
||||||
|
int_handler.write(".global panic\n.extern panic2\npanic:\n push {r0-r12,lr}\n")
|
||||||
|
for opc in push_regs:
|
||||||
|
int_handler.write(" "+opc+"\n")
|
||||||
|
int_handler.write(" b panic\n")
|
||||||
|
|
||||||
|
reg_struct.write("#include <stdint.h>\nstruct cpu_state {\n")
|
||||||
|
if ("ENABLE_HARD" in config) and config["ENABLE_HARD"]:
|
||||||
|
for reg in ["fpsid","fpscr","fpexc"]:
|
||||||
|
reg_struct.write(" uint32_t "+reg+";\n")
|
||||||
|
for reg in ("d"+str(i) for i in range(16)):
|
||||||
|
reg_struct.write(" double "+reg+";\n")
|
||||||
|
for i in range(13):
|
||||||
|
reg_struct.write(" uint32_t r"+str(i)+";\n")
|
||||||
|
reg_struct.write(" uint32_t pc;\n};")
|
||||||
|
|
73
kernel/arch/x86/sourcegen.py
Normal file
73
kernel/arch/x86/sourcegen.py
Normal file
|
@ -0,0 +1,73 @@
|
||||||
|
print("Writing interrupt stubs")
|
||||||
|
int_handler.write(".macro intr_stub nr\n.global intr_stub_\\nr\n.align 16\nintr_stub_\\nr:\n pushl $0\n pushl $\\nr\n jmp intr_common_handler\n.endm\n.macro intr_stub_error_code nr\n.global intr_stub_\\nr\n.align 16\nintr_stub_\\nr:\n pushl $\\nr\n jmp intr_common_handler\n.endm\n")
|
||||||
|
for i in range(256):
|
||||||
|
if i in [8,10,11,12,13,14,17]:
|
||||||
|
int_handler.write("intr_stub_error_code "+str(i)+"\n")
|
||||||
|
else:
|
||||||
|
int_handler.write("intr_stub "+str(i)+"\n")
|
||||||
|
|
||||||
|
int_handler.write(".extern handleINT\n")
|
||||||
|
int_handler.write("intr_common_handler:\n")
|
||||||
|
int_handler.write(" cli\n")
|
||||||
|
print("Generating register save/restore")
|
||||||
|
all_regs_push=[]
|
||||||
|
all_regs_pop=[]
|
||||||
|
data_section=""
|
||||||
|
for reg in ["ebp","edi","esi","edx","ecx","ebx","eax"]:
|
||||||
|
all_regs_push.append("push %"+reg)
|
||||||
|
all_regs_pop.append("pop %"+reg)
|
||||||
|
if config["ENABLE_FPU"] and not config["ENABLE_SSE"]:
|
||||||
|
data_section+="fsave_reg:\n .space 108\n"
|
||||||
|
all_regs_push.append("fsave fsave_reg")
|
||||||
|
all_regs_pop.append("frstor fsave_reg")
|
||||||
|
all_regs_push.append("pushl $fsave_reg")
|
||||||
|
if config["ENABLE_SSE"]:
|
||||||
|
data_section+=".align 16\nfxsave_reg:\n .space 512"
|
||||||
|
all_regs_push.append("fxsave fxsave_reg")
|
||||||
|
all_regs_pop.append("fxrstor fxsave_reg")
|
||||||
|
all_regs_push.append("pushl $fxsave_reg")
|
||||||
|
|
||||||
|
print("Writing interrupt handler")
|
||||||
|
for ins in all_regs_push:
|
||||||
|
int_handler.write(" "+ins+"\n")
|
||||||
|
int_handler.write(" push %esp\n call handleINT\n mov %eax, %esp\n")
|
||||||
|
for ins in reversed(all_regs_pop):
|
||||||
|
int_handler.write(" "+ins+"\n")
|
||||||
|
int_handler.write(" add $8, %esp\n iret\n")
|
||||||
|
|
||||||
|
print("Writing panic handler")
|
||||||
|
int_handler.write(".global panic\n.extern panic2\npanic:\n")
|
||||||
|
for ins in all_regs_push:
|
||||||
|
int_handler.write(" "+ins+"\n")
|
||||||
|
int_handler.write(" push %esp\n jmp panic2\n")
|
||||||
|
|
||||||
|
int_handler.write(".section .data\n"+data_section)
|
||||||
|
|
||||||
|
print("Generating cpu_state struct")
|
||||||
|
reg_struct.write("#include <stdint.h>\n")
|
||||||
|
if config["ENABLE_FPU"] and not config["ENABLE_SSE"]:
|
||||||
|
reg_struct.write("struct fpu_state {\n")
|
||||||
|
for reg in ["cwd","swd","twd","fip","fcs","foo","fos"]:
|
||||||
|
reg_struct.write(" uint32_t "+reg+";\n")
|
||||||
|
for reg in ("st"+str(i) for i in range(8)):
|
||||||
|
reg_struct.write(" __float80 "+reg+";\n")
|
||||||
|
reg_struct.write("}__attribute__((packed,aligned(16)));\n")
|
||||||
|
if config["ENABLE_SSE"]:
|
||||||
|
reg_struct.write("struct fpu_state {\n")
|
||||||
|
for reg in ["cwd","swd","twd","fop"]:
|
||||||
|
reg_struct.write(" uint16_t "+reg+";\n")
|
||||||
|
for reg in ["fip","fcs","foo","fos","mxcsr","mxcsr_mask"]:
|
||||||
|
reg_struct.write(" uint32_t "+reg+";\n")
|
||||||
|
for reg in range(8):
|
||||||
|
reg_struct.write(" __float80 st"+str(reg)+";\n")
|
||||||
|
reg_struct.write(" char buf"+str(reg)+"[6];\n")
|
||||||
|
for reg in range(16):
|
||||||
|
reg_struct.write(" __float128 xmm"+str(reg)+";\n")
|
||||||
|
reg_struct.write("}__attribute__((packed,aligned(16)));\n")
|
||||||
|
reg_struct.write("struct cpu_state {\n")
|
||||||
|
if config["ENABLE_FPU"]:
|
||||||
|
reg_struct.write(" fpu_state *fpu;\n")
|
||||||
|
for reg in ["eax","ebx","ecx","edx","esi","edi","ebp","intr","error","eip","cs","eflags","esp","ss"]:
|
||||||
|
reg_struct.write(" uint32_t "+reg+";\n")
|
||||||
|
reg_struct.write("}__attribute__((packed));")
|
||||||
|
|
73
kernel/arch/x86_64/sourcegen.py
Normal file
73
kernel/arch/x86_64/sourcegen.py
Normal file
|
@ -0,0 +1,73 @@
|
||||||
|
print("Writing interrupt stubs")
|
||||||
|
int_handler.write(".macro intr_stub nr\n.global intr_stub_\\nr\n.align 16\nintr_stub_\\nr:\n pushq $0\n pushq $\\nr\n jmp intr_common_handler\n.endm\n.macro intr_stub_error_code nr\n.global intr_stub_\\nr\n.align 16\nintr_stub_\\nr:\n pushq $\\nr\n jmp intr_common_handler\n.endm\n")
|
||||||
|
for i in range(256):
|
||||||
|
if i in [8,10,11,12,13,14,17]:
|
||||||
|
int_handler.write("intr_stub_error_code "+str(i)+"\n")
|
||||||
|
else:
|
||||||
|
int_handler.write("intr_stub "+str(i)+"\n")
|
||||||
|
|
||||||
|
int_handler.write(".extern handleINT\n")
|
||||||
|
int_handler.write("intr_common_handler:\n")
|
||||||
|
int_handler.write(" cli\n")
|
||||||
|
print("Generating register save/restore")
|
||||||
|
all_regs_push=[]
|
||||||
|
all_regs_pop=[]
|
||||||
|
data_section=""
|
||||||
|
for reg in ["r15","r14","r13","r12","r11","r10","r9","r8","rbp","rdi","rsi","rdx","rcx","rbx","rax"]:
|
||||||
|
all_regs_push.append("push %"+reg)
|
||||||
|
all_regs_pop.append("pop %"+reg)
|
||||||
|
if config["ENABLE_FPU"] and not config["ENABLE_SSE"]:
|
||||||
|
data_section+="fsave_reg:\n .space 108\n"
|
||||||
|
all_regs_push.append("fsave fsave_reg")
|
||||||
|
all_regs_pop.append("frstor fsave_reg")
|
||||||
|
all_regs_push.append("pushq $fsave_reg")
|
||||||
|
if config["ENABLE_SSE"]:
|
||||||
|
data_section+=".align 16\nfxsave_reg:\n .space 512"
|
||||||
|
all_regs_push.append("fxsave fxsave_reg")
|
||||||
|
all_regs_pop.append("fxrstor fxsave_reg")
|
||||||
|
all_regs_push.append("pushq $fxsave_reg")
|
||||||
|
|
||||||
|
print("Writing interrupt handler")
|
||||||
|
for ins in all_regs_push:
|
||||||
|
int_handler.write(" "+ins+"\n")
|
||||||
|
int_handler.write(" mov %rsp, %rdi\n call handleINT\n mov %rax, %rsp\n")
|
||||||
|
for ins in reversed(all_regs_pop):
|
||||||
|
int_handler.write(" "+ins+"\n")
|
||||||
|
int_handler.write(" add $8, %esp\n iret\n")
|
||||||
|
|
||||||
|
print("Writing panic handler")
|
||||||
|
int_handler.write(".global panic\n.extern panic2\npanic:\n")
|
||||||
|
for ins in all_regs_push:
|
||||||
|
int_handler.write(" "+ins+"\n")
|
||||||
|
int_handler.write(" mov %rsp, %rdi\n jmp panic2\n")
|
||||||
|
|
||||||
|
int_handler.write(".section .data\n"+data_section)
|
||||||
|
|
||||||
|
print("Generating cpu_state struct")
|
||||||
|
reg_struct.write("#include <stdint.h>\n")
|
||||||
|
if config["ENABLE_FPU"] and not config["ENABLE_SSE"]:
|
||||||
|
reg_struct.write("struct fpu_state {\n")
|
||||||
|
for reg in ["cwd","swd","twd","fip","fcs","foo","fos"]:
|
||||||
|
reg_struct.write(" uint32_t "+reg+";\n")
|
||||||
|
for reg in ("st"+str(i) for i in range(8)):
|
||||||
|
reg_struct.write(" __float80 "+reg+";\n")
|
||||||
|
reg_struct.write("}__attribute__((packed,aligned(16)));\n")
|
||||||
|
if config["ENABLE_SSE"]:
|
||||||
|
reg_struct.write("struct fpu_state {\n")
|
||||||
|
for reg in ["cwd","swd","twd","fop"]:
|
||||||
|
reg_struct.write(" uint16_t "+reg+";\n")
|
||||||
|
for reg in ["fip","fcs","foo","fos","mxcsr","mxcsr_mask"]:
|
||||||
|
reg_struct.write(" uint32_t "+reg+";\n")
|
||||||
|
for reg in range(8):
|
||||||
|
reg_struct.write(" __float80 st"+str(reg)+";\n")
|
||||||
|
reg_struct.write(" char buf"+str(reg)+"[6];\n")
|
||||||
|
for reg in range(16):
|
||||||
|
reg_struct.write(" __float128 xmm"+str(reg)+";\n")
|
||||||
|
reg_struct.write("}__attribute__((packed,aligned(16)));\n")
|
||||||
|
reg_struct.write("struct cpu_state {\n")
|
||||||
|
if config["ENABLE_FPU"]:
|
||||||
|
reg_struct.write(" fpu_state *fpu;\n")
|
||||||
|
for reg in ["rax","rbx","rcx","rdx","rsi","rdi","rbp","r8","r9","r10","r11","r12","r13","r14","r15","intr","error","rip","cs","rflags","rsp","ss"]:
|
||||||
|
reg_struct.write(" uint64_t "+reg+";\n")
|
||||||
|
reg_struct.write("}__attribute__((packed));")
|
||||||
|
|
|
@ -20,7 +20,8 @@ PICAfb::PICAfb() : Framebuffer(25, 30) {
|
||||||
*((uint32_t *)0x10202A40) = 0x3F; // Bottom screen brightness
|
*((uint32_t *)0x10202A40) = 0x3F; // Bottom screen brightness
|
||||||
*((uint32_t *)0x10202244) = 0x1023E;
|
*((uint32_t *)0x10202244) = 0x1023E;
|
||||||
*((uint32_t *)0x10202A44) = 0x1023E;
|
*((uint32_t *)0x10202A44) = 0x1023E;
|
||||||
|
// TODO this code is ugly and copied right out of the arm9loaderhax git
|
||||||
|
// find out what 90% of this does
|
||||||
// Top screen
|
// Top screen
|
||||||
*(volatile uint32_t *)0x10400400 = 0x000001c2;
|
*(volatile uint32_t *)0x10400400 = 0x000001c2;
|
||||||
*(volatile uint32_t *)0x10400404 = 0x000000d1;
|
*(volatile uint32_t *)0x10400404 = 0x000000d1;
|
||||||
|
|
82
kernel/hw/pc/8259/pic.cpp
Normal file
82
kernel/hw/pc/8259/pic.cpp
Normal file
|
@ -0,0 +1,82 @@
|
||||||
|
#include "pic.hpp"
|
||||||
|
#include "../io.hpp"
|
||||||
|
#define PIC1 0x20
|
||||||
|
#define PIC2 0xA0
|
||||||
|
#define PIC1_COMMAND PIC1
|
||||||
|
#define PIC1_DATA (PIC1 + 1)
|
||||||
|
#define PIC2_COMMAND PIC2
|
||||||
|
#define PIC2_DATA (PIC2 + 1)
|
||||||
|
|
||||||
|
#define PIC_EOI 0x20
|
||||||
|
#define ICW1_ICW4 0x01
|
||||||
|
#define ICW1_SINGLE 0x02
|
||||||
|
#define ICW1_INTERVAL4 0x04
|
||||||
|
#define ICW1_LEVEL 0x08
|
||||||
|
#define ICW1_INIT 0x10
|
||||||
|
|
||||||
|
#define ICW4_8086 0x01
|
||||||
|
#define ICW4_AUTO 0x02
|
||||||
|
#define ICW4_BUF_SLAVE 0x04
|
||||||
|
#define ICW4_BUF_MASTER 0x0C
|
||||||
|
#define ICW4_SFNM 0x10
|
||||||
|
namespace PIC {
|
||||||
|
auto sendEOI(bool slave) -> void {
|
||||||
|
if (slave) { out<unsigned char>(PIC2_COMMAND, PIC_EOI); }
|
||||||
|
out<unsigned char>(PIC1_COMMAND, PIC_EOI);
|
||||||
|
}
|
||||||
|
auto initPIC(int off1, int off2) -> void {
|
||||||
|
uint8_t a1 = in<uint8_t>(PIC1_DATA);
|
||||||
|
uint8_t a2 = in<uint8_t>(PIC2_DATA);
|
||||||
|
|
||||||
|
out<uint8_t>(PIC1_COMMAND, ICW1_INIT + ICW1_ICW4);
|
||||||
|
out<uint8_t>(PIC2_COMMAND, ICW1_INIT + ICW1_ICW4);
|
||||||
|
out<uint8_t>(PIC1_DATA, off1);
|
||||||
|
out<uint8_t>(PIC2_DATA, off2);
|
||||||
|
out<uint8_t>(PIC1_DATA, 4); // Slave at 2
|
||||||
|
out<uint8_t>(PIC2_DATA, 2); // Self at 2
|
||||||
|
|
||||||
|
out<uint8_t>(PIC1_DATA, ICW4_8086);
|
||||||
|
out<uint8_t>(PIC2_DATA, ICW4_8086);
|
||||||
|
|
||||||
|
out(PIC1_DATA, a1);
|
||||||
|
out(PIC2_DATA, a2);
|
||||||
|
}
|
||||||
|
auto disable() -> void {
|
||||||
|
out<uint8_t>(PIC1_DATA, 0xFF);
|
||||||
|
out<uint8_t>(PIC2_DATA, 0xFF);
|
||||||
|
}
|
||||||
|
auto mask(int no) -> void {
|
||||||
|
if (no < 8) {
|
||||||
|
out<uint8_t>(PIC1_DATA, in<uint8_t>(PIC1_DATA) | (1 << no));
|
||||||
|
} else {
|
||||||
|
no -= 8;
|
||||||
|
out<uint8_t>(PIC2_DATA, in<uint8_t>(PIC2_DATA) | (1 << no));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
auto unmask(int no) -> void {
|
||||||
|
if (no < 8) {
|
||||||
|
out<uint8_t>(PIC1_DATA, in<uint8_t>(PIC1_DATA) & ~(1 << no));
|
||||||
|
} else {
|
||||||
|
no -= 8;
|
||||||
|
out<uint8_t>(PIC2_DATA, in<uint8_t>(PIC2_DATA) & ~(1 << no));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
auto disableSlave() -> void { mask(2); }
|
||||||
|
auto enableSlave() -> void { unmask(2); }
|
||||||
|
auto isSpurious(bool slave) -> bool {
|
||||||
|
if (slave) {
|
||||||
|
out<uint8_t>(PIC2_COMMAND, 0x0B);
|
||||||
|
io_wait();
|
||||||
|
if (!(in<uint8_t>(PIC2_DATA) & 0x80)) {
|
||||||
|
sendEOI(false);
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
out<uint8_t>(PIC1_COMMAND, 0x0B);
|
||||||
|
io_wait();
|
||||||
|
return (in<uint8_t>(PIC1_DATA) & 0x80) ? true : false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
15
kernel/hw/pc/8259/pic.hpp
Normal file
15
kernel/hw/pc/8259/pic.hpp
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
#pragma once
|
||||||
|
#include <stdint.h>
|
||||||
|
/**
|
||||||
|
* Namespace contains function to control the Programmable Interrupt Controller
|
||||||
|
*/
|
||||||
|
namespace PIC {
|
||||||
|
auto sendEOI(bool slave) -> void; ///< Signals the PIC that the interrupt has ended
|
||||||
|
auto initPIC(int off1, int off2) -> void; ///< Initializes the pic/remaps it
|
||||||
|
auto disable() -> void; ///< disables PIC completely
|
||||||
|
auto maskIRQ(int no) -> void; ///< disables a single IRQ
|
||||||
|
auto unmaskIRQ(int no) -> void; ///< reenables a single IRQ
|
||||||
|
auto disableSlave() -> void; ///< disables IRQ2 and 8-15
|
||||||
|
auto enableSlave() -> void; ///< reenables at least IRQ2
|
||||||
|
auto isSpurious(bool slave) -> bool; ///< Return if this isn't an actual IRQ.
|
||||||
|
}
|
|
@ -6,3 +6,5 @@ if config["ENABLE_FRAMEBUFFER"]:
|
||||||
add_driver(False, "vesafb")
|
add_driver(False, "vesafb")
|
||||||
else:
|
else:
|
||||||
add_driver(False, "cgaterm")
|
add_driver(False, "cgaterm")
|
||||||
|
add_driver(False, "8259")
|
||||||
|
add_driver(False, "idt")
|
||||||
|
|
21
kernel/hw/pc/io.hpp
Normal file
21
kernel/hw/pc/io.hpp
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
template <typename T>
|
||||||
|
static void out(uint16_t port, T val) {
|
||||||
|
if (sizeof(T) == 1)
|
||||||
|
asm volatile("outb %0, %1" : : "a"(val), "Nd"(port));
|
||||||
|
else if (sizeof(T) == 2)
|
||||||
|
asm volatile("outw %0, %1" : : "a"(val), "Nd"(port));
|
||||||
|
else if (sizeof(T) == 4)
|
||||||
|
asm volatile("outl %0, %1" : : "a"(val), "Nd"(port));
|
||||||
|
}
|
||||||
|
template <typename T>
|
||||||
|
static T in(uint16_t port) {
|
||||||
|
T val = 0;
|
||||||
|
if (sizeof(T) == 1)
|
||||||
|
asm volatile("inb %1, %0" : "=a"(val) : "Nd"(port));
|
||||||
|
else if (sizeof(T) == 2)
|
||||||
|
asm volatile("inw %1, %0" : "=a"(val) : "Nd"(port));
|
||||||
|
else if (sizeof(T) == 4)
|
||||||
|
asm volatile("inl %1, %0" : "=a"(val) : "Nd"(port));
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
static void io_wait() { out<unsigned char>(0x80, 0); }
|
Loading…
Reference in a new issue