syscall and trap frame work

This commit is contained in:
icexin committed 2021-07-25 00:27:54 +08:00
1 parent fff454eb89
commit 22f6fd156f
13 files changed
+1033 -46

No files matched your search

+1 -1
View File
@@ -15,7 +15,7 @@ mouse: enabled=0
#display_library: x, options="gui_debug"
#display_library: nogui
log:bochs.log
#log:bochs.log
debug: action=ignore, cpu0=report
#info: action=report
magic_break:enabled=1
+4 -27
View File
@@ -10,6 +10,10 @@ TEXT ·rt0(SB), NOSPLIT, $0-0
// never return
TEXT ·go_entry(SB), NOSPLIT, $0
SUBQ $256, SP
PUSHQ SP
CALL ·prepareArgs(SB)
ADDQ $8, SP
JMP _rt0_amd64_linux(SB)
TEXT ·sseInit(SB), NOSPLIT, $0
@@ -22,33 +26,6 @@ TEXT ·sseInit(SB), NOSPLIT, $0
MOVL AX, CR4
RET
TEXT ·lgdt(SB), NOSPLIT, $0-8
MOVQ gdtptr+0(FP), AX
LGDT (AX)
RET
TEXT ·lidt(SB), NOSPLIT, $0-8
MOVQ idtptr+0(FP), AX
LIDT (AX)
RET
TEXT ·reloadCS(SB), NOSPLIT, $0
// save ip
MOVQ 0(SP), AX
// save sp
MOVQ SP, BX
ADDQ $8, BX
// rerange the stack, as in an interrupt stack
PUSHQ $0x10 // SS
PUSHQ BX
PUSHFQ
PUSHQ $8
PUSHQ AX
// IRET
IRETQ
TEXT ·rdmsr(SB),NOSPLIT,$0-16
MOVL reg+0(FP), CX
RDMSR
+52
View File
@@ -0,0 +1,52 @@
package kernel64
import (
"unsafe"
"github.com/icexin/eggos/sys"
"gvisor.dev/gvisor/pkg/abi/linux"
)
//go:nosplit
func envput(pbuf *[]byte, v uintptr) uintptr {
buf := *pbuf
*(*uintptr)(unsafe.Pointer(&buf[0])) = v
*pbuf = buf[unsafe.Sizeof(v):]
return uintptr(unsafe.Pointer(&buf[0]))
}
//go:nosplit
func envdup(pbuf *[]byte, s string) uintptr {
buf := *pbuf
copy(buf, s)
*pbuf = buf[len(s):]
return uintptr(unsafe.Pointer(&buf[0]))
}
//go:nosplit
func prepareArgs(sp uintptr) {
const argc = 1
buf := sys.UnsafeBuffer(sp, 256)
// put args
envput(&buf, argc)
argv0 := (*uintptr)(unsafe.Pointer(envput(&buf, 0)))
// end of args
envput(&buf, 0)
envTerm := (*uintptr)(unsafe.Pointer(envput(&buf, 0)))
envGoDebug := (*uintptr)(unsafe.Pointer(envput(&buf, 0)))
// end of env
envput(&buf, 0)
// put auxillary vector
envput(&buf, linux.AT_PAGESZ)
envput(&buf, sys.PageSize)
envput(&buf, linux.AT_NULL)
envput(&buf, 0)
// alloc memory for argv[0]
*argv0 = envdup(&buf, "eggos\x00")
*envTerm = envdup(&buf, "TERM=xterm\x00")
*envGoDebug = envdup(&buf, "GODEBUG=asyncpreemptoff=1\x00")
}
+13
View File
@@ -0,0 +1,13 @@
package mm
import "syscall"
// SysMmap like Mmap but can run in user mode
// wraper of syscall.Mmap
func SysMmap(vaddr, size uintptr) uintptr {
mem, _, err := syscall.Syscall6(syscall.SYS_MMAP, uintptr(vaddr), size, syscall.PROT_READ|syscall.PROT_WRITE, 0, 0, 0)
if err != 0 {
panic(err.Error())
}
return mem
}
+2 -3
View File
@@ -28,8 +28,7 @@ func preinit() {
mm.Init()
syscallInit()
uart.PreInit()
threadInit()
uart.WriteString("kernel64\n")
go_entry()
for {
}
schedule()
}
+34
View File
@@ -0,0 +1,34 @@
#include "textflag.h"
TEXT ·lgdt(SB), NOSPLIT, $0-8
MOVQ gdtptr+0(FP), AX
LGDT (AX)
RET
TEXT ·lidt(SB), NOSPLIT, $0-8
MOVQ idtptr+0(FP), AX
LIDT (AX)
RET
TEXT ·ltr(SB), NOSPLIT, $0-8
MOVQ sel+0(FP), AX
LTR AX
RET
TEXT ·reloadCS(SB), NOSPLIT, $0
// save ip
MOVQ 0(SP), AX
// save sp
MOVQ SP, BX
ADDQ $8, BX
// rerange the stack, as in an interrupt stack
PUSHQ $0x10 // SS
PUSHQ BX
PUSHFQ
PUSHQ $8
PUSHQ AX
// IRET
IRETQ
+51 -7
View File
@@ -11,12 +11,22 @@ const (
segDplUser = 0x60
)
const (
_KCODE_IDX = 1
_KDATA_IDX = 2
_UCODE_IDX = 3
_UDATA_IDX = 4
_TSS_IDX = 5
)
var (
gdt [5]gdtSegDesc
gdt [7]gdtSegDesc
gdtptr [10]byte
idt [256]idtSetDesc
idtptr [10]byte
tss [26]uint32
)
type gdtSegDesc [8]byte
@@ -36,12 +46,15 @@ func lgdt(gdtptr uintptr)
//go:nosplit
func lidt(idtptr uintptr)
//go:nosplit
func ltr(sel uintptr)
//go:nosplit
func reloadCS()
//go:nosplit
func setGdtCodeDesc(desc *gdtSegDesc, dpl uint8) {
desc[5] |= dpl | 0x98 // P=1 C=0
desc[5] |= dpl | 0x99 // P=1 C=0
desc[6] |= 0x20 // D=0 L=1
}
@@ -50,19 +63,44 @@ func setGdtDataDesc(desc *gdtSegDesc, dpl uint8) {
desc[5] |= dpl | 0x92 // P=1 W=1
}
//go:nosplit
func setTssDesc(lo, hi *gdtSegDesc, addr, limit uintptr) {
// tss limit 0-15
lo[0] = byte(limit)
lo[1] = byte(limit >> 8)
// tss base 0-15
lo[2] = byte(addr)
lo[3] = byte(addr >> 8)
// tss base 16-23
lo[4] = byte(addr >> 16)
// type 64 bit tss, P=1
lo[5] = 0x89
// limit 16-19 and AVL=1
lo[6] = 0x80 | byte(limit>>16)&0x07
// base addr 24-31 G=0
lo[7] = byte(addr >> 24)
// base addr 32-63
*(*uint32)(unsafe.Pointer(hi)) = uint32(addr >> 32)
}
//go:nosplit
func gdtInit() {
// leave gdt[0] untouch
setGdtCodeDesc(&gdt[1], segDplKernel)
setGdtDataDesc(&gdt[2], segDplKernel)
setGdtCodeDesc(&gdt[3], segDplUser)
setGdtDataDesc(&gdt[4], segDplUser)
// leave gdt[0] untouched
setGdtCodeDesc(&gdt[_KCODE_IDX], segDplKernel)
setGdtDataDesc(&gdt[_KDATA_IDX], segDplKernel)
setGdtCodeDesc(&gdt[_UCODE_IDX], segDplUser)
setGdtDataDesc(&gdt[_UDATA_IDX], segDplUser)
tssAddr := uintptr(unsafe.Pointer(&tss[0]))
tssLimit := uintptr(unsafe.Sizeof(tss)) - 1
setTssDesc(&gdt[_TSS_IDX], &gdt[_TSS_IDX+1], tssAddr, tssLimit)
limit := (*uint16)(unsafe.Pointer(&gdtptr[0]))
base := (*uint64)(unsafe.Pointer(&gdtptr[2]))
*limit = uint16(unsafe.Sizeof(gdt) - 1)
*base = uint64(uintptr(unsafe.Pointer(&gdt[0])))
lgdt(uintptr(unsafe.Pointer(&gdtptr[0])))
ltr(_TSS_IDX << 3)
reloadCS()
}
@@ -87,3 +125,9 @@ func idtInit() {
*base = uint64(uintptr(unsafe.Pointer(&idt[0])))
lidt(uintptr(unsafe.Pointer(&idtptr)))
}
//go:nosplit
func setTssSP0(addr uintptr) {
tss[1] = uint32(addr)
tss[2] = uint32(addr >> 32)
}
+92 -4
View File
@@ -1,8 +1,15 @@
package kernel64
import (
"syscall"
"github.com/icexin/eggos/debug"
"github.com/icexin/eggos/kernel/isyscall"
"github.com/icexin/eggos/kernel/trap"
"github.com/icexin/eggos/kernel64/mm"
"github.com/icexin/eggos/sys"
"github.com/icexin/eggos/uart"
"gvisor.dev/gvisor/pkg/abi/linux"
"gvisor.dev/gvisor/pkg/abi/linux/errno"
)
const (
@@ -12,27 +19,108 @@ const (
_MSR_IA32_EFER = 0xc0000080
_MSR_FS_BASE = 0xc0000100
_MSR_GS_BASE = 0xc0000101
_EFER_SCE = 1 << 0 // Enable SYSCALL.
)
//go:nosplit
func syscallEntry() {
uart.WriteString("syscall")
func syscallEntry()
//go:nosplit
func syscallIntr() {
my := Mythread()
tf := my.tf
my.systf = *tf
// SYSCALL store IP in RCX and FLAGS in R11
// tf.IP = tf.CX
// tf.FLAGS = tf.R11
// after we enter syscallIntr from SYSCALL,
// the CS changed to 8 and SS changed to 16,
// both need be changed to USER
// tf.CS = _UCODE_IDX<<3 | _RPL_USER
// tf.SS = _UDATA_IDX<<3 | _RPL_USER
req := tf.SyscallRequest()
doSyscall(&req)
tf.AX = req.Ret
}
//go:nosplit
func panicNosys() {
req := Mythread().systf.SyscallRequest()
debug.PrintStr("syscall not found:")
debug.PrintStr(sysnum[req.NO])
debug.PrintStr("\n")
for {
}
}
//go:nosplit
func doSyscall(req *isyscall.Request) {
switch req.NO {
case syscall.SYS_ARCH_PRCTL:
sysArchPrctl(req)
case syscall.SYS_SCHED_GETAFFINITY:
req.Ret = 0
case syscall.SYS_OPENAT:
req.Ret = isyscall.Errno(errno.ENOSYS)
case syscall.SYS_MMAP:
sysMmap(req)
case syscall.SYS_READ:
sysRead(req)
case syscall.SYS_CLOSE:
default:
changeReturnPC(Mythread().tf, sys.FuncPC(panicNosys))
}
}
//go:nosplit
func sysArchPrctl(req *isyscall.Request) {
switch req.Args[0] {
case linux.ARCH_SET_FS:
wrmsr(_MSR_FS_BASE, req.Args[1])
Mythread().fsBase = req.Args[1]
default:
req.Ret = errno.EINVAL
}
}
//go:nosplit
func sysMmap(req *isyscall.Request) {
addr := req.Args[0]
n := req.Args[1]
prot := req.Args[2]
// called on sysReserve
if prot == syscall.PROT_NONE {
req.Ret = mm.Sbrk(n)
return
}
// called on sysMap and sysAlloc
req.Ret = mm.Mmap(addr, n)
return
}
//go:nosplit
func sysRead(req *isyscall.Request) {
req.Ret = isyscall.Errno(errno.EINVAL)
return
}
//go:nosplit
func syscallInit() {
// write syscall selector
wrmsr(_MSR_STAR, 8<<32)
// clear IF when enter syscall
wrmsr(_MSR_FSTAR, 0x200)
// wrmsr(_MSR_FSTAR, 0x200)
// set syscall entry
wrmsr(_MSR_LSTAR, sys.FuncPC(syscallEntry))
// Enable SYSCALL instruction.
efer := rdmsr(_MSR_IA32_EFER)
wrmsr(_MSR_IA32_EFER, efer|_EFER_SCE)
trap.Register(0x80, syscallIntr)
}
+36 -2
View File
@@ -1,6 +1,40 @@
#include "textflag.h"
#define tls_my 0
#define tls_ax 8
#define m_kstack 40
#define ucode_idx 3
#define udata_idx 4
#define rpl_user 3
TEXT ·syscallEntry1(SB), NOSPLIT, $0
CALL ·dotrap(SB)
TEXT ·syscallEntry(SB), NOSPLIT, $0
// save AX
MOVQ AX, tls_ax(GS)
// AX == pointer of current thread
MOVQ tls_my(GS), AX
// AX == kernel stack
MOVQ m_kstack(AX), AX
// push regs like INT 0x80
SUBQ $40, AX
// CX store IP
MOVQ CX, 0(AX)
// save CS
MOVQ $ucode_idx<<3|rpl_user, 8(AX)
// R11 store FLAGS
MOVQ R11, 16(AX)
// save SP
MOVQ SP, 24(AX)
// save SS
MOVQ $udata_idx<<3|rpl_user, 32(AX)
// change SP
MOVQ AX, SP
// restore AX
MOVQ tls_ax(GS), AX
// jmp INT 0x80
JMP ·trap128(SB)
+319
View File
@@ -0,0 +1,319 @@
package kernel64
// copy from https://github.com/lunixbochs/ghostrace/blob/a9d482a46185139ca37908b6ce98e4c5ef048791/ghost/sys/num/linux_x86_64_sys.go#L3
var sysnum = [...]string{
0: "read",
1: "write",
2: "open",
3: "close",
4: "stat",
5: "fstat",
6: "lstat",
7: "poll",
8: "lseek",
9: "mmap",
10: "mprotect",
11: "munmap",
12: "brk",
13: "rt_sigaction",
14: "rt_sigprocmask",
15: "rt_sigreturn",
16: "ioctl",
17: "pread64",
18: "pwrite64",
19: "readv",
20: "writev",
21: "access",
22: "pipe",
23: "select",
24: "sched_yield",
25: "mremap",
26: "msync",
27: "mincore",
28: "madvise",
29: "shmget",
30: "shmat",
31: "shmctl",
32: "dup",
33: "dup2",
34: "pause",
35: "nanosleep",
36: "getitimer",
37: "alarm",
38: "setitimer",
39: "getpid",
40: "sendfile",
41: "socket",
42: "connect",
43: "accept",
44: "sendto",
45: "recvfrom",
46: "sendmsg",
47: "recvmsg",
48: "shutdown",
49: "bind",
50: "listen",
51: "getsockname",
52: "getpeername",
53: "socketpair",
54: "setsockopt",
55: "getsockopt",
56: "clone",
57: "fork",
58: "vfork",
59: "execve",
60: "exit",
61: "wait4",
62: "kill",
63: "uname",
64: "semget",
65: "semop",
66: "semctl",
67: "shmdt",
68: "msgget",
69: "msgsnd",
70: "msgrcv",
71: "msgctl",
72: "fcntl",
73: "flock",
74: "fsync",
75: "fdatasync",
76: "truncate",
77: "ftruncate",
78: "getdents",
79: "getcwd",
80: "chdir",
81: "fchdir",
82: "rename",
83: "mkdir",
84: "rmdir",
85: "creat",
86: "link",
87: "unlink",
88: "symlink",
89: "readlink",
90: "chmod",
91: "fchmod",
92: "chown",
93: "fchown",
94: "lchown",
95: "umask",
96: "gettimeofday",
97: "getrlimit",
98: "getrusage",
99: "sysinfo",
100: "times",
101: "ptrace",
102: "getuid",
103: "syslog",
104: "getgid",
105: "setuid",
106: "setgid",
107: "geteuid",
108: "getegid",
109: "setpgid",
110: "getppid",
111: "getpgrp",
112: "setsid",
113: "setreuid",
114: "setregid",
115: "getgroups",
116: "setgroups",
117: "setresuid",
118: "getresuid",
119: "setresgid",
120: "getresgid",
121: "getpgid",
122: "setfsuid",
123: "setfsgid",
124: "getsid",
125: "capget",
126: "capset",
127: "rt_sigpending",
128: "rt_sigtimedwait",
129: "rt_sigqueueinfo",
130: "rt_sigsuspend",
131: "sigaltstack",
132: "utime",
133: "mknod",
134: "uselib",
135: "personality",
136: "ustat",
137: "statfs",
138: "fstatfs",
139: "sysfs",
140: "getpriority",
141: "setpriority",
142: "sched_setparam",
143: "sched_getparam",
144: "sched_setscheduler",
145: "sched_getscheduler",
146: "sched_get_priority_max",
147: "sched_get_priority_min",
148: "sched_rr_get_interval",
149: "mlock",
150: "munlock",
151: "mlockall",
152: "munlockall",
153: "vhangup",
154: "modify_ldt",
155: "pivot_root",
156: "_sysctl",
157: "prctl",
158: "arch_prctl",
159: "adjtimex",
160: "setrlimit",
161: "chroot",
162: "sync",
163: "acct",
164: "settimeofday",
165: "mount",
166: "umount2",
167: "swapon",
168: "swapoff",
169: "reboot",
170: "sethostname",
171: "setdomainname",
172: "iopl",
173: "ioperm",
174: "create_module",
175: "init_module",
176: "delete_module",
177: "get_kernel_syms",
178: "query_module",
179: "quotactl",
180: "nfsservctl",
181: "getpmsg",
182: "putpmsg",
183: "afs_syscall",
184: "tuxcall",
185: "security",
186: "gettid",
187: "readahead",
188: "setxattr",
189: "lsetxattr",
190: "fsetxattr",
191: "getxattr",
192: "lgetxattr",
193: "fgetxattr",
194: "listxattr",
195: "llistxattr",
196: "flistxattr",
197: "removexattr",
198: "lremovexattr",
199: "fremovexattr",
200: "tkill",
201: "time",
202: "futex",
203: "sched_setaffinity",
204: "sched_getaffinity",
205: "set_thread_area",
206: "io_setup",
207: "io_destroy",
208: "io_getevents",
209: "io_submit",
210: "io_cancel",
211: "get_thread_area",
212: "lookup_dcookie",
213: "epoll_create",
214: "epoll_ctl_old",
215: "epoll_wait_old",
216: "remap_file_pages",
217: "getdents64",
218: "set_tid_address",
219: "restart_syscall",
220: "semtimedop",
221: "fadvise64",
222: "timer_create",
223: "timer_settime",
224: "timer_gettime",
225: "timer_getoverrun",
226: "timer_delete",
227: "clock_settime",
228: "clock_gettime",
229: "clock_getres",
230: "clock_nanosleep",
231: "exit_group",
232: "epoll_wait",
233: "epoll_ctl",
234: "tgkill",
235: "utimes",
236: "vserver",
237: "mbind",
238: "set_mempolicy",
239: "get_mempolicy",
240: "mq_open",
241: "mq_unlink",
242: "mq_timedsend",
243: "mq_timedreceive",
244: "mq_notify",
245: "mq_getsetattr",
246: "kexec_load",
247: "waitid",
248: "add_key",
249: "request_key",
250: "keyctl",
251: "ioprio_set",
252: "ioprio_get",
253: "inotify_init",
254: "inotify_add_watch",
255: "inotify_rm_watch",
256: "migrate_pages",
257: "openat",
258: "mkdirat",
259: "mknodat",
260: "fchownat",
261: "futimesat",
262: "newfstatat",
263: "unlinkat",
264: "renameat",
265: "linkat",
266: "symlinkat",
267: "readlinkat",
268: "fchmodat",
269: "faccessat",
270: "pselect6",
271: "ppoll",
272: "unshare",
273: "set_robust_list",
274: "get_robust_list",
275: "splice",
276: "tee",
277: "sync_file_range",
278: "vmsplice",
279: "move_pages",
280: "utimensat",
281: "epoll_pwait",
282: "signalfd",
283: "timerfd_create",
284: "eventfd",
285: "fallocate",
286: "timerfd_settime",
287: "timerfd_gettime",
288: "accept4",
289: "signalfd4",
290: "eventfd2",
291: "epoll_create1",
292: "dup3",
293: "pipe2",
294: "inotify_init1",
295: "preadv",
296: "pwritev",
297: "rt_tgsigqueueinfo",
298: "perf_event_open",
299: "recvmmsg",
300: "fanotify_init",
301: "fanotify_mark",
302: "prlimit64",
303: "name_to_handle_at",
304: "open_by_handle_at",
305: "clock_adjtime",
306: "syncfs",
307: "sendmmsg",
308: "setns",
309: "getcpu",
310: "process_vm_readv",
311: "process_vm_writev",
312: "kcmp",
313: "finit_module",
}
+341
View File
@@ -0,0 +1,341 @@
package kernel64
import (
"unsafe"
"github.com/icexin/eggos/kernel64/mm"
"github.com/icexin/eggos/sys"
)
const (
_NTHREDS = 20
_FLAGS_IF = 0x200
_FLAGS_IOPL_USER = 0x3000
_RPL_USER = 3
_THREAD_STACK_SIZE = 32 << 10
)
const (
UNUSED = iota
INITING
SLEEPING
RUNNABLE
RUNNING
EXIT
)
const (
_TSS_ESP0 = 1
_TSS_SS0 = 2
)
var (
threads [_NTHREDS]Thread
scheduler *context
taskstate [27]uint32
idleThread threadptr
)
type context struct {
r15 uintptr
r14 uintptr
r13 uintptr
r12 uintptr
r11 uintptr
bx uintptr
bp uintptr
ip uintptr
}
// position of threadTLS and fpstate must be synced with trap.s and syscall.s
type Thread struct {
// store thread tls, the pointer to Thread
threadTLS [4]uintptr
// the state of fpu
fpstate uintptr
kstack uintptr
stack uintptr
tf *trapFrame
context *context
id int
state int
counter int64
// sysmon 会调用usleep,进而调用sleepon,如果sleepKey是个指针会触发gcWriteBarrier
// 而sysmon没有P,会导致空指针
sleepKey uintptr
// store goroutine tls
fsBase uintptr
// 用于保存需要转发的系统调用栈帧
systf trapFrame
}
//go:nosplit
func allocThread() *Thread {
var t *Thread
for i := 0; i < _NTHREDS; i++ {
tt := &threads[i]
if tt.state == UNUSED {
t = tt
t.id = i
break
}
}
if t == nil {
throw("no thread slot available")
}
// t.sigstack.ss_flags = _SS_DISABLE
// t.sigstack.ss_sp = mm.Alloc()
// t.sigstack.ss_size = mm.PGSIZE
t.state = INITING
t.kstack = mm.Mmap(0, _THREAD_STACK_SIZE) + _THREAD_STACK_SIZE
t.fpstate = mm.Alloc()
t.threadTLS[0] = uintptr(unsafe.Pointer(t))
return t
}
type threadptr uintptr
//go:nosplit
func (t threadptr) ptr() *Thread {
return (*Thread)(unsafe.Pointer(t))
}
//go:nosplit
func setFS(addr uintptr) {
wrmsr(_MSR_FS_BASE, addr)
}
//go:nosplit
func setGS(addr uintptr) {
wrmsr(_MSR_GS_BASE, addr)
}
//go:nosplit
func Mythread() *Thread
//go:nosplit
func setMythread(t *Thread) {
switchThreadContext(t)
}
//go:nosplit
func switchThreadContext(t *Thread) {
// set go tls base address
setFS(t.fsBase)
// set current thread base address
setGS(uintptr(unsafe.Pointer(&t.threadTLS)))
// use current thread esp0 in tss
setTssSP0(t.kstack)
}
//go:nosplit
func thread0Init() {
t := allocThread()
t.stack = mm.Mmap(0, _THREAD_STACK_SIZE)
t.stack += _THREAD_STACK_SIZE
sp := t.kstack
// for trap frame
sp -= unsafe.Sizeof(trapFrame{})
tf := (*trapFrame)(unsafe.Pointer(sp))
// Because trapret restore fpstate
// we need a valid fpstate here
sys.Fxsave(t.fpstate)
// tf.SS = _KDATA_IDX << 3
tf.SS = _UDATA_IDX<<3 | _RPL_USER
tf.SP = t.stack
// enable interrupt and io port
// TODO: enable interrupt
// tf.FLAGS = _FLAGS_IF | _FLAGS_IOPL_USER
tf.CS = _UCODE_IDX<<3 | _RPL_USER
// tf.CS = _KCODE_IDX << 3
tf.IP = sys.FuncPC(thread0)
t.tf = tf
// for context
sp -= unsafe.Sizeof(*t.context)
ctx := (*context)(unsafe.Pointer(sp))
ctx.ip = sys.FuncPC(trapret)
t.context = ctx
t.state = RUNNABLE
}
//go:nosplit
func sysClone(pc, stack uintptr) uintptr
//go:nosplit
func sysYield()
//go:nosplit
func sysHlt()
// thread0 is the first thread
//go:nosplit
func thread0() {
// jump to go rt0
go_entry()
panic("main return")
}
// run when after main init
func idleInit() {
// thread0 clone idle thread
stack := mm.SysMmap(0, _THREAD_STACK_SIZE) + _THREAD_STACK_SIZE
tid := sysClone(sys.FuncPC(idle), stack)
idleThread = (threadptr)(unsafe.Pointer(&threads[tid]))
// make idle thread running at ring0, so that it can call HLT instruction.
tf := idleThread.ptr().tf
tf.CS = _KCODE_IDX << 3
}
//go:nosplit
func idle() {
for {
sys.Hlt()
sysYield()
}
}
//go:nosplit
func clone(pc, usp uintptr) int {
my := Mythread()
chld := allocThread()
sp := chld.kstack
// for trap frame
sp -= unsafe.Sizeof(trapFrame{})
tf := (*trapFrame)(unsafe.Pointer(sp))
*tf = *my.tf
// copy fpstate
fpsrc := (*[512]byte)(unsafe.Pointer(my.fpstate))
fpdst := (*[512]byte)(unsafe.Pointer(chld.fpstate))
*fpdst = *fpsrc
tf.SP = usp
tf.IP = pc
tf.AX = 0
// for context
sp -= unsafe.Sizeof(context{})
ctx := (*context)(unsafe.Pointer(sp))
ctx.ip = sys.FuncPC(trapret)
chld.context = ctx
// *(*uintptr)(unsafe.Pointer(&chld.context)) = sp
chld.tf = tf
chld.stack = usp
chld.state = RUNNABLE
return chld.id
}
//go:nosplit
func exit() {
t := Mythread()
t.state = EXIT
Yield()
// TODO: handle thread exit in scheduler
}
//go:nosplit
func threadInit() {
thread0Init()
}
//go:nosplit
func swtch(old **context, _new *context)
//go:nosplit
func schedule() {
var t *Thread
var idx int
for {
t = pickup(&idx)
switchto(t)
}
}
// pickup selects the next runnable thread
//go:nosplit
func pickup(pidx *int) *Thread {
curr := *pidx
// if traptask != 0 && traptask.ptr().state == RUNNABLE {
// return traptask.ptr()
// }
// if syscalltask != 0 && syscalltask.ptr().state == RUNNABLE {
// return syscalltask.ptr()
// }
var t *Thread
for i := 0; i < _NTHREDS; i++ {
idx := (curr + i + 1) % _NTHREDS
*pidx = idx
tt := &threads[idx]
// debug.PrintHex(uintptr(tt.state))
// debug.PrintStr("\n")
// debug.PrintHex(uintptr(unsafe.Pointer(tt)))
// debug.PrintStr("\n")
// debug.PrintHex(uintptr(idleThread))
// debug.PrintStr("\n")
if tt.state == RUNNABLE && tt != idleThread.ptr() {
t = tt
break
}
}
if t == nil {
throw("no runnable thread")
t = idleThread.ptr()
}
return t
}
// switchto switch thread context from scheduler to t
//go:nosplit
func switchto(t *Thread) {
// begin := nanosecond()
// assert interrupt is enableds
// TODO: enable check
// if t.tf != nil && t.tf.FLAGS&0x200 == 0 {
// throw("bad eflags")
// }
setMythread(t)
t.state = RUNNING
swtch(&scheduler, t.context)
// used := nanosecond() - begin
// t.counter += used
}
func ThreadStat(stat *[_NTHREDS]int64) {
for i := 0; i < _NTHREDS; i++ {
stat[i] = threads[i].counter
}
}
//go:nosplit
func Sched() {
my := Mythread()
swtch(&my.context, scheduler)
}
//go:nosplit
func Yield() {
my := Mythread()
my.state = RUNNABLE
swtch(&my.context, scheduler)
}
+58
View File
@@ -0,0 +1,58 @@
#include "textflag.h"
#define SYS_clone 56
#define SYS_sched_yield 158
#define tls_my 0
// func swtch(old **context, _new *context)
TEXT ·swtch(SB), NOSPLIT, $0-16
MOVQ old+0(FP), AX
MOVQ _new+8(FP), DX
// Save old callee-saved registers
PUSHQ BP
PUSHQ BX
PUSHQ R11
PUSHQ R12
PUSHQ R13
PUSHQ R14
PUSHQ R15
// Switch stacks
MOVQ SP, (AX)
MOVQ DX, SP
POPQ R15
POPQ R14
POPQ R13
POPQ R12
POPQ R11
POPQ BX
POPQ BP
RET
TEXT ·Mythread(SB), NOSPLIT, $0-8
MOVQ tls_my(GS), AX
MOVQ AX, ret+0(FP)
RET
TEXT ·sysClone(SB), NOSPLIT, $0-24
MOVQ $SYS_clone, AX
MOVL pc+0(FP), DX
MOVL stack+4(FP), CX
INT $0x80
// In parent, return.
CMPL AX, $0
JEQ 3(PC)
MOVL AX, ret+8(FP)
RET
NOP SP // tell vet SP changed - stop checking offsets
JMP DX
TEXT ·sysYield(SB), NOSPLIT, $0
MOVL $SYS_sched_yield, AX
INT $0x80
RET
+30 -2
View File
@@ -4,6 +4,9 @@ import (
"unsafe"
"github.com/icexin/eggos/debug"
"github.com/icexin/eggos/kernel/isyscall"
"github.com/icexin/eggos/kernel/trap"
"github.com/icexin/eggos/pic"
"github.com/icexin/eggos/sys"
"github.com/icexin/eggos/uart"
)
@@ -16,10 +19,19 @@ type trapFrame struct {
Trapno, Err uintptr
// pushed by hardward
// pushed by hardware
IP, CS, FLAGS, SP, SS uintptr
}
func (t *trapFrame) SyscallRequest() isyscall.Request {
return isyscall.Request{
NO: t.AX,
Args: [6]uintptr{
t.DI, t.SI, t.DX, t.R10, t.R8, t.R9,
},
}
}
//go:nosplit
func trapret()
@@ -54,7 +66,23 @@ func changeReturnPC(tf *trapFrame, pc uintptr) {
//go:nosplit
func dotrap(tf *trapFrame) {
Mythread().tf = tf
debug.PrintHex(tf.Trapno)
uart.WriteString("trap\n")
preparePanic(tf)
handler := trap.Handler(int(tf.Trapno))
if handler == nil {
preparePanic(tf)
return
}
// timer and syscall interrupts are processed synchronously
if tf.Trapno > 32 && tf.Trapno != 0x80 {
// pci using level trigger irq, cause dead lock on trap handler
// FIXME: hard code network irq line
if tf.Trapno == 43 {
pic.DisableIRQ(43 - pic.IRQ_BASE)
}
// wakeIRQ(tf.Trapno)
return
}
handler()
}