chore(vkernel): 重置基线 — 纳入 TPV codegen 修复配合的内核侧调整与既有工作区内容
- devfs.vp: string.split 传 PATH_BUFFER_SIZE(配合 split 新增容量参数) - fat32_types.vp: lfn_extract 越界钳制(base+i > MAX_LFN 返回 -1) - sheet.vp: gfx.Renderer 实参修正为 (fb, zb, w, h)(原单参导致 w/h=0 渲染空操作) - 同批包含 VKernel 其余既有移植改动与 vpsdk/Apps/Libs 工作区内容
This commit is contained in:
1 parent
cd1cc915c5
commit
a518f75b24
61 files changed
+9272
-9201
No files matched your search
@@ -57,6 +57,7 @@ ViperTemplateProject/
|
||||
StandardTemplateProject/
|
||||
|
||||
# ViperOS 编译产物(每个子项目内的 output/ 和 temp/)
|
||||
**/.tpv_build/
|
||||
**/output/
|
||||
**/temp/
|
||||
**/*.deps.json
|
||||
|
||||
+21
-21
@@ -25,9 +25,9 @@ YIELD_ROWS: t.CDefine = 4
|
||||
V3_POOL_SIZE: t.CDefine = 8192
|
||||
V3_POOL_BYTES: t.CDefine = V3_POOL_SIZE * 24 + 512
|
||||
|
||||
_v3_mem: t.CArray[t.CUInt8T, V3_POOL_BYTES]
|
||||
_v3_mem: t.CArray[uint8, V3_POOL_BYTES]
|
||||
_v3_pool: memhub.MemPool | t.CPtr
|
||||
_fb_mem: t.CArray[t.CUInt32T, GW * GH]
|
||||
_fb_mem: t.CArray[uint32, GW * GH]
|
||||
|
||||
class V3:
|
||||
x: t.CFloat64T
|
||||
@@ -35,7 +35,7 @@ class V3:
|
||||
z: t.CFloat64T
|
||||
|
||||
def __new__() -> 'V3' | t.CPtr:
|
||||
return t.CVoid(t.CUInt64T(_v3_pool.alloc(24)), t.CPtr)
|
||||
return t.CVoid(uint64(_v3_pool.alloc(24)), t.CPtr)
|
||||
|
||||
def __init__(self, x: t.CFloat64T, y: t.CFloat64T, z: t.CFloat64T):
|
||||
self.x = x
|
||||
@@ -124,7 +124,7 @@ def hash3(x: t.CFloat64T, y: t.CFloat64T, z: t.CFloat64T) -> t.CFloat64T:
|
||||
|
||||
def stars(d: V3 | t.CPtr) -> V3 | t.CPtr:
|
||||
col: V3 | t.CPtr = V3(0.0, 0.0, 0.0)
|
||||
i: t.CInt = 0
|
||||
i: int = 0
|
||||
while i < 3:
|
||||
s: t.CFloat64T = 80.0 + t.CFloat64T(i) * 90.0
|
||||
px: t.CFloat64T = d.x * s
|
||||
@@ -185,7 +185,7 @@ def trace(dir_v: V3 | t.CPtr, gT: t.CFloat64T) -> V3 | t.CPtr:
|
||||
T: t.CFloat64T = 1.0
|
||||
col: V3 | t.CPtr = V3(0.0, 0.0, 0.0)
|
||||
|
||||
i: t.CInt = 0
|
||||
i: int = 0
|
||||
while i < MAX_STEPS:
|
||||
r2: t.CFloat64T = pos.dot(pos)
|
||||
r: t.CFloat64T = vm.sqrt(r2)
|
||||
@@ -238,7 +238,7 @@ def trace(dir_v: V3 | t.CPtr, gT: t.CFloat64T) -> V3 | t.CPtr:
|
||||
i += 1
|
||||
return col
|
||||
|
||||
def shade_pixel(px: t.CInt, py: t.CInt, gT: t.CFloat64T) -> t.CUInt32T:
|
||||
def shade_pixel(px: int, py: int, gT: t.CFloat64T) -> uint32:
|
||||
aspect: t.CFloat64T = GW_F / GH_F
|
||||
sx: t.CFloat64T = (2.0 * (t.CFloat64T(px) + 0.5) / GW_F - 1.0) * aspect * FOVF
|
||||
sy: t.CFloat64T = (1.0 - 2.0 * (t.CFloat64T(py) + 0.5) / GH_F) * FOVF
|
||||
@@ -252,13 +252,13 @@ def shade_pixel(px: t.CInt, py: t.CInt, gT: t.CFloat64T) -> t.CUInt32T:
|
||||
c.x = vm.pow(c.x, 1.0 / 2.2)
|
||||
c.y = vm.pow(c.y, 1.0 / 2.2)
|
||||
c.z = vm.pow(c.z, 1.0 / 2.2)
|
||||
R: t.CInt = t.CInt(clmp(c.x, 0.0, 1.0) * 255.0)
|
||||
G: t.CInt = t.CInt(clmp(c.y, 0.0, 1.0) * 255.0)
|
||||
B: t.CInt = t.CInt(clmp(c.z, 0.0, 1.0) * 255.0)
|
||||
return t.CUInt32T((R << 16) | (G << 8) | B)
|
||||
R: int = int(clmp(c.x, 0.0, 1.0) * 255.0)
|
||||
G: int = int(clmp(c.y, 0.0, 1.0) * 255.0)
|
||||
B: int = int(clmp(c.z, 0.0, 1.0) * 255.0)
|
||||
return uint32((R << 16) | (G << 8) | B)
|
||||
|
||||
@c.Attribute(t.attr.section(".text.startup"), t.attr.aligned(16))
|
||||
def _start() -> t.CInt | t.CExport:
|
||||
def _start() -> int | t.CExport:
|
||||
global _v3_pool
|
||||
_v3_pool = memhub.MemPool(c.Addr(_v3_mem), V3_POOL_BYTES)
|
||||
setup_camera()
|
||||
@@ -266,7 +266,7 @@ def _start() -> t.CInt | t.CExport:
|
||||
root: vpui.Tk = vpui.Tk()
|
||||
root.title("Gargantua")
|
||||
root.set_style(window.STYLE_WIN7)
|
||||
root.bg_color = t.CUInt32T(0x000000)
|
||||
root.bg_color = uint32(0x000000)
|
||||
master: vpui.Tk | t.CPtr = c.Addr(root)
|
||||
|
||||
canvas: vpui.FBCanvas = vpui.FBCanvas(master, GW, GH)
|
||||
@@ -279,33 +279,33 @@ def _start() -> t.CInt | t.CExport:
|
||||
root.geometry(100, 30, GW, GH + 32)
|
||||
|
||||
gT: t.CFloat64T = 0.0
|
||||
rendered: t.CInt = 0
|
||||
rendered: int = 0
|
||||
|
||||
evt: window.InputEvent
|
||||
while window.is_active(root.win_id):
|
||||
result: t.CInt = window.poll_event(c.Addr(evt))
|
||||
result: int = window.poll_event(c.Addr(evt))
|
||||
if result != 0:
|
||||
if evt.type == window.EVENT_TYPE_PING:
|
||||
window.flush(root.win_id)
|
||||
elif evt.type == window.EVENT_TYPE_RESIZE:
|
||||
sz: t.CInt = window.get_win_size(root.win_id)
|
||||
new_w: t.CInt = sz >> 16
|
||||
new_h: t.CInt = sz & 0xFFFF
|
||||
sz: int = window.get_win_size(root.win_id)
|
||||
new_w: int = sz >> 16
|
||||
new_h: int = sz & 0xFFFF
|
||||
canvas.set_fb(fb, new_w, new_h)
|
||||
|
||||
if rendered == 0:
|
||||
y: t.CInt = 0
|
||||
y: int = 0
|
||||
while y < GH:
|
||||
x: t.CInt = 0
|
||||
x: int = 0
|
||||
while x < GW:
|
||||
pixel: t.CUInt32T = shade_pixel(x, y, gT)
|
||||
pixel: uint32 = shade_pixel(x, y, gT)
|
||||
fb[y * GW + x] = pixel
|
||||
x += 1
|
||||
y += 1
|
||||
if y % YIELD_ROWS == 0:
|
||||
root.redraw()
|
||||
process.yield_cpu()
|
||||
result2: t.CInt = window.poll_event(c.Addr(evt))
|
||||
result2: int = window.poll_event(c.Addr(evt))
|
||||
if result2 != 0:
|
||||
if evt.type == window.EVENT_TYPE_PING:
|
||||
window.flush(root.win_id)
|
||||
|
||||
+53
-53
@@ -1,53 +1,53 @@
|
||||
import vpsdk.vpui as vpui
|
||||
import vpsdk.window as window
|
||||
import vpsdk.process as process
|
||||
import vpsdk.dynlib as dynlib
|
||||
import vpsdk.stdlib as stdlib
|
||||
import vpsdk.stdio as stdio
|
||||
from stdint import *
|
||||
import t, c
|
||||
|
||||
@c.Attribute(t.attr.section(".text.startup"), t.attr.aligned(16))
|
||||
def _start() -> t.CInt | t.CExport:
|
||||
base: t.CUInt64T = dynlib.load_so("/LIBS/SLOG.SO")
|
||||
if base != 0:
|
||||
dynlib.so_call1("log_info", "Hello from dynamic library!")
|
||||
|
||||
root: vpui.Tk = vpui.Tk()
|
||||
root.title("Input Demo")
|
||||
root.set_style(window.STYLE_WIN7)
|
||||
root.geometry(290, 30, 300, 200)
|
||||
root.bg_color = t.CUInt32T(0x1E1E32)
|
||||
master: vpui.Tk | t.CPtr = c.Addr(root)
|
||||
|
||||
entry: vpui.Entry = vpui.Entry(master, 260, 28)
|
||||
root.pack(0, vpui.PACK_TOP, vpui.FILL_X, 0, 20, 10)
|
||||
result: vpui.Label = vpui.Label(master, "", t.CUInt32T(0x00FF00))
|
||||
root.pack(1, vpui.PACK_BOTTOM, 0, 0, 0, 10)
|
||||
|
||||
def _on_submit() -> t.CInt:
|
||||
text: t.CConst | str = entry.get()
|
||||
result.config(text)
|
||||
entry.delete(0, -1)
|
||||
return 0
|
||||
|
||||
lbl: vpui.Label = vpui.Label(master, "Name:", 0xFFFFFFFF)
|
||||
root.pack(2, vpui.PACK_TOP, 0, 0, 20, 0)
|
||||
btn: vpui.Button = vpui.Button(master, 100, 36, "Submit", c.Addr(_on_submit))
|
||||
root.pack(3, vpui.PACK_TOP, 0, 0, 0, 10)
|
||||
|
||||
root2: vpui.Tk = vpui.Tk()
|
||||
root2.title("Test No-Resp")
|
||||
root2.set_style(window.STYLE_WIN10)
|
||||
root2.geometry(200, 50, 300, 150)
|
||||
root2.bg_color = t.CUInt32T(0x1E1E32)
|
||||
master2: vpui.Tk | t.CPtr = c.Addr(root2)
|
||||
|
||||
lbl2: vpui.Label = vpui.Label(master2, "This window will NOT respond!", 0xFFFFFFFF)
|
||||
lbl2.place(10, 10)
|
||||
|
||||
root2.update()
|
||||
|
||||
root.mainloop()
|
||||
process.exit(0)
|
||||
return 0
|
||||
import vpsdk.vpui as vpui
|
||||
import vpsdk.window as window
|
||||
import vpsdk.process as process
|
||||
import vpsdk.dynlib as dynlib
|
||||
import vpsdk.stdlib as stdlib
|
||||
import vpsdk.stdio as stdio
|
||||
from stdint import *
|
||||
import t, c
|
||||
|
||||
@c.Attribute(t.attr.section(".text.startup"), t.attr.aligned(16))
|
||||
def _start() -> int | t.CExport:
|
||||
base: uint64 = dynlib.load_so("/LIBS/SLOG.SO")
|
||||
if base != 0:
|
||||
dynlib.so_call1("log_info", "Hello from dynamic library!")
|
||||
|
||||
root: vpui.Tk = vpui.Tk()
|
||||
root.title("Input Demo")
|
||||
root.set_style(window.STYLE_WIN7)
|
||||
root.geometry(290, 30, 300, 200)
|
||||
root.bg_color = uint32(0x1E1E32)
|
||||
master: vpui.Tk | t.CPtr = c.Addr(root)
|
||||
|
||||
entry: vpui.Entry = vpui.Entry(master, 260, 28)
|
||||
root.pack(0, vpui.PACK_TOP, vpui.FILL_X, 0, 20, 10)
|
||||
result: vpui.Label = vpui.Label(master, "", uint32(0x00FF00))
|
||||
root.pack(1, vpui.PACK_BOTTOM, 0, 0, 0, 10)
|
||||
|
||||
def _on_submit() -> int:
|
||||
text: t.CConst | str = entry.get()
|
||||
result.config(text)
|
||||
entry.delete(0, -1)
|
||||
return 0
|
||||
|
||||
lbl: vpui.Label = vpui.Label(master, "Name:", 0xFFFFFFFF)
|
||||
root.pack(2, vpui.PACK_TOP, 0, 0, 20, 0)
|
||||
btn: vpui.Button = vpui.Button(master, 100, 36, "Submit", c.Addr(_on_submit))
|
||||
root.pack(3, vpui.PACK_TOP, 0, 0, 0, 10)
|
||||
|
||||
root2: vpui.Tk = vpui.Tk()
|
||||
root2.title("Test No-Resp")
|
||||
root2.set_style(window.STYLE_WIN10)
|
||||
root2.geometry(200, 50, 300, 150)
|
||||
root2.bg_color = uint32(0x1E1E32)
|
||||
master2: vpui.Tk | t.CPtr = c.Addr(root2)
|
||||
|
||||
lbl2: vpui.Label = vpui.Label(master2, "This window will NOT respond!", 0xFFFFFFFF)
|
||||
lbl2.place(10, 10)
|
||||
|
||||
root2.update()
|
||||
|
||||
root.mainloop()
|
||||
process.exit(0)
|
||||
return 0
|
||||
+305
-305
@@ -1,305 +1,305 @@
|
||||
from stdint import *
|
||||
import vipermath
|
||||
import string
|
||||
import t, c
|
||||
|
||||
|
||||
PI: t.CDefine = float(3.14159265358979323846)
|
||||
|
||||
SPHERE_SLICES: t.CDefine = (24 * 1)
|
||||
SPHERE_STACKS: t.CDefine = (16 * 1)
|
||||
SIN_WAVE_GRID: t.CDefine = (40 * 1)
|
||||
|
||||
def COLOR_RGB(r: int, g: int, b: int) -> t.CInline | t.CInt:
|
||||
return (255 << 24) | (r << 16) | (g << 8) | (b)
|
||||
|
||||
@t.Object
|
||||
class Vec3:
|
||||
x: float
|
||||
y: float
|
||||
z: float
|
||||
def __init__(self, x: float, y: float, z: float):
|
||||
self.x = x
|
||||
self.y = y
|
||||
self.z = z
|
||||
def Sub(self, b: 'Vec3') -> 'Vec3':
|
||||
return Vec3(self.x - b.x, self.y - b.y, self.z - b.z)
|
||||
def Cross(self, b: 'Vec3') -> 'Vec3':
|
||||
return Vec3(self.y * b.z - self.z * b.y, self.z * b.x - self.x * b.z, self.x * b.y - self.y * b.x)
|
||||
def Dot(self, b: 'Vec3') -> float:
|
||||
return self.x * b.x + self.y * b.y + self.z * b.z
|
||||
def Norm(self) -> 'Vec3':
|
||||
l = vipermath.sqrtf(self.Dot(self))
|
||||
return Vec3(self.x / l, self.y / l, self.z / l)
|
||||
|
||||
class Mat4:
|
||||
m: t.CArray[t.CArray[float, 4], 4]
|
||||
|
||||
def Mat4_Identity() -> Mat4:
|
||||
m: Mat4 = Mat4()
|
||||
string.memset(c.Addr(m), 0, Mat4.__sizeof__())
|
||||
m.m[0][0] = 1; m.m[1][1] = 1; m.m[2][2] = 1; m.m[3][3] = 1
|
||||
return m
|
||||
|
||||
def Mat4_Mul(a: Mat4, b: Mat4) -> Mat4:
|
||||
res: Mat4 = Mat4()
|
||||
string.memset(c.Addr(res), 0, Mat4.__sizeof__())
|
||||
for i in range(4):
|
||||
for j in range(4):
|
||||
for k in range(4):
|
||||
res.m[i][j] += a.m[i][k] * b.m[k][j]
|
||||
return res
|
||||
|
||||
def Mat4_MulVec(m: Mat4, v: Vec3) -> Vec3:
|
||||
x: float = m.m[0][0] * v.x + m.m[0][1] * v.y + m.m[0][2] * v.z + m.m[0][3]
|
||||
y: float = m.m[1][0] * v.x + m.m[1][1] * v.y + m.m[1][2] * v.z + m.m[1][3]
|
||||
z: float = m.m[2][0] * v.x + m.m[2][1] * v.y + m.m[2][2] * v.z + m.m[2][3]
|
||||
w: float = m.m[3][0] * v.x + m.m[3][1] * v.y + m.m[3][2] * v.z + m.m[3][3]
|
||||
if w != 0:
|
||||
x /= w; y /= w; z /= w
|
||||
return Vec3(x, y, z)
|
||||
|
||||
def Mat4_Perspective(fov: float, aspect: float, zn: float, zf: float) -> Mat4:
|
||||
m: Mat4 = Mat4()
|
||||
string.memset(c.Addr(m), 0, Mat4.__sizeof__())
|
||||
f: float = float(1.0) / vipermath.tanf(fov / float(2.0))
|
||||
m.m[0][0] = f / aspect; m.m[1][1] = f
|
||||
m.m[2][2] = zf / (zn - zf); m.m[2][3] = (zf * zn) / (zn - zf); m.m[3][2] = -1
|
||||
return m
|
||||
|
||||
def Mat4_LookAt(eye: Vec3, target: Vec3, up: Vec3) -> Mat4:
|
||||
zaxis: Vec3 = eye.Sub(target).Norm()
|
||||
xaxis: Vec3 = up.Cross(zaxis).Norm()
|
||||
yaxis: Vec3 = zaxis.Cross(xaxis)
|
||||
m: Mat4 = Mat4_Identity()
|
||||
m.m[0][0]=xaxis.x; m.m[0][1]=xaxis.y; m.m[0][2]=xaxis.z; m.m[0][3]= -xaxis.Dot(eye)
|
||||
m.m[1][0]=yaxis.x; m.m[1][1]=yaxis.y; m.m[1][2]=yaxis.z; m.m[1][3]= -yaxis.Dot(eye)
|
||||
m.m[2][0]=zaxis.x; m.m[2][1]=zaxis.y; m.m[2][2]=zaxis.z; m.m[2][3]= -zaxis.Dot(eye)
|
||||
m.m[3][3] = 1
|
||||
return m
|
||||
|
||||
def Mat4_Translate(x: float, y: float, z: float) -> Mat4:
|
||||
m: Mat4 = Mat4_Identity()
|
||||
m.m[0][3] = x; m.m[1][3] = y; m.m[2][3] = z
|
||||
return m
|
||||
|
||||
def Mat4_RotateY(a: float) -> Mat4:
|
||||
m: Mat4 = Mat4_Identity()
|
||||
m.m[0][0] = vipermath.cosf(a); m.m[0][2] = vipermath.sinf(a)
|
||||
m.m[2][0] = -vipermath.sinf(a); m.m[2][2] = vipermath.cosf(a)
|
||||
return m
|
||||
|
||||
|
||||
@t.Object
|
||||
class Surface:
|
||||
fb: UINT32PTR
|
||||
zb: float | t.CPtr
|
||||
w: int
|
||||
h: int
|
||||
def __init__(self, fb: UINT32PTR, zb: float | t.CPtr, w: int, h: int):
|
||||
self.fb = fb
|
||||
self.zb = zb
|
||||
self.w = w
|
||||
self.h = h
|
||||
|
||||
@t.Object
|
||||
class Renderer:
|
||||
_fb: UINT32PTR
|
||||
_zb: float | t.CPtr
|
||||
_w: int
|
||||
_h: int
|
||||
|
||||
def __init__(self, fb: UINT32PTR, zb: float | t.CPtr, w: int, h: int):
|
||||
self._fb = fb
|
||||
self._zb = zb
|
||||
self._w = w
|
||||
self._h = h
|
||||
|
||||
def Clear(self, color: t.CUInt32T):
|
||||
fb: UINT32PTR = self._fb
|
||||
zb: float | t.CPtr = self._zb
|
||||
size: int = self._w * self._h
|
||||
for i in range(size):
|
||||
fb[i] = color
|
||||
zb[i] = float(1.0)
|
||||
|
||||
def DrawLine2D(self, x0: int, y0: int, x1: int, y1: int, col: t.CUInt32T):
|
||||
fb: UINT32PTR = self._fb
|
||||
w: int = self._w; h: int = self._h
|
||||
dx: int = abs(x1-x0); dy: int = abs(y1-y0)
|
||||
sx: int = 1 if x0 < x1 else -1; sy: int = 1 if y0 < y1 else -1
|
||||
err: int = dx - dy
|
||||
while True:
|
||||
if x0 >= 0 and x0 < w and y0 >= 0 and y0 < h: fb[y0 * w + x0] = col
|
||||
if x0 == x1 and y0 == y1: break
|
||||
e2: int = 2 * err
|
||||
if e2 > -dy: err -= dy; x0 += sx
|
||||
if e2 < dx: err += dx; y0 += sy
|
||||
|
||||
def DrawTriangle(self, v0: Vec3, v1: Vec3, v2: Vec3, col: t.CUInt32T):
|
||||
if v0.z < float(0.0) or v1.z < float(0.0) or v2.z < float(0.0): return
|
||||
if (v0.x > float(10.0) or v0.x < float(-10.0) or v0.y > float(10.0) or v0.y < float(-10.0) or
|
||||
v1.x > float(10.0) or v1.x < float(-10.0) or v1.y > float(10.0) or v1.y < float(-10.0) or
|
||||
v2.x > float(10.0) or v2.x < float(-10.0) or v2.y > float(10.0) or v2.y < float(-10.0)): return
|
||||
|
||||
fb: UINT32PTR = self._fb
|
||||
zb: float | t.CPtr = self._zb
|
||||
w: int = self._w
|
||||
h: int = self._h
|
||||
|
||||
sx0: float = (v0.x + float(1.0)) * float(0.5) * w; sy0: float = (float(1.0) - v0.y) * float(0.5) * h
|
||||
sx1: float = (v1.x + float(1.0)) * float(0.5) * w; sy1: float = (float(1.0) - v1.y) * float(0.5) * h
|
||||
sx2: float = (v2.x + float(1.0)) * float(0.5) * w; sy2: float = (float(1.0) - v2.y) * float(0.5) * h
|
||||
|
||||
minX: int = max(0, int(vipermath.floorf(min(min(sx0, sx1), sx2))))
|
||||
maxX: int = min(w - 1, int(vipermath.ceilf(max(max(sx0, sx1), sx2))))
|
||||
minY: int = max(0, int(vipermath.floorf(min(min(sy0, sy1), sy2))))
|
||||
maxY: int = min(h - 1, int(vipermath.ceilf(max(max(sy0, sy1), sy2))))
|
||||
|
||||
dx12: float = sx1 - sx2; dy12: float = sy1 - sy2
|
||||
dx02: float = sx0 - sx2; dy02: float = sy0 - sy2
|
||||
denom: float = dx12 * dy02 - dy12 * dx02
|
||||
if denom < float(0.001) and denom > float(-0.001): return
|
||||
invDenom: float = float(1.0) / denom
|
||||
|
||||
row_dxP_start: float = float(minX) - sx2
|
||||
for y in range(minY, maxY + 1):
|
||||
dyP: float = float(y) - sy2
|
||||
dxP: float = row_dxP_start
|
||||
row_base: int = y * w
|
||||
for x in range(minX, maxX + 1):
|
||||
w0: float = (dx12 * dyP - dy12 * dxP) * invDenom
|
||||
w1: float = (dxP * dy02 - dyP * dx02) * invDenom
|
||||
w2: float = float(1.0) - w0 - w1
|
||||
if w0 >= 0 and w1 >= 0 and w2 >= 0:
|
||||
z: float = w0 * v0.z + w1 * v1.z + w2 * v2.z
|
||||
idx: int = row_base + x
|
||||
if z < zb[idx]:
|
||||
zb[idx] = z
|
||||
fb[idx] = col
|
||||
dxP += float(1.0)
|
||||
|
||||
def DrawGlowDot(self, x: float, y: float, radius: float, core_col: t.CUInt32T, intensity: float):
|
||||
fb: UINT32PTR = self._fb; w: int = self._w; h: int = self._h
|
||||
r: int = int(radius) + 4
|
||||
ix: int = int(x); iy: int = int(y)
|
||||
for dy in range(-r, r + 1):
|
||||
py: int = iy + dy
|
||||
if py < 0 or py >= h: continue
|
||||
for dx in range(-r, r + 1):
|
||||
px: int = ix + dx
|
||||
if px < 0 or px >= w: continue
|
||||
dist: float = vipermath.sqrtf(float(dx*dx + dy*dy))
|
||||
if dist < radius:
|
||||
self.BlendPixel(px, py, core_col, intensity)
|
||||
elif dist < float(r):
|
||||
fade: float = 1.0 - (dist - radius) / 4.0
|
||||
self.BlendPixel(px, py, core_col, intensity * fade * 0.5)
|
||||
|
||||
def BlendPixel(self, x: int, y: int, col: t.CUInt32T, alpha: float):
|
||||
if alpha <= 0.0: return
|
||||
fb: UINT32PTR = self._fb; w: int = self._w; h: int = self._h
|
||||
if x < 0 or x >= w or y < 0 or y >= h: return
|
||||
|
||||
idx: int = y * w + x
|
||||
bg: t.CUInt32T = fb[idx]
|
||||
bg_b: int = bg & 0xFF; bg_g: int = (bg >> 8) & 0xFF; bg_r: int = (bg >> 16) & 0xFF
|
||||
f_b: int = col & 0xFF; f_g: int = (col >> 8) & 0xFF; f_r: int = (col >> 16) & 0xFF
|
||||
|
||||
a: int = int(alpha * 255.0)
|
||||
inv_a: int = 255 - a
|
||||
nr: int = (f_r * a + bg_r * inv_a) >> 8
|
||||
ng: int = (f_g * a + bg_g * inv_a) >> 8
|
||||
nb: int = (f_b * a + bg_b * inv_a) >> 8
|
||||
|
||||
fb[idx] = COLOR_RGB(255 if (nr > 255) else nr,
|
||||
255 if (ng > 255) else ng,
|
||||
255 if (nb > 255) else nb)
|
||||
|
||||
|
||||
@t.Object
|
||||
class Scene3D:
|
||||
renderer: Renderer
|
||||
|
||||
def __init__(self, fb: UINT32PTR, zb: float | t.CPtr, w: int, h: int):
|
||||
self.renderer = Renderer(fb, zb, w, h)
|
||||
|
||||
def Render(self, time: float):
|
||||
rw: int = self.renderer._w
|
||||
rh: int = self.renderer._h
|
||||
self.renderer.Clear(COLOR_RGB(15, 15, 25))
|
||||
|
||||
yaw: float = float(45.0) * PI / float(180.0); pitch: float = float(45.0) * PI / float(180.0); radius: float = float(10.0)
|
||||
eye: Vec3 = Vec3(radius*vipermath.cosf(pitch)*vipermath.cosf(yaw), radius*vipermath.sinf(pitch), radius*vipermath.cosf(pitch)*vipermath.sinf(yaw))
|
||||
target: Vec3 = Vec3(0, 0, 0); up: Vec3 = Vec3(0, 1, 0)
|
||||
view: Mat4 = Mat4_LookAt(eye, target, up)
|
||||
proj: Mat4 = Mat4_Perspective(PI / float(3.0), float(rw)/float(rh), float(0.1), float(100.0))
|
||||
vp: Mat4 = Mat4_Mul(proj, view)
|
||||
|
||||
cubeX: float = float(-3.5)
|
||||
cubeMVP: Mat4 = Mat4_Mul(vp, Mat4_Translate(cubeX, 0, 0))
|
||||
self._DrawCube(cubeMVP, COLOR_RGB(180, 180, 180))
|
||||
|
||||
colors: t.CArray[t.CUInt32T, 4] = [COLOR_RGB(255,50,50), COLOR_RGB(50,50,255), COLOR_RGB(255,255,50), COLOR_RGB(50,255,255)]
|
||||
for i in range(4):
|
||||
a: float = time * float(1.5) + i * (PI / float(2.0)); r: float = float(3.0)
|
||||
pos: Vec3 = Vec3(vipermath.cosf(a) * r + cubeX, 0, vipermath.sinf(a) * r)
|
||||
sphereMVP: Mat4 = Mat4_Mul(vp, Mat4_Translate(pos.x, pos.y, pos.z))
|
||||
self._DrawSphere(sphereMVP, Vec3(0,0,0), float(0.5), colors[i])
|
||||
|
||||
self._Draw3DSinWave(vp, Vec3(float(3.5), 0, 0), time)
|
||||
|
||||
self.renderer.DrawLine2D(50, rh - 150, rw - 50, rh - 150, COLOR_RGB(80, 80, 80))
|
||||
self.renderer.DrawLine2D(50, rh - 50, 50, rh - 250, COLOR_RGB(80, 80, 80))
|
||||
wave_shift: float = time * float(2.0)
|
||||
prev_x: int = 50; prev_y: int = rh - 150 - int(vipermath.sinf(0 - wave_shift) * float(100.0))
|
||||
for i in range(1, rw - 100):
|
||||
tr: float = float(i) / float(rw-100) * float(4.0) * PI
|
||||
cx: int = 50 + i; cy: int = rh - 150 - int(vipermath.sinf(tr - wave_shift) * float(100.0))
|
||||
self.renderer.DrawLine2D(prev_x, prev_y, cx, cy, COLOR_RGB(0, 255, 100))
|
||||
prev_x = cx; prev_y = cy
|
||||
|
||||
def _DrawCube(self, mvp: Mat4, col: t.CUInt32T):
|
||||
v: t.CArray[Vec3, 8] = [
|
||||
Vec3(-1, -1, -1), Vec3(-1, -1, 1), Vec3(-1, 1, -1), Vec3(-1, 1, 1),
|
||||
Vec3( 1, -1, -1), Vec3( 1, -1, 1), Vec3( 1, 1, -1), Vec3( 1, 1, 1)
|
||||
]
|
||||
for i in range(8): v[i] = Mat4_MulVec(mvp, v[i])
|
||||
faces: t.CArray[t.CArray[int, 3], 12] = [
|
||||
[0, 2, 1], [1, 2, 3], [4, 1, 5], [4, 0, 1], [6, 3, 2], [6, 7, 3],
|
||||
[4, 6, 0], [0, 6, 2], [5, 7, 4], [4, 7, 6], [1, 3, 5], [5, 3, 7]
|
||||
]
|
||||
for i in range(12): self.renderer.DrawTriangle(v[faces[i][0]], v[faces[i][1]], v[faces[i][2]], col)
|
||||
|
||||
def _DrawSphere(self, mvp: Mat4, center: Vec3, radius: float, col: t.CUInt32T):
|
||||
step_pi: float = PI / SPHERE_STACKS; step_2pi: float = float(2.0) * PI / SPHERE_SLICES
|
||||
for i in range(SPHERE_STACKS):
|
||||
for j in range(SPHERE_SLICES):
|
||||
theta1: float = i * step_pi; theta2: float = (i + 1) * step_pi
|
||||
phi1: float = j * step_2pi; phi2: float = (j + 1) * step_2pi
|
||||
v: t.CArray[Vec3, 4]
|
||||
v[0] = Vec3(center.x+radius*vipermath.sinf(theta1)*vipermath.cosf(phi1), center.y+radius*vipermath.cosf(theta1), center.z+radius*vipermath.sinf(theta1)*vipermath.sinf(phi1))
|
||||
v[1] = Vec3(center.x+radius*vipermath.sinf(theta1)*vipermath.cosf(phi2), center.y+radius*vipermath.cosf(theta1), center.z+radius*vipermath.sinf(theta1)*vipermath.sinf(phi2))
|
||||
v[2] = Vec3(center.x+radius*vipermath.sinf(theta2)*vipermath.cosf(phi1), center.y+radius*vipermath.cosf(theta2), center.z+radius*vipermath.sinf(theta2)*vipermath.sinf(phi1))
|
||||
v[3] = Vec3(center.x+radius*vipermath.sinf(theta2)*vipermath.cosf(phi2), center.y+radius*vipermath.cosf(theta2), center.z+radius*vipermath.sinf(theta2)*vipermath.sinf(phi2))
|
||||
for k in range(4): v[k] = Mat4_MulVec(mvp, v[k])
|
||||
self.renderer.DrawTriangle(v[0], v[1], v[2], col)
|
||||
self.renderer.DrawTriangle(v[1], v[3], v[2], col)
|
||||
|
||||
def _Draw3DSinWave(self, vp: Mat4, pos: Vec3, time: float):
|
||||
_range: float = float(2.0) * PI; step: float = _range / SIN_WAVE_GRID; scale: float = float(0.5)
|
||||
mvp: Mat4 = Mat4_Mul(vp, Mat4_Mul(Mat4_Translate(pos.x, pos.y, pos.z), Mat4_RotateY(time * float(1.0))))
|
||||
for i in range(SIN_WAVE_GRID):
|
||||
for j in range(SIN_WAVE_GRID):
|
||||
x0: float = -PI + i * step; z0 = -PI + j * step; x1: float = x0 + step; z1 = z0 + step
|
||||
y00: float = vipermath.sinf(x0) * vipermath.cosf(z0) * scale; y10: float = vipermath.sinf(x1) * vipermath.cosf(z0) * scale
|
||||
y01: float = vipermath.sinf(x0) * vipermath.cosf(z1) * scale; y11: float = vipermath.sinf(x1) * vipermath.cosf(z1) * scale
|
||||
|
||||
t1: float = (y00 / scale + float(1.0)) * float(0.5); r1: int = int(50 + 205 * t1); g1: int = int(80 + 120 * vipermath.sinf(t1 * PI)); b1: int = int(255 - 205 * t1)
|
||||
col1: t.CUInt32T = COLOR_RGB(255 if (r1 > 255) else (0 if (r1 < 0) else r1), 255 if (g1 > 255) else (0 if (g1 < 0) else g1), 255 if (b1 > 255) else (0 if (b1 < 0) else b1))
|
||||
t2: float = (y11 / scale + float(1.0)) * float(0.5); r2: int = int(50 + 205 * t2); g2: int = int(80 + 120 * vipermath.sinf(t2 * PI)); b2: int = int(255 - 205 * t2)
|
||||
col2: t.CUInt32T = COLOR_RGB(255 if (r2 > 255) else (0 if (r2 < 0) else r2), 255 if (g2 > 255) else (0 if (g2 < 0) else g2), 255 if (b2 > 255) else (0 if (b2 < 0) else b2))
|
||||
|
||||
v00: Vec3 = Mat4_MulVec(mvp, Vec3(x0, y00, z0)); v10: Vec3 = Mat4_MulVec(mvp, Vec3(x1, y10, z0))
|
||||
v01: Vec3 = Mat4_MulVec(mvp, Vec3(x0, y01, z1)); v11: Vec3 = Mat4_MulVec(mvp, Vec3(x1, y11, z1))
|
||||
self.renderer.DrawTriangle(v00, v10, v11, col1); self.renderer.DrawTriangle(v00, v11, v01, col2)
|
||||
from stdint import *
|
||||
import vipermath
|
||||
import string
|
||||
import t, c
|
||||
|
||||
|
||||
PI: t.CDefine = float(3.14159265358979323846)
|
||||
|
||||
SPHERE_SLICES: t.CDefine = (24 * 1)
|
||||
SPHERE_STACKS: t.CDefine = (16 * 1)
|
||||
SIN_WAVE_GRID: t.CDefine = (40 * 1)
|
||||
|
||||
def COLOR_RGB(r: int, g: int, b: int) -> t.CInline | int:
|
||||
return (255 << 24) | (r << 16) | (g << 8) | (b)
|
||||
|
||||
@t.Object
|
||||
class Vec3:
|
||||
x: float
|
||||
y: float
|
||||
z: float
|
||||
def __init__(self, x: float, y: float, z: float):
|
||||
self.x = x
|
||||
self.y = y
|
||||
self.z = z
|
||||
def Sub(self, b: 'Vec3') -> 'Vec3':
|
||||
return Vec3(self.x - b.x, self.y - b.y, self.z - b.z)
|
||||
def Cross(self, b: 'Vec3') -> 'Vec3':
|
||||
return Vec3(self.y * b.z - self.z * b.y, self.z * b.x - self.x * b.z, self.x * b.y - self.y * b.x)
|
||||
def Dot(self, b: 'Vec3') -> float:
|
||||
return self.x * b.x + self.y * b.y + self.z * b.z
|
||||
def Norm(self) -> 'Vec3':
|
||||
l = vipermath.sqrtf(self.Dot(self))
|
||||
return Vec3(self.x / l, self.y / l, self.z / l)
|
||||
|
||||
class Mat4:
|
||||
m: t.CArray[t.CArray[float, 4], 4]
|
||||
|
||||
def Mat4_Identity() -> Mat4:
|
||||
m: Mat4 = Mat4()
|
||||
string.memset(c.Addr(m), 0, Mat4.__sizeof__())
|
||||
m.m[0][0] = 1; m.m[1][1] = 1; m.m[2][2] = 1; m.m[3][3] = 1
|
||||
return m
|
||||
|
||||
def Mat4_Mul(a: Mat4, b: Mat4) -> Mat4:
|
||||
res: Mat4 = Mat4()
|
||||
string.memset(c.Addr(res), 0, Mat4.__sizeof__())
|
||||
for i in range(4):
|
||||
for j in range(4):
|
||||
for k in range(4):
|
||||
res.m[i][j] += a.m[i][k] * b.m[k][j]
|
||||
return res
|
||||
|
||||
def Mat4_MulVec(m: Mat4, v: Vec3) -> Vec3:
|
||||
x: float = m.m[0][0] * v.x + m.m[0][1] * v.y + m.m[0][2] * v.z + m.m[0][3]
|
||||
y: float = m.m[1][0] * v.x + m.m[1][1] * v.y + m.m[1][2] * v.z + m.m[1][3]
|
||||
z: float = m.m[2][0] * v.x + m.m[2][1] * v.y + m.m[2][2] * v.z + m.m[2][3]
|
||||
w: float = m.m[3][0] * v.x + m.m[3][1] * v.y + m.m[3][2] * v.z + m.m[3][3]
|
||||
if w != 0:
|
||||
x /= w; y /= w; z /= w
|
||||
return Vec3(x, y, z)
|
||||
|
||||
def Mat4_Perspective(fov: float, aspect: float, zn: float, zf: float) -> Mat4:
|
||||
m: Mat4 = Mat4()
|
||||
string.memset(c.Addr(m), 0, Mat4.__sizeof__())
|
||||
f: float = float(1.0) / vipermath.tanf(fov / float(2.0))
|
||||
m.m[0][0] = f / aspect; m.m[1][1] = f
|
||||
m.m[2][2] = zf / (zn - zf); m.m[2][3] = (zf * zn) / (zn - zf); m.m[3][2] = -1
|
||||
return m
|
||||
|
||||
def Mat4_LookAt(eye: Vec3, target: Vec3, up: Vec3) -> Mat4:
|
||||
zaxis: Vec3 = eye.Sub(target).Norm()
|
||||
xaxis: Vec3 = up.Cross(zaxis).Norm()
|
||||
yaxis: Vec3 = zaxis.Cross(xaxis)
|
||||
m: Mat4 = Mat4_Identity()
|
||||
m.m[0][0]=xaxis.x; m.m[0][1]=xaxis.y; m.m[0][2]=xaxis.z; m.m[0][3]= -xaxis.Dot(eye)
|
||||
m.m[1][0]=yaxis.x; m.m[1][1]=yaxis.y; m.m[1][2]=yaxis.z; m.m[1][3]= -yaxis.Dot(eye)
|
||||
m.m[2][0]=zaxis.x; m.m[2][1]=zaxis.y; m.m[2][2]=zaxis.z; m.m[2][3]= -zaxis.Dot(eye)
|
||||
m.m[3][3] = 1
|
||||
return m
|
||||
|
||||
def Mat4_Translate(x: float, y: float, z: float) -> Mat4:
|
||||
m: Mat4 = Mat4_Identity()
|
||||
m.m[0][3] = x; m.m[1][3] = y; m.m[2][3] = z
|
||||
return m
|
||||
|
||||
def Mat4_RotateY(a: float) -> Mat4:
|
||||
m: Mat4 = Mat4_Identity()
|
||||
m.m[0][0] = vipermath.cosf(a); m.m[0][2] = vipermath.sinf(a)
|
||||
m.m[2][0] = -vipermath.sinf(a); m.m[2][2] = vipermath.cosf(a)
|
||||
return m
|
||||
|
||||
|
||||
@t.Object
|
||||
class Surface:
|
||||
fb: UINT32PTR
|
||||
zb: float | t.CPtr
|
||||
w: int
|
||||
h: int
|
||||
def __init__(self, fb: UINT32PTR, zb: float | t.CPtr, w: int, h: int):
|
||||
self.fb = fb
|
||||
self.zb = zb
|
||||
self.w = w
|
||||
self.h = h
|
||||
|
||||
@t.Object
|
||||
class Renderer:
|
||||
_fb: UINT32PTR
|
||||
_zb: float | t.CPtr
|
||||
_w: int
|
||||
_h: int
|
||||
|
||||
def __init__(self, fb: UINT32PTR, zb: float | t.CPtr, w: int, h: int):
|
||||
self._fb = fb
|
||||
self._zb = zb
|
||||
self._w = w
|
||||
self._h = h
|
||||
|
||||
def Clear(self, color: uint32):
|
||||
fb: UINT32PTR = self._fb
|
||||
zb: float | t.CPtr = self._zb
|
||||
size: int = self._w * self._h
|
||||
for i in range(size):
|
||||
fb[i] = color
|
||||
zb[i] = float(1.0)
|
||||
|
||||
def DrawLine2D(self, x0: int, y0: int, x1: int, y1: int, col: uint32):
|
||||
fb: UINT32PTR = self._fb
|
||||
w: int = self._w; h: int = self._h
|
||||
dx: int = abs(x1-x0); dy: int = abs(y1-y0)
|
||||
sx: int = 1 if x0 < x1 else -1; sy: int = 1 if y0 < y1 else -1
|
||||
err: int = dx - dy
|
||||
while True:
|
||||
if x0 >= 0 and x0 < w and y0 >= 0 and y0 < h: fb[y0 * w + x0] = col
|
||||
if x0 == x1 and y0 == y1: break
|
||||
e2: int = 2 * err
|
||||
if e2 > -dy: err -= dy; x0 += sx
|
||||
if e2 < dx: err += dx; y0 += sy
|
||||
|
||||
def DrawTriangle(self, v0: Vec3, v1: Vec3, v2: Vec3, col: uint32):
|
||||
if v0.z < float(0.0) or v1.z < float(0.0) or v2.z < float(0.0): return
|
||||
if (v0.x > float(10.0) or v0.x < float(-10.0) or v0.y > float(10.0) or v0.y < float(-10.0) or
|
||||
v1.x > float(10.0) or v1.x < float(-10.0) or v1.y > float(10.0) or v1.y < float(-10.0) or
|
||||
v2.x > float(10.0) or v2.x < float(-10.0) or v2.y > float(10.0) or v2.y < float(-10.0)): return
|
||||
|
||||
fb: UINT32PTR = self._fb
|
||||
zb: float | t.CPtr = self._zb
|
||||
w: int = self._w
|
||||
h: int = self._h
|
||||
|
||||
sx0: float = (v0.x + float(1.0)) * float(0.5) * w; sy0: float = (float(1.0) - v0.y) * float(0.5) * h
|
||||
sx1: float = (v1.x + float(1.0)) * float(0.5) * w; sy1: float = (float(1.0) - v1.y) * float(0.5) * h
|
||||
sx2: float = (v2.x + float(1.0)) * float(0.5) * w; sy2: float = (float(1.0) - v2.y) * float(0.5) * h
|
||||
|
||||
minX: int = max(0, int(vipermath.floorf(min(min(sx0, sx1), sx2))))
|
||||
maxX: int = min(w - 1, int(vipermath.ceilf(max(max(sx0, sx1), sx2))))
|
||||
minY: int = max(0, int(vipermath.floorf(min(min(sy0, sy1), sy2))))
|
||||
maxY: int = min(h - 1, int(vipermath.ceilf(max(max(sy0, sy1), sy2))))
|
||||
|
||||
dx12: float = sx1 - sx2; dy12: float = sy1 - sy2
|
||||
dx02: float = sx0 - sx2; dy02: float = sy0 - sy2
|
||||
denom: float = dx12 * dy02 - dy12 * dx02
|
||||
if denom < float(0.001) and denom > float(-0.001): return
|
||||
invDenom: float = float(1.0) / denom
|
||||
|
||||
row_dxP_start: float = float(minX) - sx2
|
||||
for y in range(minY, maxY + 1):
|
||||
dyP: float = float(y) - sy2
|
||||
dxP: float = row_dxP_start
|
||||
row_base: int = y * w
|
||||
for x in range(minX, maxX + 1):
|
||||
w0: float = (dx12 * dyP - dy12 * dxP) * invDenom
|
||||
w1: float = (dxP * dy02 - dyP * dx02) * invDenom
|
||||
w2: float = float(1.0) - w0 - w1
|
||||
if w0 >= 0 and w1 >= 0 and w2 >= 0:
|
||||
z: float = w0 * v0.z + w1 * v1.z + w2 * v2.z
|
||||
idx: int = row_base + x
|
||||
if z < zb[idx]:
|
||||
zb[idx] = z
|
||||
fb[idx] = col
|
||||
dxP += float(1.0)
|
||||
|
||||
def DrawGlowDot(self, x: float, y: float, radius: float, core_col: uint32, intensity: float):
|
||||
fb: UINT32PTR = self._fb; w: int = self._w; h: int = self._h
|
||||
r: int = int(radius) + 4
|
||||
ix: int = int(x); iy: int = int(y)
|
||||
for dy in range(-r, r + 1):
|
||||
py: int = iy + dy
|
||||
if py < 0 or py >= h: continue
|
||||
for dx in range(-r, r + 1):
|
||||
px: int = ix + dx
|
||||
if px < 0 or px >= w: continue
|
||||
dist: float = vipermath.sqrtf(float(dx*dx + dy*dy))
|
||||
if dist < radius:
|
||||
self.BlendPixel(px, py, core_col, intensity)
|
||||
elif dist < float(r):
|
||||
fade: float = 1.0 - (dist - radius) / 4.0
|
||||
self.BlendPixel(px, py, core_col, intensity * fade * 0.5)
|
||||
|
||||
def BlendPixel(self, x: int, y: int, col: uint32, alpha: float):
|
||||
if alpha <= 0.0: return
|
||||
fb: UINT32PTR = self._fb; w: int = self._w; h: int = self._h
|
||||
if x < 0 or x >= w or y < 0 or y >= h: return
|
||||
|
||||
idx: int = y * w + x
|
||||
bg: uint32 = fb[idx]
|
||||
bg_b: int = bg & 0xFF; bg_g: int = (bg >> 8) & 0xFF; bg_r: int = (bg >> 16) & 0xFF
|
||||
f_b: int = col & 0xFF; f_g: int = (col >> 8) & 0xFF; f_r: int = (col >> 16) & 0xFF
|
||||
|
||||
a: int = int(alpha * 255.0)
|
||||
inv_a: int = 255 - a
|
||||
nr: int = (f_r * a + bg_r * inv_a) >> 8
|
||||
ng: int = (f_g * a + bg_g * inv_a) >> 8
|
||||
nb: int = (f_b * a + bg_b * inv_a) >> 8
|
||||
|
||||
fb[idx] = COLOR_RGB(255 if (nr > 255) else nr,
|
||||
255 if (ng > 255) else ng,
|
||||
255 if (nb > 255) else nb)
|
||||
|
||||
|
||||
@t.Object
|
||||
class Scene3D:
|
||||
renderer: Renderer
|
||||
|
||||
def __init__(self, fb: UINT32PTR, zb: float | t.CPtr, w: int, h: int):
|
||||
self.renderer = Renderer(fb, zb, w, h)
|
||||
|
||||
def Render(self, time: float):
|
||||
rw: int = self.renderer._w
|
||||
rh: int = self.renderer._h
|
||||
self.renderer.Clear(COLOR_RGB(15, 15, 25))
|
||||
|
||||
yaw: float = float(45.0) * PI / float(180.0); pitch: float = float(45.0) * PI / float(180.0); radius: float = float(10.0)
|
||||
eye: Vec3 = Vec3(radius*vipermath.cosf(pitch)*vipermath.cosf(yaw), radius*vipermath.sinf(pitch), radius*vipermath.cosf(pitch)*vipermath.sinf(yaw))
|
||||
target: Vec3 = Vec3(0, 0, 0); up: Vec3 = Vec3(0, 1, 0)
|
||||
view: Mat4 = Mat4_LookAt(eye, target, up)
|
||||
proj: Mat4 = Mat4_Perspective(PI / float(3.0), float(rw)/float(rh), float(0.1), float(100.0))
|
||||
vp: Mat4 = Mat4_Mul(proj, view)
|
||||
|
||||
cubeX: float = float(-3.5)
|
||||
cubeMVP: Mat4 = Mat4_Mul(vp, Mat4_Translate(cubeX, 0, 0))
|
||||
self._DrawCube(cubeMVP, COLOR_RGB(180, 180, 180))
|
||||
|
||||
colors: t.CArray[uint32, 4] = [COLOR_RGB(255,50,50), COLOR_RGB(50,50,255), COLOR_RGB(255,255,50), COLOR_RGB(50,255,255)]
|
||||
for i in range(4):
|
||||
a: float = time * float(1.5) + i * (PI / float(2.0)); r: float = float(3.0)
|
||||
pos: Vec3 = Vec3(vipermath.cosf(a) * r + cubeX, 0, vipermath.sinf(a) * r)
|
||||
sphereMVP: Mat4 = Mat4_Mul(vp, Mat4_Translate(pos.x, pos.y, pos.z))
|
||||
self._DrawSphere(sphereMVP, Vec3(0,0,0), float(0.5), colors[i])
|
||||
|
||||
self._Draw3DSinWave(vp, Vec3(float(3.5), 0, 0), time)
|
||||
|
||||
self.renderer.DrawLine2D(50, rh - 150, rw - 50, rh - 150, COLOR_RGB(80, 80, 80))
|
||||
self.renderer.DrawLine2D(50, rh - 50, 50, rh - 250, COLOR_RGB(80, 80, 80))
|
||||
wave_shift: float = time * float(2.0)
|
||||
prev_x: int = 50; prev_y: int = rh - 150 - int(vipermath.sinf(0 - wave_shift) * float(100.0))
|
||||
for i in range(1, rw - 100):
|
||||
tr: float = float(i) / float(rw-100) * float(4.0) * PI
|
||||
cx: int = 50 + i; cy: int = rh - 150 - int(vipermath.sinf(tr - wave_shift) * float(100.0))
|
||||
self.renderer.DrawLine2D(prev_x, prev_y, cx, cy, COLOR_RGB(0, 255, 100))
|
||||
prev_x = cx; prev_y = cy
|
||||
|
||||
def _DrawCube(self, mvp: Mat4, col: uint32):
|
||||
v: t.CArray[Vec3, 8] = [
|
||||
Vec3(-1, -1, -1), Vec3(-1, -1, 1), Vec3(-1, 1, -1), Vec3(-1, 1, 1),
|
||||
Vec3( 1, -1, -1), Vec3( 1, -1, 1), Vec3( 1, 1, -1), Vec3( 1, 1, 1)
|
||||
]
|
||||
for i in range(8): v[i] = Mat4_MulVec(mvp, v[i])
|
||||
faces: t.CArray[t.CArray[int, 3], 12] = [
|
||||
[0, 2, 1], [1, 2, 3], [4, 1, 5], [4, 0, 1], [6, 3, 2], [6, 7, 3],
|
||||
[4, 6, 0], [0, 6, 2], [5, 7, 4], [4, 7, 6], [1, 3, 5], [5, 3, 7]
|
||||
]
|
||||
for i in range(12): self.renderer.DrawTriangle(v[faces[i][0]], v[faces[i][1]], v[faces[i][2]], col)
|
||||
|
||||
def _DrawSphere(self, mvp: Mat4, center: Vec3, radius: float, col: uint32):
|
||||
step_pi: float = PI / SPHERE_STACKS; step_2pi: float = float(2.0) * PI / SPHERE_SLICES
|
||||
for i in range(SPHERE_STACKS):
|
||||
for j in range(SPHERE_SLICES):
|
||||
theta1: float = i * step_pi; theta2: float = (i + 1) * step_pi
|
||||
phi1: float = j * step_2pi; phi2: float = (j + 1) * step_2pi
|
||||
v: t.CArray[Vec3, 4]
|
||||
v[0] = Vec3(center.x+radius*vipermath.sinf(theta1)*vipermath.cosf(phi1), center.y+radius*vipermath.cosf(theta1), center.z+radius*vipermath.sinf(theta1)*vipermath.sinf(phi1))
|
||||
v[1] = Vec3(center.x+radius*vipermath.sinf(theta1)*vipermath.cosf(phi2), center.y+radius*vipermath.cosf(theta1), center.z+radius*vipermath.sinf(theta1)*vipermath.sinf(phi2))
|
||||
v[2] = Vec3(center.x+radius*vipermath.sinf(theta2)*vipermath.cosf(phi1), center.y+radius*vipermath.cosf(theta2), center.z+radius*vipermath.sinf(theta2)*vipermath.sinf(phi1))
|
||||
v[3] = Vec3(center.x+radius*vipermath.sinf(theta2)*vipermath.cosf(phi2), center.y+radius*vipermath.cosf(theta2), center.z+radius*vipermath.sinf(theta2)*vipermath.sinf(phi2))
|
||||
for k in range(4): v[k] = Mat4_MulVec(mvp, v[k])
|
||||
self.renderer.DrawTriangle(v[0], v[1], v[2], col)
|
||||
self.renderer.DrawTriangle(v[1], v[3], v[2], col)
|
||||
|
||||
def _Draw3DSinWave(self, vp: Mat4, pos: Vec3, time: float):
|
||||
_range: float = float(2.0) * PI; step: float = _range / SIN_WAVE_GRID; scale: float = float(0.5)
|
||||
mvp: Mat4 = Mat4_Mul(vp, Mat4_Mul(Mat4_Translate(pos.x, pos.y, pos.z), Mat4_RotateY(time * float(1.0))))
|
||||
for i in range(SIN_WAVE_GRID):
|
||||
for j in range(SIN_WAVE_GRID):
|
||||
x0: float = -PI + i * step; z0 = -PI + j * step; x1: float = x0 + step; z1 = z0 + step
|
||||
y00: float = vipermath.sinf(x0) * vipermath.cosf(z0) * scale; y10: float = vipermath.sinf(x1) * vipermath.cosf(z0) * scale
|
||||
y01: float = vipermath.sinf(x0) * vipermath.cosf(z1) * scale; y11: float = vipermath.sinf(x1) * vipermath.cosf(z1) * scale
|
||||
|
||||
t1: float = (y00 / scale + float(1.0)) * float(0.5); r1: int = int(50 + 205 * t1); g1: int = int(80 + 120 * vipermath.sinf(t1 * PI)); b1: int = int(255 - 205 * t1)
|
||||
col1: uint32 = COLOR_RGB(255 if (r1 > 255) else (0 if (r1 < 0) else r1), 255 if (g1 > 255) else (0 if (g1 < 0) else g1), 255 if (b1 > 255) else (0 if (b1 < 0) else b1))
|
||||
t2: float = (y11 / scale + float(1.0)) * float(0.5); r2: int = int(50 + 205 * t2); g2: int = int(80 + 120 * vipermath.sinf(t2 * PI)); b2: int = int(255 - 205 * t2)
|
||||
col2: uint32 = COLOR_RGB(255 if (r2 > 255) else (0 if (r2 < 0) else r2), 255 if (g2 > 255) else (0 if (g2 < 0) else g2), 255 if (b2 > 255) else (0 if (b2 < 0) else b2))
|
||||
|
||||
v00: Vec3 = Mat4_MulVec(mvp, Vec3(x0, y00, z0)); v10: Vec3 = Mat4_MulVec(mvp, Vec3(x1, y10, z0))
|
||||
v01: Vec3 = Mat4_MulVec(mvp, Vec3(x0, y01, z1)); v11: Vec3 = Mat4_MulVec(mvp, Vec3(x1, y11, z1))
|
||||
self.renderer.DrawTriangle(v00, v10, v11, col1); self.renderer.DrawTriangle(v00, v11, v01, col2)
|
||||
+66
-66
@@ -1,66 +1,66 @@
|
||||
import vpsdk.window as window
|
||||
import vpsdk.process as process
|
||||
import vpsdk.vpui as vpui
|
||||
import vpsdk.stdlib as stdlib
|
||||
import vpsdk.stdio as stdio
|
||||
import viperstring as string
|
||||
import vipermath
|
||||
from stdint import *
|
||||
import gfx
|
||||
import t, c
|
||||
|
||||
SCENE_W: t.CDefine = 640
|
||||
SCENE_H: t.CDefine = 360
|
||||
|
||||
_zbuf_mem: t.CArray[t.CUInt8T, SCENE_W * SCENE_H * 8]
|
||||
_fb_mem: t.CArray[t.CUInt32T, SCENE_W * SCENE_H]
|
||||
|
||||
_root_ptr: vpui.Tk | t.CPtr
|
||||
_canvas_ptr: vpui.FBCanvas | t.CPtr
|
||||
_s3d_ptr: gfx.Scene3D | t.CPtr
|
||||
_time_val: float = float(0.0)
|
||||
|
||||
def _render_thread(arg: t.CVoid | t.CPtr) -> t.CVoid:
|
||||
root: vpui.Tk | t.CPtr = _root_ptr
|
||||
canvas: vpui.FBCanvas | t.CPtr = _canvas_ptr
|
||||
s3d: gfx.Scene3D | t.CPtr = _s3d_ptr
|
||||
while root.winfo_exists():
|
||||
s3d.Render(_time_val)
|
||||
_time_val += float(0.02)
|
||||
root.update()
|
||||
process.yield_cpu()
|
||||
|
||||
@c.Attribute(t.attr.section(".text.startup"), t.attr.aligned(16))
|
||||
def _start() -> t.CInt | t.CExport:
|
||||
root: vpui.Tk = vpui.Tk()
|
||||
root.title("3D Scene")
|
||||
root.set_style(window.STYLE_WIN11)
|
||||
root.bg_color = t.CUInt32T(0x0F0F19)
|
||||
master: vpui.Tk | t.CPtr = c.Addr(root)
|
||||
|
||||
canvas: vpui.FBCanvas = vpui.FBCanvas(master, SCENE_W, SCENE_H)
|
||||
root.pack(0, vpui.PACK_TOP, vpui.FILL_BOTH, 1, 0, 0)
|
||||
|
||||
zbuf: float | t.CPtr = t.CVoid(c.Addr(_zbuf_mem), t.CPtr)
|
||||
string.memset(zbuf, 0, SCENE_W * SCENE_H * 8)
|
||||
|
||||
fb: UINT32PTR = c.Addr(_fb_mem)
|
||||
string.memset(fb, 0, SCENE_W * SCENE_H * 4)
|
||||
canvas.set_fb(fb, SCENE_W, SCENE_H)
|
||||
|
||||
s3d: gfx.Scene3D = gfx.Scene3D(fb, zbuf, SCENE_W, SCENE_H)
|
||||
|
||||
root.geometry(100, 30, SCENE_W, SCENE_H + 32)
|
||||
|
||||
global _root_ptr, _canvas_ptr, _s3d_ptr
|
||||
|
||||
_root_ptr = c.Addr(root)
|
||||
_canvas_ptr = c.Addr(canvas)
|
||||
_s3d_ptr = c.Addr(s3d)
|
||||
|
||||
process.thread_create(_render_thread, None)
|
||||
|
||||
root.mainloop()
|
||||
|
||||
process.exit(0)
|
||||
return 0
|
||||
import vpsdk.window as window
|
||||
import vpsdk.process as process
|
||||
import vpsdk.vpui as vpui
|
||||
import vpsdk.stdlib as stdlib
|
||||
import vpsdk.stdio as stdio
|
||||
import viperstring as string
|
||||
import vipermath
|
||||
from stdint import *
|
||||
import gfx
|
||||
import t, c
|
||||
|
||||
SCENE_W: t.CDefine = 640
|
||||
SCENE_H: t.CDefine = 360
|
||||
|
||||
_zbuf_mem: t.CArray[uint8, SCENE_W * SCENE_H * 8]
|
||||
_fb_mem: t.CArray[uint32, SCENE_W * SCENE_H]
|
||||
|
||||
_root_ptr: vpui.Tk | t.CPtr
|
||||
_canvas_ptr: vpui.FBCanvas | t.CPtr
|
||||
_s3d_ptr: gfx.Scene3D | t.CPtr
|
||||
_time_val: float = float(0.0)
|
||||
|
||||
def _render_thread(arg: t.CPtr) -> t.CVoid:
|
||||
root: vpui.Tk | t.CPtr = _root_ptr
|
||||
canvas: vpui.FBCanvas | t.CPtr = _canvas_ptr
|
||||
s3d: gfx.Scene3D | t.CPtr = _s3d_ptr
|
||||
while root.winfo_exists():
|
||||
s3d.Render(_time_val)
|
||||
_time_val += float(0.02)
|
||||
root.update()
|
||||
process.yield_cpu()
|
||||
|
||||
@c.Attribute(t.attr.section(".text.startup"), t.attr.aligned(16))
|
||||
def _start() -> int | t.CExport:
|
||||
root: vpui.Tk = vpui.Tk()
|
||||
root.title("3D Scene")
|
||||
root.set_style(window.STYLE_WIN11)
|
||||
root.bg_color = uint32(0x0F0F19)
|
||||
master: vpui.Tk | t.CPtr = c.Addr(root)
|
||||
|
||||
canvas: vpui.FBCanvas = vpui.FBCanvas(master, SCENE_W, SCENE_H)
|
||||
root.pack(0, vpui.PACK_TOP, vpui.FILL_BOTH, 1, 0, 0)
|
||||
|
||||
zbuf: float | t.CPtr = t.CVoid(c.Addr(_zbuf_mem), t.CPtr)
|
||||
string.memset(zbuf, 0, SCENE_W * SCENE_H * 8)
|
||||
|
||||
fb: UINT32PTR = c.Addr(_fb_mem)
|
||||
string.memset(fb, 0, SCENE_W * SCENE_H * 4)
|
||||
canvas.set_fb(fb, SCENE_W, SCENE_H)
|
||||
|
||||
s3d: gfx.Scene3D = gfx.Scene3D(fb, zbuf, SCENE_W, SCENE_H)
|
||||
|
||||
root.geometry(100, 30, SCENE_W, SCENE_H + 32)
|
||||
|
||||
global _root_ptr, _canvas_ptr, _s3d_ptr
|
||||
|
||||
_root_ptr = c.Addr(root)
|
||||
_canvas_ptr = c.Addr(canvas)
|
||||
_s3d_ptr = c.Addr(s3d)
|
||||
|
||||
process.thread_create(_render_thread, None)
|
||||
|
||||
root.mainloop()
|
||||
|
||||
process.exit(0)
|
||||
return 0
|
||||
+327
-327
@@ -1,327 +1,327 @@
|
||||
import vpsdk.vpui as vpui
|
||||
import vpsdk.window as window
|
||||
import vpsdk.process as process
|
||||
import vpsdk.fs as fs
|
||||
import vpsdk.syscall as _syscall
|
||||
import vpsdk.stdlib as stdlib
|
||||
import vpsdk.stdio as stdio
|
||||
import string
|
||||
import viperlib
|
||||
from stdint import *
|
||||
import t, c
|
||||
|
||||
@c.Attribute(t.attr.section(".text.startup"), t.attr.aligned(16))
|
||||
def _start() -> t.CInt | t.CExport:
|
||||
root: vpui.Tk = vpui.Tk()
|
||||
root.title("Terminal")
|
||||
root.set_style(window.STYLE_WIN7)
|
||||
root.geometry(80, 30, 640, 480)
|
||||
root.bg_color = t.CUInt32T(0x0C0C0C)
|
||||
master: vpui.Tk | t.CPtr = c.Addr(root)
|
||||
|
||||
def _sdbg(msg: str):
|
||||
_syscall._syscall1(t.CUInt64T(18), t.CUInt64T(msg))
|
||||
|
||||
_sdbg("[term] start\n")
|
||||
|
||||
_cwd: t.CArray[t.CChar, 64]
|
||||
_cwd[0] = 47
|
||||
for i in range(1, 64):
|
||||
_cwd[i] = 0
|
||||
|
||||
sbar: vpui.Scrollbar = vpui.Scrollbar(master, 16, 446, vpui.VERTICAL)
|
||||
root.pack(0, vpui.PACK_RIGHT, vpui.FILL_Y, 0, 0, 0)
|
||||
|
||||
term: vpui.Text = vpui.Text(master, 624, 446)
|
||||
root.pack(1, vpui.PACK_LEFT, vpui.FILL_BOTH, 1, 0, 0)
|
||||
term.insert("ViperOS Terminal v1.1")
|
||||
term.insert("Type 'help' for commands.")
|
||||
term.insert("")
|
||||
|
||||
term.yscrollbar = t.CType(sbar, vpui.Widget, t.CPtr)
|
||||
|
||||
def _on_scroll():
|
||||
act: t.CInt = sbar.action
|
||||
if act == 1:
|
||||
term.scroll_offset -= 1
|
||||
elif act == 2:
|
||||
term.scroll_offset += 1
|
||||
elif act == 3:
|
||||
vis: t.CInt = term._visible_lines()
|
||||
term.scroll_offset -= vis
|
||||
elif act == 4:
|
||||
vis2: t.CInt = term._visible_lines()
|
||||
term.scroll_offset += vis2
|
||||
elif act == 5:
|
||||
aval: t.CInt = sbar.action_value
|
||||
if term.line_count > 0:
|
||||
term.scroll_offset = aval * term.line_count / 1000
|
||||
vis3: t.CInt = term._visible_lines()
|
||||
max_off: t.CInt = term.line_count - vis3
|
||||
if max_off < 0: max_off = 0
|
||||
if term.scroll_offset < 0: term.scroll_offset = 0
|
||||
if term.scroll_offset > max_off: term.scroll_offset = max_off
|
||||
term._update_scrollbar()
|
||||
|
||||
sbar.command = c.Addr(_on_scroll)
|
||||
|
||||
def _startswith(s: str, prefix: str) -> t.CInt:
|
||||
plen: t.CSizeT = string.strlen(prefix)
|
||||
if string.strncmp(s, prefix, plen) == 0:
|
||||
return 1
|
||||
return 0
|
||||
|
||||
def _build_path(out: str, out_size: t.CInt, rel: str):
|
||||
if c.Deref(rel) == 47:
|
||||
string.strncpy(out, rel, out_size - 1)
|
||||
else:
|
||||
i: t.CInt = 0
|
||||
for i in range(63):
|
||||
ch: t.CChar = _cwd[i]
|
||||
c.DerefAs(out + i, ch)
|
||||
if ch == 0: break
|
||||
cwd_len: t.CInt = i
|
||||
if cwd_len > 0 and _cwd[cwd_len - 1] != 47:
|
||||
c.DerefAs(out + cwd_len, t.CChar(47))
|
||||
cwd_len += 1
|
||||
j: t.CInt = 0
|
||||
for j in range(out_size - 1 - cwd_len):
|
||||
ch2: t.CChar = c.Deref(rel + j)
|
||||
c.DerefAs(out + cwd_len + j, ch2)
|
||||
if ch2 == 0: break
|
||||
c.DerefAs(out + out_size - 1, t.CChar(0))
|
||||
|
||||
def _print_dir_entry(name: str, is_dir: t.CInt):
|
||||
buf: t.CArray[t.CChar, 80]
|
||||
j: t.CInt = 0
|
||||
for j in range(78):
|
||||
ch: t.CChar = c.Deref(name + j)
|
||||
buf[j] = ch
|
||||
if ch == 0: break
|
||||
if is_dir and j < 78:
|
||||
buf[j] = 47
|
||||
j += 1
|
||||
buf[j] = 0
|
||||
term.insert_ptr(c.Addr(buf[0]))
|
||||
|
||||
def _cmd_cd(path: str):
|
||||
if path is None or c.Deref(path) == 0:
|
||||
_cwd[0] = 47
|
||||
for i in range(1, 64):
|
||||
_cwd[i] = 0
|
||||
return
|
||||
full: t.CArray[t.CChar, 256]
|
||||
_build_path(c.Addr(full[0]), 256, path)
|
||||
dd: t.CInt = fs.opendir(c.Addr(full[0]))
|
||||
if dd < 0:
|
||||
term.insert("Error: dir not found")
|
||||
return
|
||||
fs.closedir(dd)
|
||||
string.strncpy(c.Addr(_cwd[0]), c.Addr(full[0]), 63)
|
||||
_cwd[63] = 0
|
||||
|
||||
def _cmd_ls():
|
||||
dd: t.CInt = fs.opendir(c.Addr(_cwd[0]))
|
||||
if dd < 0:
|
||||
term.insert("Error: cannot open dir")
|
||||
return
|
||||
info: t.CArray[t.CChar, 320]
|
||||
string.memset(c.Addr(info[0]), 0, 320)
|
||||
while True:
|
||||
result: t.CInt = fs.readdir(dd, c.Addr(info[0]))
|
||||
if result != 0: break
|
||||
attr_val: t.CUInt8T = t.CUInt8T(c.Deref(c.Addr(info[4])))
|
||||
name_off: t.CInt = 16
|
||||
name_ptr: str = c.Addr(info[name_off])
|
||||
if c.Deref(name_ptr) == 0: break
|
||||
if c.Deref(name_ptr) == 46:
|
||||
if c.Deref(name_ptr + 1) == 0:
|
||||
string.memset(c.Addr(info[0]), 0, 320)
|
||||
continue
|
||||
if c.Deref(name_ptr + 1) == 46 and c.Deref(name_ptr + 2) == 0:
|
||||
string.memset(c.Addr(info[0]), 0, 320)
|
||||
continue
|
||||
if (attr_val & 0x10) != 0:
|
||||
_print_dir_entry(name_ptr, 1)
|
||||
else:
|
||||
_print_dir_entry(name_ptr, 0)
|
||||
string.memset(c.Addr(info[0]), 0, 320)
|
||||
fs.closedir(dd)
|
||||
|
||||
def _cmd_cat(path: str):
|
||||
full: t.CArray[t.CChar, 256]
|
||||
_build_path(c.Addr(full[0]), 256, path)
|
||||
fd: t.CInt = fs.open(c.Addr(full[0]), fs.O_RDONLY)
|
||||
if fd < 0:
|
||||
term.insert("Error: file not found")
|
||||
return
|
||||
buf: t.CArray[t.CChar, 80]
|
||||
while True:
|
||||
string.memset(c.Addr(buf[0]), 0, 80)
|
||||
n: t.CInt = fs.read(fd, c.Addr(buf[0]), 78)
|
||||
if n <= 0: break
|
||||
if n > 78: n = 78
|
||||
buf[n] = 0
|
||||
term.insert_ptr(c.Addr(buf[0]))
|
||||
fs.close(fd)
|
||||
|
||||
def _cmd_mkdir(path: str):
|
||||
full: t.CArray[t.CChar, 256]
|
||||
_build_path(c.Addr(full[0]), 256, path)
|
||||
result: t.CInt = fs.mkdir(c.Addr(full[0]))
|
||||
if result < 0:
|
||||
term.insert("Error: mkdir failed")
|
||||
else:
|
||||
term.insert("Directory created")
|
||||
|
||||
def _cmd_rm(path: str):
|
||||
full: t.CArray[t.CChar, 256]
|
||||
_build_path(c.Addr(full[0]), 256, path)
|
||||
result: t.CInt = fs.remove(c.Addr(full[0]))
|
||||
if result < 0:
|
||||
term.insert("Error: remove failed")
|
||||
else:
|
||||
term.insert("Removed")
|
||||
|
||||
def _cmd_touch(path: str):
|
||||
full: t.CArray[t.CChar, 256]
|
||||
_build_path(c.Addr(full[0]), 256, path)
|
||||
fd: t.CInt = fs.open(c.Addr(full[0]), fs.O_WRONLY | fs.O_CREAT)
|
||||
if fd < 0:
|
||||
term.insert("Error: touch failed")
|
||||
return
|
||||
fs.close(fd)
|
||||
term.insert("File created")
|
||||
|
||||
def _cmd_sysinfo():
|
||||
term.insert("ViperOS v1.0 (x86_64)")
|
||||
term.insert("Framebuffer: 32bpp")
|
||||
term.insert("Compiler: TransPyC")
|
||||
|
||||
def _cmd_hexdump(path: str):
|
||||
full: t.CArray[t.CChar, 256]
|
||||
_build_path(c.Addr(full[0]), 256, path)
|
||||
fd: t.CInt = fs.open(c.Addr(full[0]), fs.O_RDONLY)
|
||||
if fd < 0:
|
||||
term.insert("Error: file not found")
|
||||
return
|
||||
offset: t.CInt = 0
|
||||
buf: t.CArray[t.CChar, 16]
|
||||
while True:
|
||||
string.memset(c.Addr(buf[0]), 0, 16)
|
||||
n: t.CInt = fs.read(fd, c.Addr(buf[0]), 16)
|
||||
if n <= 0: break
|
||||
if n > 16: n = 16
|
||||
line: t.CArray[t.CChar, 80]
|
||||
string.memset(c.Addr(line[0]), 0, 80)
|
||||
viperlib.snprintf(c.Addr(line[0]), 80, "%08x: ", offset)
|
||||
pos: t.CInt = 10
|
||||
j: t.CInt = 0
|
||||
for j in range(16):
|
||||
if j < n:
|
||||
ub: t.CUInt32T = t.CUInt32T(buf[j]) & 0xFF
|
||||
hi: t.CInt = t.CInt(ub >> 4)
|
||||
lo: t.CInt = t.CInt(ub & 0xF)
|
||||
if hi < 10:
|
||||
line[pos] = t.CChar(48 + hi)
|
||||
else:
|
||||
line[pos] = t.CChar(65 + hi - 10)
|
||||
pos += 1
|
||||
if lo < 10:
|
||||
line[pos] = t.CChar(48 + lo)
|
||||
else:
|
||||
line[pos] = t.CChar(65 + lo - 10)
|
||||
pos += 1
|
||||
else:
|
||||
line[pos] = 32
|
||||
pos += 1
|
||||
line[pos] = 32
|
||||
pos += 1
|
||||
line[pos] = 32
|
||||
pos += 1
|
||||
if j == 7:
|
||||
line[pos] = 32
|
||||
pos += 1
|
||||
line[pos] = 124
|
||||
pos += 1
|
||||
for j in range(n):
|
||||
b2: t.CUInt32T = t.CUInt32T(buf[j]) & 0xFF
|
||||
if b2 >= 32 and b2 < 127:
|
||||
line[pos] = t.CChar(b2)
|
||||
else:
|
||||
line[pos] = 46
|
||||
pos += 1
|
||||
line[pos] = 0
|
||||
term.insert_ptr(c.Addr(line[0]))
|
||||
offset += n
|
||||
fs.close(fd)
|
||||
|
||||
def _cmd_run(path: str, blocking: t.CInt):
|
||||
full: t.CArray[t.CChar, 256]
|
||||
_build_path(c.Addr(full[0]), 256, path)
|
||||
pid: t.CInt = process.spawn(c.Addr(full[0]), blocking)
|
||||
if pid < 0:
|
||||
term.insert("Error: cannot spawn")
|
||||
elif blocking:
|
||||
term.insert("Process exited")
|
||||
else:
|
||||
msg: t.CArray[t.CChar, 32]
|
||||
viperlib.snprintf(c.Addr(msg[0]), 32, "Spawned pid=%d", pid)
|
||||
term.insert_ptr(c.Addr(msg[0]))
|
||||
|
||||
def _on_command() -> t.CInt:
|
||||
_sdbg("[cmd] enter\n")
|
||||
text: str = term.get()
|
||||
_sdbg("[cmd] text=")
|
||||
_sdbg(text)
|
||||
_sdbg("\n")
|
||||
if _startswith(text, "echo "):
|
||||
term.insert_ptr(text + 5)
|
||||
elif string.samestr(text, "echo"):
|
||||
pass
|
||||
elif string.samestr(text, "clear"):
|
||||
term.delete(0, -1)
|
||||
elif string.samestr(text, "help"):
|
||||
term.insert("File: ls cd cat pwd mkdir rm touch")
|
||||
term.insert("Sys: ver about sysinfo reboot")
|
||||
term.insert("Util: echo clear help hexdump run runb")
|
||||
elif string.samestr(text, "ver"):
|
||||
term.insert("ViperOS Terminal v1.1")
|
||||
elif string.samestr(text, "about"):
|
||||
term.insert("ViperOS - A tiny OS in Viper lang")
|
||||
elif string.samestr(text, "pwd"):
|
||||
term.insert_ptr(c.Addr(_cwd[0]))
|
||||
elif string.samestr(text, "ls"):
|
||||
_cmd_ls()
|
||||
elif string.samestr(text, "cd"):
|
||||
_cmd_cd("")
|
||||
elif _startswith(text, "cd "):
|
||||
_cmd_cd(text + 3)
|
||||
elif _startswith(text, "cat "):
|
||||
_cmd_cat(text + 4)
|
||||
elif _startswith(text, "mkdir "):
|
||||
_cmd_mkdir(text + 6)
|
||||
elif _startswith(text, "rm "):
|
||||
_cmd_rm(text + 3)
|
||||
elif _startswith(text, "touch "):
|
||||
_cmd_touch(text + 6)
|
||||
elif string.samestr(text, "sysinfo"):
|
||||
_cmd_sysinfo()
|
||||
elif string.samestr(text, "reboot"):
|
||||
process.exit(0)
|
||||
elif _startswith(text, "hexdump "):
|
||||
_cmd_hexdump(text + 8)
|
||||
elif _startswith(text, "run "):
|
||||
_cmd_run(text + 4, 0)
|
||||
elif _startswith(text, "runb "):
|
||||
_cmd_run(text + 5, 1)
|
||||
else:
|
||||
if text is not None and c.Deref(text) != 0:
|
||||
term.insert("Unknown command. Type 'help'.")
|
||||
return 0
|
||||
|
||||
term.on_command = c.Addr(_on_command)
|
||||
|
||||
root.mainloop()
|
||||
process.exit(0)
|
||||
return 0
|
||||
import vpsdk.vpui as vpui
|
||||
import vpsdk.window as window
|
||||
import vpsdk.process as process
|
||||
import vpsdk.fs as fs
|
||||
import vpsdk.syscall as _syscall
|
||||
import vpsdk.stdlib as stdlib
|
||||
import vpsdk.stdio as stdio
|
||||
import string
|
||||
import viperlib
|
||||
from stdint import *
|
||||
import t, c
|
||||
|
||||
@c.Attribute(t.attr.section(".text.startup"), t.attr.aligned(16))
|
||||
def _start() -> int | t.CExport:
|
||||
root: vpui.Tk = vpui.Tk()
|
||||
root.title("Terminal")
|
||||
root.set_style(window.STYLE_WIN7)
|
||||
root.geometry(80, 30, 640, 480)
|
||||
root.bg_color = uint32(0x0C0C0C)
|
||||
master: vpui.Tk | t.CPtr = c.Addr(root)
|
||||
|
||||
def _sdbg(msg: str):
|
||||
_syscall._syscall1(uint64(18), uint64(msg))
|
||||
|
||||
_sdbg("[term] start\n")
|
||||
|
||||
_cwd: t.CArray[t.CChar, 64]
|
||||
_cwd[0] = 47
|
||||
for i in range(1, 64):
|
||||
_cwd[i] = 0
|
||||
|
||||
sbar: vpui.Scrollbar = vpui.Scrollbar(master, 16, 446, vpui.VERTICAL)
|
||||
root.pack(0, vpui.PACK_RIGHT, vpui.FILL_Y, 0, 0, 0)
|
||||
|
||||
term: vpui.Text = vpui.Text(master, 624, 446)
|
||||
root.pack(1, vpui.PACK_LEFT, vpui.FILL_BOTH, 1, 0, 0)
|
||||
term.insert("ViperOS Terminal v1.1")
|
||||
term.insert("Type 'help' for commands.")
|
||||
term.insert("")
|
||||
|
||||
term.yscrollbar = t.CType(sbar, vpui.Widget, t.CPtr)
|
||||
|
||||
def _on_scroll():
|
||||
act: int = sbar.action
|
||||
if act == 1:
|
||||
term.scroll_offset -= 1
|
||||
elif act == 2:
|
||||
term.scroll_offset += 1
|
||||
elif act == 3:
|
||||
vis: int = term._visible_lines()
|
||||
term.scroll_offset -= vis
|
||||
elif act == 4:
|
||||
vis2: int = term._visible_lines()
|
||||
term.scroll_offset += vis2
|
||||
elif act == 5:
|
||||
aval: int = sbar.action_value
|
||||
if term.line_count > 0:
|
||||
term.scroll_offset = aval * term.line_count / 1000
|
||||
vis3: int = term._visible_lines()
|
||||
max_off: int = term.line_count - vis3
|
||||
if max_off < 0: max_off = 0
|
||||
if term.scroll_offset < 0: term.scroll_offset = 0
|
||||
if term.scroll_offset > max_off: term.scroll_offset = max_off
|
||||
term._update_scrollbar()
|
||||
|
||||
sbar.command = c.Addr(_on_scroll)
|
||||
|
||||
def _startswith(s: str, prefix: str) -> int:
|
||||
plen: t.CSizeT = string.strlen(prefix)
|
||||
if string.strncmp(s, prefix, plen) == 0:
|
||||
return 1
|
||||
return 0
|
||||
|
||||
def _build_path(out: str, out_size: int, rel: str):
|
||||
if c.Deref(rel) == 47:
|
||||
string.strncpy(out, rel, out_size - 1)
|
||||
else:
|
||||
i: int = 0
|
||||
for i in range(63):
|
||||
ch: t.CChar = _cwd[i]
|
||||
c.DerefAs(out + i, ch)
|
||||
if ch == 0: break
|
||||
cwd_len: int = i
|
||||
if cwd_len > 0 and _cwd[cwd_len - 1] != 47:
|
||||
c.DerefAs(out + cwd_len, t.CChar(47))
|
||||
cwd_len += 1
|
||||
j: int = 0
|
||||
for j in range(out_size - 1 - cwd_len):
|
||||
ch2: t.CChar = c.Deref(rel + j)
|
||||
c.DerefAs(out + cwd_len + j, ch2)
|
||||
if ch2 == 0: break
|
||||
c.DerefAs(out + out_size - 1, t.CChar(0))
|
||||
|
||||
def _print_dir_entry(name: str, is_dir: int):
|
||||
buf: t.CArray[t.CChar, 80]
|
||||
j: int = 0
|
||||
for j in range(78):
|
||||
ch: t.CChar = c.Deref(name + j)
|
||||
buf[j] = ch
|
||||
if ch == 0: break
|
||||
if is_dir and j < 78:
|
||||
buf[j] = 47
|
||||
j += 1
|
||||
buf[j] = 0
|
||||
term.insert_ptr(c.Addr(buf[0]))
|
||||
|
||||
def _cmd_cd(path: str):
|
||||
if path is None or c.Deref(path) == 0:
|
||||
_cwd[0] = 47
|
||||
for i in range(1, 64):
|
||||
_cwd[i] = 0
|
||||
return
|
||||
full: t.CArray[t.CChar, 256]
|
||||
_build_path(c.Addr(full[0]), 256, path)
|
||||
dd: int = fs.opendir(c.Addr(full[0]))
|
||||
if dd < 0:
|
||||
term.insert("Error: dir not found")
|
||||
return
|
||||
fs.closedir(dd)
|
||||
string.strncpy(c.Addr(_cwd[0]), c.Addr(full[0]), 63)
|
||||
_cwd[63] = 0
|
||||
|
||||
def _cmd_ls():
|
||||
dd: int = fs.opendir(c.Addr(_cwd[0]))
|
||||
if dd < 0:
|
||||
term.insert("Error: cannot open dir")
|
||||
return
|
||||
info: t.CArray[t.CChar, 320]
|
||||
string.memset(c.Addr(info[0]), 0, 320)
|
||||
while True:
|
||||
result: int = fs.readdir(dd, c.Addr(info[0]))
|
||||
if result != 0: break
|
||||
attr_val: uint8 = uint8(c.Deref(c.Addr(info[4])))
|
||||
name_off: int = 16
|
||||
name_ptr: str = c.Addr(info[name_off])
|
||||
if c.Deref(name_ptr) == 0: break
|
||||
if c.Deref(name_ptr) == 46:
|
||||
if c.Deref(name_ptr + 1) == 0:
|
||||
string.memset(c.Addr(info[0]), 0, 320)
|
||||
continue
|
||||
if c.Deref(name_ptr + 1) == 46 and c.Deref(name_ptr + 2) == 0:
|
||||
string.memset(c.Addr(info[0]), 0, 320)
|
||||
continue
|
||||
if (attr_val & 0x10) != 0:
|
||||
_print_dir_entry(name_ptr, 1)
|
||||
else:
|
||||
_print_dir_entry(name_ptr, 0)
|
||||
string.memset(c.Addr(info[0]), 0, 320)
|
||||
fs.closedir(dd)
|
||||
|
||||
def _cmd_cat(path: str):
|
||||
full: t.CArray[t.CChar, 256]
|
||||
_build_path(c.Addr(full[0]), 256, path)
|
||||
fd: int = fs.open(c.Addr(full[0]), fs.O_RDONLY)
|
||||
if fd < 0:
|
||||
term.insert("Error: file not found")
|
||||
return
|
||||
buf: t.CArray[t.CChar, 80]
|
||||
while True:
|
||||
string.memset(c.Addr(buf[0]), 0, 80)
|
||||
n: int = fs.read(fd, c.Addr(buf[0]), 78)
|
||||
if n <= 0: break
|
||||
if n > 78: n = 78
|
||||
buf[n] = 0
|
||||
term.insert_ptr(c.Addr(buf[0]))
|
||||
fs.close(fd)
|
||||
|
||||
def _cmd_mkdir(path: str):
|
||||
full: t.CArray[t.CChar, 256]
|
||||
_build_path(c.Addr(full[0]), 256, path)
|
||||
result: int = fs.mkdir(c.Addr(full[0]))
|
||||
if result < 0:
|
||||
term.insert("Error: mkdir failed")
|
||||
else:
|
||||
term.insert("Directory created")
|
||||
|
||||
def _cmd_rm(path: str):
|
||||
full: t.CArray[t.CChar, 256]
|
||||
_build_path(c.Addr(full[0]), 256, path)
|
||||
result: int = fs.remove(c.Addr(full[0]))
|
||||
if result < 0:
|
||||
term.insert("Error: remove failed")
|
||||
else:
|
||||
term.insert("Removed")
|
||||
|
||||
def _cmd_touch(path: str):
|
||||
full: t.CArray[t.CChar, 256]
|
||||
_build_path(c.Addr(full[0]), 256, path)
|
||||
fd: int = fs.open(c.Addr(full[0]), fs.O_WRONLY | fs.O_CREAT)
|
||||
if fd < 0:
|
||||
term.insert("Error: touch failed")
|
||||
return
|
||||
fs.close(fd)
|
||||
term.insert("File created")
|
||||
|
||||
def _cmd_sysinfo():
|
||||
term.insert("ViperOS v1.0 (x86_64)")
|
||||
term.insert("Framebuffer: 32bpp")
|
||||
term.insert("Compiler: TransPyC")
|
||||
|
||||
def _cmd_hexdump(path: str):
|
||||
full: t.CArray[t.CChar, 256]
|
||||
_build_path(c.Addr(full[0]), 256, path)
|
||||
fd: int = fs.open(c.Addr(full[0]), fs.O_RDONLY)
|
||||
if fd < 0:
|
||||
term.insert("Error: file not found")
|
||||
return
|
||||
offset: int = 0
|
||||
buf: t.CArray[t.CChar, 16]
|
||||
while True:
|
||||
string.memset(c.Addr(buf[0]), 0, 16)
|
||||
n: int = fs.read(fd, c.Addr(buf[0]), 16)
|
||||
if n <= 0: break
|
||||
if n > 16: n = 16
|
||||
line: t.CArray[t.CChar, 80]
|
||||
string.memset(c.Addr(line[0]), 0, 80)
|
||||
viperlib.snprintf(c.Addr(line[0]), 80, "%08x: ", offset)
|
||||
pos: int = 10
|
||||
j: int = 0
|
||||
for j in range(16):
|
||||
if j < n:
|
||||
ub: uint32 = uint32(buf[j]) & 0xFF
|
||||
hi: int = int(ub >> 4)
|
||||
lo: int = int(ub & 0xF)
|
||||
if hi < 10:
|
||||
line[pos] = t.CChar(48 + hi)
|
||||
else:
|
||||
line[pos] = t.CChar(65 + hi - 10)
|
||||
pos += 1
|
||||
if lo < 10:
|
||||
line[pos] = t.CChar(48 + lo)
|
||||
else:
|
||||
line[pos] = t.CChar(65 + lo - 10)
|
||||
pos += 1
|
||||
else:
|
||||
line[pos] = 32
|
||||
pos += 1
|
||||
line[pos] = 32
|
||||
pos += 1
|
||||
line[pos] = 32
|
||||
pos += 1
|
||||
if j == 7:
|
||||
line[pos] = 32
|
||||
pos += 1
|
||||
line[pos] = 124
|
||||
pos += 1
|
||||
for j in range(n):
|
||||
b2: uint32 = uint32(buf[j]) & 0xFF
|
||||
if b2 >= 32 and b2 < 127:
|
||||
line[pos] = t.CChar(b2)
|
||||
else:
|
||||
line[pos] = 46
|
||||
pos += 1
|
||||
line[pos] = 0
|
||||
term.insert_ptr(c.Addr(line[0]))
|
||||
offset += n
|
||||
fs.close(fd)
|
||||
|
||||
def _cmd_run(path: str, blocking: int):
|
||||
full: t.CArray[t.CChar, 256]
|
||||
_build_path(c.Addr(full[0]), 256, path)
|
||||
pid: int = process.spawn(c.Addr(full[0]), blocking)
|
||||
if pid < 0:
|
||||
term.insert("Error: cannot spawn")
|
||||
elif blocking:
|
||||
term.insert("Process exited")
|
||||
else:
|
||||
msg: t.CArray[t.CChar, 32]
|
||||
viperlib.snprintf(c.Addr(msg[0]), 32, "Spawned pid=%d", pid)
|
||||
term.insert_ptr(c.Addr(msg[0]))
|
||||
|
||||
def _on_command() -> int:
|
||||
_sdbg("[cmd] enter\n")
|
||||
text: str = term.get()
|
||||
_sdbg("[cmd] text=")
|
||||
_sdbg(text)
|
||||
_sdbg("\n")
|
||||
if _startswith(text, "echo "):
|
||||
term.insert_ptr(text + 5)
|
||||
elif string.samestr(text, "echo"):
|
||||
pass
|
||||
elif string.samestr(text, "clear"):
|
||||
term.delete(0, -1)
|
||||
elif string.samestr(text, "help"):
|
||||
term.insert("File: ls cd cat pwd mkdir rm touch")
|
||||
term.insert("Sys: ver about sysinfo reboot")
|
||||
term.insert("Util: echo clear help hexdump run runb")
|
||||
elif string.samestr(text, "ver"):
|
||||
term.insert("ViperOS Terminal v1.1")
|
||||
elif string.samestr(text, "about"):
|
||||
term.insert("ViperOS - A tiny OS in Viper lang")
|
||||
elif string.samestr(text, "pwd"):
|
||||
term.insert_ptr(c.Addr(_cwd[0]))
|
||||
elif string.samestr(text, "ls"):
|
||||
_cmd_ls()
|
||||
elif string.samestr(text, "cd"):
|
||||
_cmd_cd("")
|
||||
elif _startswith(text, "cd "):
|
||||
_cmd_cd(text + 3)
|
||||
elif _startswith(text, "cat "):
|
||||
_cmd_cat(text + 4)
|
||||
elif _startswith(text, "mkdir "):
|
||||
_cmd_mkdir(text + 6)
|
||||
elif _startswith(text, "rm "):
|
||||
_cmd_rm(text + 3)
|
||||
elif _startswith(text, "touch "):
|
||||
_cmd_touch(text + 6)
|
||||
elif string.samestr(text, "sysinfo"):
|
||||
_cmd_sysinfo()
|
||||
elif string.samestr(text, "reboot"):
|
||||
process.exit(0)
|
||||
elif _startswith(text, "hexdump "):
|
||||
_cmd_hexdump(text + 8)
|
||||
elif _startswith(text, "run "):
|
||||
_cmd_run(text + 4, 0)
|
||||
elif _startswith(text, "runb "):
|
||||
_cmd_run(text + 5, 1)
|
||||
else:
|
||||
if text is not None and c.Deref(text) != 0:
|
||||
term.insert("Unknown command. Type 'help'.")
|
||||
return 0
|
||||
|
||||
term.on_command = c.Addr(_on_command)
|
||||
|
||||
root.mainloop()
|
||||
process.exit(0)
|
||||
return 0
|
||||
@@ -1,12 +1,12 @@
|
||||
import vpsdk.syscall as syscall
|
||||
import t, c
|
||||
|
||||
def log_info(msg: t.CConst | t.CChar | t.CPtr) -> t.CVoid | t.CExport:
|
||||
syscall._syscall1(t.CUInt64T(syscall.SERIAL_PUTS), t.CUInt64T("[SerialLogger] "))
|
||||
syscall._syscall1(t.CUInt64T(syscall.SERIAL_PUTS), t.CUInt64T(msg))
|
||||
syscall._syscall1(t.CUInt64T(syscall.SERIAL_PUTS), t.CUInt64T("\n"))
|
||||
|
||||
def log_warn(msg: t.CConst | t.CChar | t.CPtr) -> t.CVoid | t.CExport:
|
||||
syscall._syscall1(t.CUInt64T(syscall.SERIAL_PUTS), t.CUInt64T("[SerialLogger:WARN] "))
|
||||
syscall._syscall1(t.CUInt64T(syscall.SERIAL_PUTS), t.CUInt64T(msg))
|
||||
syscall._syscall1(t.CUInt64T(syscall.SERIAL_PUTS), t.CUInt64T("\n"))
|
||||
import vpsdk.syscall as syscall
|
||||
import t, c
|
||||
|
||||
def log_info(msg: t.CConst | t.CChar | t.CPtr) -> t.CVoid | t.CExport:
|
||||
syscall._syscall1(uint64(syscall.SERIAL_PUTS), uint64("[SerialLogger] "))
|
||||
syscall._syscall1(uint64(syscall.SERIAL_PUTS), uint64(msg))
|
||||
syscall._syscall1(uint64(syscall.SERIAL_PUTS), uint64("\n"))
|
||||
|
||||
def log_warn(msg: t.CConst | t.CChar | t.CPtr) -> t.CVoid | t.CExport:
|
||||
syscall._syscall1(uint64(syscall.SERIAL_PUTS), uint64("[SerialLogger:WARN] "))
|
||||
syscall._syscall1(uint64(syscall.SERIAL_PUTS), uint64(msg))
|
||||
syscall._syscall1(uint64(syscall.SERIAL_PUTS), uint64("\n"))
|
||||
+80
-80
@@ -1,80 +1,80 @@
|
||||
import t
|
||||
import vpsdk.syscall as syscall
|
||||
|
||||
UINT32PTR: t.CTypedef = t.CUInt32T | t.CPtr
|
||||
|
||||
def color_rgb(r: t.CUInt8T, g: t.CUInt8T, b: t.CUInt8T) -> t.CUInt32T:
|
||||
return t.CUInt32T(r) | (t.CUInt32T(g) << 8) | (t.CUInt32T(b) << 16)
|
||||
|
||||
def get_winbuf(win_id: t.CInt) -> UINT32PTR:
|
||||
return t.CVoid(syscall._syscall2(t.CUInt64T(syscall.GET_WINBUF), t.CUInt64T(win_id), 0), t.CPtr)
|
||||
|
||||
def win_flush(win_id: t.CInt) -> t.CVoid:
|
||||
syscall._syscall2(t.CUInt64T(syscall.WIN_FLUSH), t.CUInt64T(win_id), 0)
|
||||
|
||||
def draw_pixel(buf: UINT32PTR, bw: t.CInt, x: t.CInt, y: t.CInt, color: t.CUInt32T) -> t.CVoid | t.CExport:
|
||||
if x < 0 or y < 0: return
|
||||
buf[y * bw + x] = color
|
||||
|
||||
def draw_line(buf: UINT32PTR, bw: t.CInt, x0: t.CInt, y0: t.CInt, x1: t.CInt, y1: t.CInt, color: t.CUInt32T) -> t.CVoid | t.CExport:
|
||||
dx: t.CInt = x1 - x0
|
||||
dy: t.CInt = y1 - y0
|
||||
sx: t.CInt = 1
|
||||
sy: t.CInt = 1
|
||||
if dx < 0:
|
||||
dx = -dx
|
||||
sx = -1
|
||||
if dy < 0:
|
||||
dy = -dy
|
||||
sy = -1
|
||||
err: t.CInt = dx - dy
|
||||
while True:
|
||||
if x0 >= 0 and y0 >= 0:
|
||||
buf[y0 * bw + x0] = color
|
||||
if x0 == x1 and y0 == y1:
|
||||
break
|
||||
e2: t.CInt = 2 * err
|
||||
if e2 > -dy:
|
||||
err -= dy
|
||||
x0 += sx
|
||||
if e2 < dx:
|
||||
err += dx
|
||||
y0 += sy
|
||||
|
||||
def draw_rect(buf: UINT32PTR, bw: t.CInt, rx: t.CInt, ry: t.CInt, rw: t.CInt, rh: t.CInt, color: t.CUInt32T) -> t.CVoid | t.CExport:
|
||||
draw_line(buf, bw, rx, ry, rx + rw - 1, ry, color)
|
||||
draw_line(buf, bw, rx + rw - 1, ry, rx + rw - 1, ry + rh - 1, color)
|
||||
draw_line(buf, bw, rx + rw - 1, ry + rh - 1, rx, ry + rh - 1, color)
|
||||
draw_line(buf, bw, rx, ry + rh - 1, rx, ry, color)
|
||||
|
||||
def fill_rect(buf: UINT32PTR, bw: t.CInt, rx: t.CInt, ry: t.CInt, rw: t.CInt, rh: t.CInt, color: t.CUInt32T) -> t.CVoid | t.CExport:
|
||||
if rx < 0: rw += rx; rx = 0
|
||||
if ry < 0: rh += ry; ry = 0
|
||||
if rw <= 0 or rh <= 0: return
|
||||
py: t.CInt = ry
|
||||
while py < ry + rh:
|
||||
px: t.CInt = rx
|
||||
while px < rx + rw:
|
||||
buf[py * bw + px] = color
|
||||
px += 1
|
||||
py += 1
|
||||
|
||||
def draw_circle(buf: UINT32PTR, bw: t.CInt, cx: t.CInt, cy: t.CInt, r: t.CInt, color: t.CUInt32T) -> t.CVoid | t.CExport:
|
||||
x: t.CInt = r
|
||||
y: t.CInt = 0
|
||||
d: t.CInt = 1 - r
|
||||
while x >= y:
|
||||
if cx + x >= 0: buf[(cy + y) * bw + cx + x] = color
|
||||
if cx + y >= 0: buf[(cy + x) * bw + cx + y] = color
|
||||
if cx - y >= 0: buf[(cy + x) * bw + cx - y] = color
|
||||
if cx - x >= 0: buf[(cy + y) * bw + cx - x] = color
|
||||
if cx - x >= 0: buf[(cy - y) * bw + cx - x] = color
|
||||
if cx - y >= 0: buf[(cy - x) * bw + cx - y] = color
|
||||
if cx + y >= 0: buf[(cy - x) * bw + cx + y] = color
|
||||
if cx + x >= 0: buf[(cy - y) * bw + cx + x] = color
|
||||
y += 1
|
||||
if d <= 0:
|
||||
d += 2 * y + 1
|
||||
else:
|
||||
x -= 1
|
||||
d += 2 * (y - x) + 1
|
||||
import t
|
||||
import vpsdk.syscall as syscall
|
||||
|
||||
UINT32PTR: t.CTypedef = uint32 | t.CPtr
|
||||
|
||||
def color_rgb(r: uint8, g: uint8, b: uint8) -> uint32:
|
||||
return uint32(r) | (uint32(g) << 8) | (uint32(b) << 16)
|
||||
|
||||
def get_winbuf(win_id: int) -> UINT32PTR:
|
||||
return t.CVoid(syscall._syscall2(uint64(syscall.GET_WINBUF), uint64(win_id), 0), t.CPtr)
|
||||
|
||||
def win_flush(win_id: int) -> t.CVoid:
|
||||
syscall._syscall2(uint64(syscall.WIN_FLUSH), uint64(win_id), 0)
|
||||
|
||||
def draw_pixel(buf: UINT32PTR, bw: int, x: int, y: int, color: uint32) -> t.CVoid | t.CExport:
|
||||
if x < 0 or y < 0: return
|
||||
buf[y * bw + x] = color
|
||||
|
||||
def draw_line(buf: UINT32PTR, bw: int, x0: int, y0: int, x1: int, y1: int, color: uint32) -> t.CVoid | t.CExport:
|
||||
dx: int = x1 - x0
|
||||
dy: int = y1 - y0
|
||||
sx: int = 1
|
||||
sy: int = 1
|
||||
if dx < 0:
|
||||
dx = -dx
|
||||
sx = -1
|
||||
if dy < 0:
|
||||
dy = -dy
|
||||
sy = -1
|
||||
err: int = dx - dy
|
||||
while True:
|
||||
if x0 >= 0 and y0 >= 0:
|
||||
buf[y0 * bw + x0] = color
|
||||
if x0 == x1 and y0 == y1:
|
||||
break
|
||||
e2: int = 2 * err
|
||||
if e2 > -dy:
|
||||
err -= dy
|
||||
x0 += sx
|
||||
if e2 < dx:
|
||||
err += dx
|
||||
y0 += sy
|
||||
|
||||
def draw_rect(buf: UINT32PTR, bw: int, rx: int, ry: int, rw: int, rh: int, color: uint32) -> t.CVoid | t.CExport:
|
||||
draw_line(buf, bw, rx, ry, rx + rw - 1, ry, color)
|
||||
draw_line(buf, bw, rx + rw - 1, ry, rx + rw - 1, ry + rh - 1, color)
|
||||
draw_line(buf, bw, rx + rw - 1, ry + rh - 1, rx, ry + rh - 1, color)
|
||||
draw_line(buf, bw, rx, ry + rh - 1, rx, ry, color)
|
||||
|
||||
def fill_rect(buf: UINT32PTR, bw: int, rx: int, ry: int, rw: int, rh: int, color: uint32) -> t.CVoid | t.CExport:
|
||||
if rx < 0: rw += rx; rx = 0
|
||||
if ry < 0: rh += ry; ry = 0
|
||||
if rw <= 0 or rh <= 0: return
|
||||
py: int = ry
|
||||
while py < ry + rh:
|
||||
px: int = rx
|
||||
while px < rx + rw:
|
||||
buf[py * bw + px] = color
|
||||
px += 1
|
||||
py += 1
|
||||
|
||||
def draw_circle(buf: UINT32PTR, bw: int, cx: int, cy: int, r: int, color: uint32) -> t.CVoid | t.CExport:
|
||||
x: int = r
|
||||
y: int = 0
|
||||
d: int = 1 - r
|
||||
while x >= y:
|
||||
if cx + x >= 0: buf[(cy + y) * bw + cx + x] = color
|
||||
if cx + y >= 0: buf[(cy + x) * bw + cx + y] = color
|
||||
if cx - y >= 0: buf[(cy + x) * bw + cx - y] = color
|
||||
if cx - x >= 0: buf[(cy + y) * bw + cx - x] = color
|
||||
if cx - x >= 0: buf[(cy - y) * bw + cx - x] = color
|
||||
if cx - y >= 0: buf[(cy - x) * bw + cx - y] = color
|
||||
if cx + y >= 0: buf[(cy - x) * bw + cx + y] = color
|
||||
if cx + x >= 0: buf[(cy - y) * bw + cx + x] = color
|
||||
y += 1
|
||||
if d <= 0:
|
||||
d += 2 * y + 1
|
||||
else:
|
||||
x -= 1
|
||||
d += 2 * (y - x) + 1
|
||||
+11
-11
@@ -1,17 +1,17 @@
|
||||
import t, c
|
||||
|
||||
|
||||
MEMORY_TYPE_AVAILABLE: t.CUInt64T = 7
|
||||
MEMORY_TYPE_RESERVED: t.CUInt64T = 0
|
||||
MEMORY_TYPE_LOADER_CODE: t.CUInt64T = 1
|
||||
MEMORY_TYPE_LOADER_DATA: t.CUInt64T = 2
|
||||
MEMORY_TYPE_BOOT_SERVICES_CODE: t.CUInt64T = 3
|
||||
MEMORY_TYPE_BOOT_SERVICES_DATA: t.CUInt64T = 4
|
||||
MEMORY_TYPE_RUNTIME_SERVICES_CODE: t.CUInt64T = 5
|
||||
MEMORY_TYPE_RUNTIME_SERVICES_DATA: t.CUInt64T = 6
|
||||
MEMORY_TYPE_ACPI_RECLAIMABLE: t.CUInt64T = 9
|
||||
MEMORY_TYPE_ACPI_NVS: t.CUInt64T = 10
|
||||
MEMORY_TYPE_BAD_MEMORY: t.CUInt64T = 8
|
||||
MEMORY_TYPE_AVAILABLE: uint64 = 7
|
||||
MEMORY_TYPE_RESERVED: uint64 = 0
|
||||
MEMORY_TYPE_LOADER_CODE: uint64 = 1
|
||||
MEMORY_TYPE_LOADER_DATA: uint64 = 2
|
||||
MEMORY_TYPE_BOOT_SERVICES_CODE: uint64 = 3
|
||||
MEMORY_TYPE_BOOT_SERVICES_DATA: uint64 = 4
|
||||
MEMORY_TYPE_RUNTIME_SERVICES_CODE: uint64 = 5
|
||||
MEMORY_TYPE_RUNTIME_SERVICES_DATA: uint64 = 6
|
||||
MEMORY_TYPE_ACPI_RECLAIMABLE: uint64 = 9
|
||||
MEMORY_TYPE_ACPI_NVS: uint64 = 10
|
||||
MEMORY_TYPE_BAD_MEMORY: uint64 = 8
|
||||
|
||||
@c.Attribute(t.attr.packed)
|
||||
class memory_map_entry:
|
||||
|
||||
@@ -1,257 +1,261 @@
|
||||
import asm
|
||||
import intr.gdt as gdt
|
||||
import intr.idt as idt
|
||||
import drivers.serial.uart.serial as serial
|
||||
import drivers.core.cpu.cpu as cpu
|
||||
import mm.mm as mm
|
||||
import platform.pch.timer as timer
|
||||
import viperlib
|
||||
import t, c
|
||||
|
||||
|
||||
IA32_APIC_BASE: t.CDefine = 0x1B
|
||||
APIC_BASE_MSR_ENABLE: t.CDefine = 0x800
|
||||
APIC_BASE_ADDR_MASK: t.CDefine = 0xFFFFF000
|
||||
|
||||
LAPIC_ID: t.CDefine = 0x020
|
||||
LAPIC_VERSION: t.CDefine = 0x030
|
||||
LAPIC_TPR: t.CDefine = 0x080
|
||||
LAPIC_EOI: t.CDefine = 0x0B0
|
||||
LAPIC_LDR: t.CDefine = 0x0D0
|
||||
LAPIC_SVR: t.CDefine = 0x0F0
|
||||
LAPIC_ISR0: t.CDefine = 0x100
|
||||
LAPIC_ICR_LOW: t.CDefine = 0x300
|
||||
LAPIC_ICR_HIGH: t.CDefine = 0x310
|
||||
LAPIC_LVT_TIMER: t.CDefine = 0x320
|
||||
LAPIC_LVT_LINT0: t.CDefine = 0x350
|
||||
LAPIC_LVT_LINT1: t.CDefine = 0x360
|
||||
LAPIC_LVT_ERROR: t.CDefine = 0x370
|
||||
LAPIC_TIMER_INIT: t.CDefine = 0x380
|
||||
LAPIC_TIMER_CURRENT: t.CDefine = 0x390
|
||||
LAPIC_TIMER_DIVIDE: t.CDefine = 0x3E0
|
||||
|
||||
LAPIC_SVR_ENABLE: t.CDefine = 0x100
|
||||
LAPIC_LVT_MASKED: t.CDefine = 0x10000
|
||||
LAPIC_LVT_DELIVERY_EXTINT: t.CDefine = 0x700
|
||||
LAPIC_LVT_DELIVERY_NMI: t.CDefine = 0x400
|
||||
LAPIC_LVT_TIMER_PERIODIC: t.CDefine = 0x20000
|
||||
|
||||
LAPIC_ICR_INIT: t.CDefine = 0x500
|
||||
LAPIC_ICR_STARTUP: t.CDefine = 0x600
|
||||
LAPIC_ICR_ASSERT: t.CDefine = 0x4000
|
||||
LAPIC_ICR_DEASSERT: t.CDefine = 0x8000
|
||||
LAPIC_ICR_LEVEL: t.CDefine = 0x8000
|
||||
|
||||
MAX_CPUS: t.CDefine = 8
|
||||
import asm
|
||||
import intr.gdt as gdt
|
||||
import intr.idt as idt
|
||||
import drivers.serial.uart.serial as serial
|
||||
import drivers.core.cpu.cpu as cpu
|
||||
import mm.mm as mm
|
||||
import platform.pch.timer as timer
|
||||
import viperlib
|
||||
import t, c
|
||||
|
||||
|
||||
IA32_APIC_BASE: t.CDefine = 0x1B
|
||||
APIC_BASE_MSR_ENABLE: t.CDefine = 0x800
|
||||
APIC_BASE_ADDR_MASK: t.CDefine = 0xFFFFF000
|
||||
|
||||
LAPIC_ID: t.CDefine = 0x020
|
||||
LAPIC_VERSION: t.CDefine = 0x030
|
||||
LAPIC_TPR: t.CDefine = 0x080
|
||||
LAPIC_EOI: t.CDefine = 0x0B0
|
||||
LAPIC_LDR: t.CDefine = 0x0D0
|
||||
LAPIC_SVR: t.CDefine = 0x0F0
|
||||
LAPIC_ISR0: t.CDefine = 0x100
|
||||
LAPIC_ICR_LOW: t.CDefine = 0x300
|
||||
LAPIC_ICR_HIGH: t.CDefine = 0x310
|
||||
LAPIC_LVT_TIMER: t.CDefine = 0x320
|
||||
LAPIC_LVT_LINT0: t.CDefine = 0x350
|
||||
LAPIC_LVT_LINT1: t.CDefine = 0x360
|
||||
LAPIC_LVT_ERROR: t.CDefine = 0x370
|
||||
LAPIC_TIMER_INIT: t.CDefine = 0x380
|
||||
LAPIC_TIMER_CURRENT: t.CDefine = 0x390
|
||||
LAPIC_TIMER_DIVIDE: t.CDefine = 0x3E0
|
||||
|
||||
LAPIC_SVR_ENABLE: t.CDefine = 0x100
|
||||
LAPIC_LVT_MASKED: t.CDefine = 0x10000
|
||||
LAPIC_LVT_DELIVERY_EXTINT: t.CDefine = 0x700
|
||||
LAPIC_LVT_DELIVERY_NMI: t.CDefine = 0x400
|
||||
LAPIC_LVT_TIMER_PERIODIC: t.CDefine = 0x20000
|
||||
|
||||
LAPIC_ICR_INIT: t.CDefine = 0x500
|
||||
LAPIC_ICR_STARTUP: t.CDefine = 0x600
|
||||
LAPIC_ICR_ASSERT: t.CDefine = 0x4000
|
||||
LAPIC_ICR_DEASSERT: t.CDefine = 0x8000
|
||||
LAPIC_ICR_LEVEL: t.CDefine = 0x8000
|
||||
|
||||
MAX_CPUS: t.CDefine = 8
|
||||
AP_TRAMPOLINE_ADDR: t.CDefine = 0x7000
|
||||
|
||||
_lapic_base: t.CUInt64T = 0
|
||||
_cpu_count: t.CUInt32T = 1
|
||||
_bsp_lapic_id: t.CUInt32T = 0
|
||||
_ap_ready: t.CUInt32T = 0
|
||||
|
||||
def read(offset: t.CUInt32T) -> t.CUInt32T:
|
||||
addr: t.CUInt64T = _lapic_base + t.CUInt64T(offset)
|
||||
return c.Deref(t.CUInt32T(addr, t.CPtr))
|
||||
|
||||
def write(offset: t.CUInt32T, value: t.CUInt32T):
|
||||
addr: t.CUInt64T = _lapic_base + t.CUInt64T(offset)
|
||||
c.Set(c.Deref(t.CUInt32T(addr, t.CPtr)), value)
|
||||
|
||||
def eoi():
|
||||
write(LAPIC_EOI, 0)
|
||||
|
||||
def get_id() -> t.CUInt32T:
|
||||
return read(LAPIC_ID) >> 24
|
||||
|
||||
@c.Attribute(t.attr.noinline)
|
||||
def init():
|
||||
global _lapic_base, _bsp_lapic_id
|
||||
msr_val: t.CUInt64T = cpu.msr_read(IA32_APIC_BASE)
|
||||
_lapic_base = msr_val & APIC_BASE_ADDR_MASK
|
||||
cpu.msr_write(IA32_APIC_BASE, msr_val | APIC_BASE_MSR_ENABLE)
|
||||
_bsp_lapic_id = read(LAPIC_ID) >> 24
|
||||
write(LAPIC_SVR, LAPIC_SVR_ENABLE | 0xFF)
|
||||
write(LAPIC_TPR, 0)
|
||||
write(LAPIC_LVT_TIMER, LAPIC_LVT_MASKED)
|
||||
write(LAPIC_LVT_LINT0, LAPIC_LVT_DELIVERY_EXTINT)
|
||||
write(LAPIC_LVT_LINT1, LAPIC_LVT_DELIVERY_NMI)
|
||||
write(LAPIC_LVT_ERROR, LAPIC_LVT_MASKED)
|
||||
write(LAPIC_TIMER_DIVIDE, 0x0B)
|
||||
write(LAPIC_LDR, 0x01000000)
|
||||
eoi()
|
||||
|
||||
@c.Attribute(t.attr.noinline)
|
||||
def detect_cpu_count() -> t.CUInt32T:
|
||||
res: cpu.cpuid_result
|
||||
cpu.cpuid(0, c.Addr(res))
|
||||
max_leaf: t.CUInt32T = res.eax
|
||||
|
||||
if max_leaf >= 0x0B:
|
||||
cpu.cpuid_sub(0x0B, 0, c.Addr(res))
|
||||
num_threads: t.CUInt32T = res.ebx & 0xFFFF
|
||||
if num_threads > 0 and num_threads <= MAX_CPUS:
|
||||
return num_threads
|
||||
|
||||
cpu.cpuid(1, c.Addr(res))
|
||||
if res.edx & cpu.CPU_FEATURE_HTT:
|
||||
count: t.CUInt32T = (res.ebx >> 16) & 0xFF
|
||||
if count > 0 and count <= MAX_CPUS:
|
||||
return count
|
||||
return 1
|
||||
|
||||
def _wait_icr():
|
||||
timeout: t.CUInt32T = 1000000
|
||||
while timeout > 0:
|
||||
val: t.CUInt32T = read(LAPIC_ICR_LOW)
|
||||
if (val & (1 << 12)) == 0:
|
||||
return
|
||||
timeout -= 1
|
||||
|
||||
def _send_ipi(apic_id: t.CUInt32T, vector: t.CUInt32T, delivery_mode: t.CUInt32T):
|
||||
_wait_icr()
|
||||
write(LAPIC_ICR_HIGH, apic_id << 24)
|
||||
write(LAPIC_ICR_LOW, vector | delivery_mode | LAPIC_ICR_LEVEL | LAPIC_ICR_ASSERT)
|
||||
_wait_icr()
|
||||
|
||||
def ap_entry():
|
||||
global _ap_ready
|
||||
my_id: t.CUInt32T = get_id()
|
||||
buf: t.CArray[t.CChar, 64]
|
||||
viperlib.snprintf(c.Addr(buf), 64, "[AP] core %u started (lapic=%u)\n", my_id, my_id)
|
||||
serial.puts(buf)
|
||||
_ap_ready = 1
|
||||
while True:
|
||||
asm.sti()
|
||||
asm.hlt()
|
||||
|
||||
_trampoline_bin: t.CArray[t.CUInt8T, 128] = [
|
||||
0xFA, # cli
|
||||
0x31, 0xC0, # xor ax, ax
|
||||
0x8E, 0xD8, # mov ds, ax
|
||||
0x8E, 0xC0, # mov es, ax
|
||||
0x0F, 0x01, 0x16, 0x00, 0x7E, # lgdt [0x7E00]
|
||||
0x0F, 0x20, 0xC0, # mov eax, cr0
|
||||
0x83, 0xC8, 0x01, # or eax, 1
|
||||
0x0F, 0x22, 0xC0, # mov cr0, eax
|
||||
0xEA, 0x1A, 0x07, 0x00, 0x00, 0x08, 0x00, # jmp 0x08:0x701A
|
||||
|
||||
# 32-bit 保护模式开始
|
||||
0xB8, 0x10, 0x00, 0x00, 0x00, # mov ax, 0x10
|
||||
0x8E, 0xD8, # mov ds, ax
|
||||
0x8E, 0xC0, # mov es, ax
|
||||
0x8E, 0xE0, # mov fs, ax
|
||||
0x8E, 0xE8, # mov gs, ax
|
||||
0x8E, 0xD0, # mov ss, ax
|
||||
0x0F, 0x20, 0xE0, # mov eax, cr4
|
||||
0x83, 0xC8, 0x20, # or eax, 0x20 (PAE)
|
||||
0x0F, 0x22, 0xE0, # mov cr4, eax
|
||||
0x8B, 0x04, 0x25, 0x00, 0x7F, 0x00, 0x00, # mov eax, [0x7F00]
|
||||
0x0F, 0x22, 0xD8, # mov cr3, eax
|
||||
0xB9, 0x80, 0x00, 0x00, 0xC0, # mov ecx, 0xC0000080 (EFER)
|
||||
0x0F, 0x32, # rdmsr
|
||||
0x83, 0xC8, 0x00, 0x01, 0x00, 0x00, # or eax, 0x100 (LME)
|
||||
0x0F, 0x79, # wrmsr
|
||||
0x0F, 0x20, 0xC0, # mov eax, cr0
|
||||
0x0D, 0x00, 0x00, 0x00, 0x80, # or eax, 0x80000000 (PG)
|
||||
0x0F, 0x22, 0xC0, # mov cr0, eax
|
||||
0xEA, 0x5A, 0x07, 0x00, 0x00, 0x08, 0x00, # jmp 0x08:0x705A
|
||||
|
||||
# 64-bit 长模式开始
|
||||
0x48, 0x8B, 0x24, 0x25, 0x08, 0x7F, 0x00, 0x00, # mov rsp, [0x7F08]
|
||||
0x0F, 0x01, 0x16, 0x10, 0x7F, # lgdt [0x7F10]
|
||||
0x0F, 0x01, 0x1E, 0x20, 0x7F, # lidt [0x7F20]
|
||||
0xB8, 0x10, 0x00, 0x00, 0x00, # mov ax, 0x10
|
||||
0x8E, 0xD8, # mov ds, ax
|
||||
0x8E, 0xC0, # mov es, ax
|
||||
0x8E, 0xE0, # mov fs, ax
|
||||
0x8E, 0xE8, # mov gs, ax
|
||||
0x8E, 0xD0, # mov ss, ax
|
||||
0x48, 0x8B, 0x04, 0x25, 0x28, 0x7F, 0x00, 0x00, # mov rax, [0x7F28]
|
||||
0xFF, 0xE0 # jmp rax
|
||||
]
|
||||
|
||||
def _setup_trampoline(entry_addr: t.CUInt64T, stack_addr: t.CUInt64T, cr3_val: t.CUInt64T):
|
||||
dest: t.CUInt8T | t.CPtr = t.CUInt8T(AP_TRAMPOLINE_ADDR, t.CPtr)
|
||||
src: t.CUInt8T | t.CPtr = c.Addr(_trampoline_bin)
|
||||
i: t.CInt
|
||||
for i in range(128):
|
||||
c.Set(c.Deref(dest + t.CUInt64T(i)), c.Deref(src + t.CUInt64T(i)))
|
||||
|
||||
gdt_ptr_addr: t.CUInt64T = AP_TRAMPOLINE_ADDR + 0x0E00
|
||||
c.Set(c.Deref(t.CUInt16T(gdt_ptr_addr, t.CPtr)), t.CUInt16T(23))
|
||||
c.Set(c.Deref(t.CUInt64T(gdt_ptr_addr + 2, t.CPtr)), t.CUInt64T(AP_TRAMPOLINE_ADDR + 0x0E10))
|
||||
|
||||
gdt_addr: t.CUInt64T = AP_TRAMPOLINE_ADDR + 0x0E10
|
||||
c.Set(c.Deref(t.CUInt64T(gdt_addr, t.CPtr)), t.CUInt64T(0))
|
||||
c.Set(c.Deref(t.CUInt64T(gdt_addr + 8, t.CPtr)), t.CUInt64T(0x00AF9A000000FFFF))
|
||||
c.Set(c.Deref(t.CUInt64T(gdt_addr + 16, t.CPtr)), t.CUInt64T(0x00CF92000000FFFF))
|
||||
|
||||
c.Set(c.Deref(t.CUInt32T(AP_TRAMPOLINE_ADDR + 0x0F00, t.CPtr)), t.CUInt32T(cr3_val))
|
||||
c.Set(c.Deref(t.CUInt64T(AP_TRAMPOLINE_ADDR + 0x0F08, t.CPtr)), stack_addr)
|
||||
|
||||
gp_addr: t.CUInt64T = t.CUInt64T(c.Addr(gdt.gp))
|
||||
gdt_base: t.CUInt64T = c.Deref(t.CUInt64T(gp_addr + 2, t.CPtr))
|
||||
gdt_limit: t.CUInt16T = c.Deref(t.CUInt16T(gp_addr, t.CPtr))
|
||||
c.Set(c.Deref(t.CUInt16T(AP_TRAMPOLINE_ADDR + 0x0F10, t.CPtr)), gdt_limit)
|
||||
c.Set(c.Deref(t.CUInt64T(AP_TRAMPOLINE_ADDR + 0x0F12, t.CPtr)), gdt_base)
|
||||
|
||||
idt_addr: t.CUInt64T = t.CUInt64T(c.Addr(idt.idt))
|
||||
idt_base: t.CUInt64T = c.Deref(t.CUInt64T(idt_addr + 2, t.CPtr))
|
||||
idt_limit: t.CUInt16T = c.Deref(t.CUInt16T(idt_addr, t.CPtr))
|
||||
c.Set(c.Deref(t.CUInt16T(AP_TRAMPOLINE_ADDR + 0x0F20, t.CPtr)), idt_limit)
|
||||
c.Set(c.Deref(t.CUInt64T(AP_TRAMPOLINE_ADDR + 0x0F22, t.CPtr)), idt_base)
|
||||
|
||||
c.Set(c.Deref(t.CUInt64T(AP_TRAMPOLINE_ADDR + 0x0F28, t.CPtr)), entry_addr)
|
||||
|
||||
def start_aps():
|
||||
global _cpu_count, _ap_ready
|
||||
if _cpu_count <= 1: return
|
||||
|
||||
cr3_val: t.CUInt64T = 0
|
||||
c.Asm(f"""mov rax, cr3
|
||||
mov {c.AsmOut(cr3_val, t.ASM_DESCR.OUTPUT_REG)}, rax""",
|
||||
[t.ASM_DESCR.CLOBBER_RAX])
|
||||
|
||||
stack_size: t.CUInt64T = 8192
|
||||
i: t.CUInt32T
|
||||
for i in range(1, _cpu_count):
|
||||
_ap_ready = 0
|
||||
stack: t.CVoid | t.CPtr = mm.malloc(stack_size)
|
||||
if stack is None: continue
|
||||
stack_top: t.CUInt64T = t.CUInt64T(stack) + stack_size
|
||||
stack_top = stack_top & ~t.CUInt64T(15)
|
||||
|
||||
_setup_trampoline(t.CUInt64T(ap_entry), stack_top, cr3_val)
|
||||
|
||||
_send_ipi(i, 0, LAPIC_ICR_INIT)
|
||||
timer.timer_msleep(10)
|
||||
_send_ipi(i, (AP_TRAMPOLINE_ADDR >> 12) & 0xFF, LAPIC_ICR_STARTUP)
|
||||
timer.timer_msleep(1)
|
||||
_send_ipi(i, (AP_TRAMPOLINE_ADDR >> 12) & 0xFF, LAPIC_ICR_STARTUP)
|
||||
|
||||
wait: t.CUInt32T = 0
|
||||
while _ap_ready == 0 and wait < 5000:
|
||||
timer.timer_msleep(1)
|
||||
wait += 1
|
||||
|
||||
def early_init():
|
||||
global _cpu_count, _bsp_lapic_id
|
||||
# 直接以 IA32_APIC_BASE 的 EN 位(bit 11)判断 APIC 是否可用:
|
||||
# QEMU/OVMF 必启用,且 msr_read 路径已在前置流程验证可用;
|
||||
# 比依赖 cpuid 特性位更可靠(避免 cpuid 包装被误判时静默跳过 init)。
|
||||
msr_val: t.CUInt64T = cpu.msr_read(IA32_APIC_BASE)
|
||||
if msr_val & APIC_BASE_MSR_ENABLE:
|
||||
init()
|
||||
_cpu_count = detect_cpu_count()
|
||||
else:
|
||||
_cpu_count = 1
|
||||
|
||||
def get_cpu_count() -> t.CUInt32T:
|
||||
return _cpu_count
|
||||
|
||||
def get_base() -> t.CUInt64T:
|
||||
return _lapic_base
|
||||
|
||||
def get_lapic_id() -> t.CUInt32T:
|
||||
return get_id()
|
||||
# trampoline 机器码字节数(与下方 _trampoline_bin 初始化列表元素数一致)
|
||||
AP_TRAMPOLINE_LEN: t.CDefine = 138
|
||||
|
||||
_lapic_base: uint64 = 0
|
||||
_cpu_count: uint32 = 1
|
||||
_bsp_lapic_id: uint32 = 0
|
||||
_ap_ready: uint32 = 0
|
||||
|
||||
def read(offset: uint32) -> uint32:
|
||||
addr: uint64 = _lapic_base + uint64(offset)
|
||||
return c.Deref(uint32(addr, t.CPtr))
|
||||
|
||||
def write(offset: uint32, value: uint32):
|
||||
addr: uint64 = _lapic_base + uint64(offset)
|
||||
c.Set(c.Deref(uint32(addr, t.CPtr)), value)
|
||||
|
||||
def eoi():
|
||||
write(LAPIC_EOI, 0)
|
||||
|
||||
def get_id() -> uint32:
|
||||
return read(LAPIC_ID) >> 24
|
||||
|
||||
@c.Attribute(t.attr.noinline)
|
||||
def init():
|
||||
global _lapic_base, _bsp_lapic_id
|
||||
msr_val: uint64 = cpu.msr_read(IA32_APIC_BASE)
|
||||
_lapic_base = msr_val & APIC_BASE_ADDR_MASK
|
||||
cpu.msr_write(IA32_APIC_BASE, msr_val | APIC_BASE_MSR_ENABLE)
|
||||
_bsp_lapic_id = read(LAPIC_ID) >> 24
|
||||
write(LAPIC_SVR, LAPIC_SVR_ENABLE | 0xFF)
|
||||
write(LAPIC_TPR, 0)
|
||||
write(LAPIC_LVT_TIMER, LAPIC_LVT_MASKED)
|
||||
write(LAPIC_LVT_LINT0, LAPIC_LVT_DELIVERY_EXTINT)
|
||||
write(LAPIC_LVT_LINT1, LAPIC_LVT_DELIVERY_NMI)
|
||||
write(LAPIC_LVT_ERROR, LAPIC_LVT_MASKED)
|
||||
write(LAPIC_TIMER_DIVIDE, 0x0B)
|
||||
write(LAPIC_LDR, 0x01000000)
|
||||
eoi()
|
||||
|
||||
@c.Attribute(t.attr.noinline)
|
||||
def detect_cpu_count() -> uint32:
|
||||
res: cpu.cpuid_result
|
||||
cpu.cpuid(0, c.Addr(res))
|
||||
max_leaf: uint32 = res.eax
|
||||
|
||||
if max_leaf >= 0x0B:
|
||||
cpu.cpuid_sub(0x0B, 0, c.Addr(res))
|
||||
num_threads: uint32 = res.ebx & 0xFFFF
|
||||
if num_threads > 0 and num_threads <= MAX_CPUS:
|
||||
return num_threads
|
||||
|
||||
cpu.cpuid(1, c.Addr(res))
|
||||
if res.edx & cpu.CPU_FEATURE_HTT:
|
||||
count: uint32 = (res.ebx >> 16) & 0xFF
|
||||
if count > 0 and count <= MAX_CPUS:
|
||||
return count
|
||||
return 1
|
||||
|
||||
def _wait_icr():
|
||||
timeout: uint32 = 1000000
|
||||
while timeout > 0:
|
||||
val: uint32 = read(LAPIC_ICR_LOW)
|
||||
if (val & (1 << 12)) == 0:
|
||||
return
|
||||
timeout -= 1
|
||||
|
||||
def _send_ipi(apic_id: uint32, vector: uint32, delivery_mode: uint32):
|
||||
_wait_icr()
|
||||
write(LAPIC_ICR_HIGH, apic_id << 24)
|
||||
write(LAPIC_ICR_LOW, vector | delivery_mode | LAPIC_ICR_LEVEL | LAPIC_ICR_ASSERT)
|
||||
_wait_icr()
|
||||
|
||||
def ap_entry():
|
||||
global _ap_ready
|
||||
my_id: uint32 = get_id()
|
||||
buf: t.CArray[t.CChar, 64]
|
||||
viperlib.snprintf(c.Addr(buf), 64, "[AP] core %u started (lapic=%u)\n", my_id, my_id)
|
||||
serial.puts(buf)
|
||||
_ap_ready = 1
|
||||
while True:
|
||||
asm.sti()
|
||||
asm.hlt()
|
||||
|
||||
_trampoline_bin: t.CArray[uint8, AP_TRAMPOLINE_LEN] = [
|
||||
0xFA, # cli
|
||||
0x31, 0xC0, # xor ax, ax
|
||||
0x8E, 0xD8, # mov ds, ax
|
||||
0x8E, 0xC0, # mov es, ax
|
||||
0x0F, 0x01, 0x16, 0x00, 0x7E, # lgdt [0x7E00]
|
||||
0x0F, 0x20, 0xC0, # mov eax, cr0
|
||||
0x83, 0xC8, 0x01, # or eax, 1
|
||||
0x0F, 0x22, 0xC0, # mov cr0, eax
|
||||
0xEA, 0x1A, 0x07, 0x00, 0x00, 0x08, 0x00, # jmp 0x08:0x701A
|
||||
|
||||
# 32-bit 保护模式开始
|
||||
0xB8, 0x10, 0x00, 0x00, 0x00, # mov ax, 0x10
|
||||
0x8E, 0xD8, # mov ds, ax
|
||||
0x8E, 0xC0, # mov es, ax
|
||||
0x8E, 0xE0, # mov fs, ax
|
||||
0x8E, 0xE8, # mov gs, ax
|
||||
0x8E, 0xD0, # mov ss, ax
|
||||
0x0F, 0x20, 0xE0, # mov eax, cr4
|
||||
0x83, 0xC8, 0x20, # or eax, 0x20 (PAE)
|
||||
0x0F, 0x22, 0xE0, # mov cr4, eax
|
||||
0x8B, 0x04, 0x25, 0x00, 0x7F, 0x00, 0x00, # mov eax, [0x7F00]
|
||||
0x0F, 0x22, 0xD8, # mov cr3, eax
|
||||
0xB9, 0x80, 0x00, 0x00, 0xC0, # mov ecx, 0xC0000080 (EFER)
|
||||
0x0F, 0x32, # rdmsr
|
||||
0x83, 0xC8, 0x00, 0x01, 0x00, 0x00, # or eax, 0x100 (LME)
|
||||
0x0F, 0x79, # wrmsr
|
||||
0x0F, 0x20, 0xC0, # mov eax, cr0
|
||||
0x0D, 0x00, 0x00, 0x00, 0x80, # or eax, 0x80000000 (PG)
|
||||
0x0F, 0x22, 0xC0, # mov cr0, eax
|
||||
0xEA, 0x5A, 0x07, 0x00, 0x00, 0x08, 0x00, # jmp 0x08:0x705A
|
||||
|
||||
# 64-bit 长模式开始
|
||||
0x48, 0x8B, 0x24, 0x25, 0x08, 0x7F, 0x00, 0x00, # mov rsp, [0x7F08]
|
||||
0x0F, 0x01, 0x16, 0x10, 0x7F, # lgdt [0x7F10]
|
||||
0x0F, 0x01, 0x1E, 0x20, 0x7F, # lidt [0x7F20]
|
||||
0xB8, 0x10, 0x00, 0x00, 0x00, # mov ax, 0x10
|
||||
0x8E, 0xD8, # mov ds, ax
|
||||
0x8E, 0xC0, # mov es, ax
|
||||
0x8E, 0xE0, # mov fs, ax
|
||||
0x8E, 0xE8, # mov gs, ax
|
||||
0x8E, 0xD0, # mov ss, ax
|
||||
0x48, 0x8B, 0x04, 0x25, 0x30, 0x7F, 0x00, 0x00, # mov rax, [0x7F30]
|
||||
0xFF, 0xE0 # jmp rax
|
||||
]
|
||||
|
||||
def _setup_trampoline(entry_addr: uint64, stack_addr: uint64, cr3_val: uint64):
|
||||
dest: uint8 | t.CPtr = uint8(AP_TRAMPOLINE_ADDR, t.CPtr)
|
||||
src: uint8 | t.CPtr = c.Addr(_trampoline_bin)
|
||||
i: int
|
||||
for i in range(AP_TRAMPOLINE_LEN):
|
||||
c.Set(c.Deref(dest + uint64(i)), c.Deref(src + uint64(i)))
|
||||
|
||||
gdt_ptr_addr: uint64 = AP_TRAMPOLINE_ADDR + 0x0E00
|
||||
c.Set(c.Deref(uint16(gdt_ptr_addr, t.CPtr)), uint16(23))
|
||||
c.Set(c.Deref(uint64(gdt_ptr_addr + 2, t.CPtr)), uint64(AP_TRAMPOLINE_ADDR + 0x0E10))
|
||||
|
||||
gdt_addr: uint64 = AP_TRAMPOLINE_ADDR + 0x0E10
|
||||
c.Set(c.Deref(uint64(gdt_addr, t.CPtr)), uint64(0))
|
||||
c.Set(c.Deref(uint64(gdt_addr + 8, t.CPtr)), uint64(0x00AF9A000000FFFF))
|
||||
c.Set(c.Deref(uint64(gdt_addr + 16, t.CPtr)), uint64(0x00CF92000000FFFF))
|
||||
|
||||
c.Set(c.Deref(uint32(AP_TRAMPOLINE_ADDR + 0x0F00, t.CPtr)), uint32(cr3_val))
|
||||
c.Set(c.Deref(uint64(AP_TRAMPOLINE_ADDR + 0x0F08, t.CPtr)), stack_addr)
|
||||
|
||||
gp_addr: uint64 = uint64(c.Addr(gdt.gp))
|
||||
gdt_base: uint64 = c.Deref(uint64(gp_addr + 2, t.CPtr))
|
||||
gdt_limit: uint16 = c.Deref(uint16(gp_addr, t.CPtr))
|
||||
c.Set(c.Deref(uint16(AP_TRAMPOLINE_ADDR + 0x0F10, t.CPtr)), gdt_limit)
|
||||
c.Set(c.Deref(uint64(AP_TRAMPOLINE_ADDR + 0x0F12, t.CPtr)), gdt_base)
|
||||
|
||||
idt_addr: uint64 = uint64(c.Addr(idt.idt))
|
||||
idt_base: uint64 = c.Deref(uint64(idt_addr + 2, t.CPtr))
|
||||
idt_limit: uint16 = c.Deref(uint16(idt_addr, t.CPtr))
|
||||
c.Set(c.Deref(uint16(AP_TRAMPOLINE_ADDR + 0x0F20, t.CPtr)), idt_limit)
|
||||
c.Set(c.Deref(uint64(AP_TRAMPOLINE_ADDR + 0x0F22, t.CPtr)), idt_base)
|
||||
|
||||
# entry 槽位后移到 0x0F30:idt 伪描述符占 0x0F20..0x0F29(limit 2 + base 8),
|
||||
# 原来 entry 放 0x0F28 会与其 base 尾部 2 字节重叠 → lidt 读到被覆盖的基址。
|
||||
c.Set(c.Deref(uint64(AP_TRAMPOLINE_ADDR + 0x0F30, t.CPtr)), entry_addr)
|
||||
|
||||
def start_aps():
|
||||
global _cpu_count, _ap_ready
|
||||
if _cpu_count <= 1: return
|
||||
|
||||
cr3_val: uint64 = 0
|
||||
c.Asm(f"""mov rax, cr3
|
||||
mov {c.AsmOut(cr3_val, t.ASM_DESCR.OUTPUT_REG)}, rax""",
|
||||
[t.ASM_DESCR.CLOBBER_RAX])
|
||||
|
||||
stack_size: uint64 = 8192
|
||||
i: uint32
|
||||
for i in range(1, _cpu_count):
|
||||
_ap_ready = 0
|
||||
stack: t.CPtr = mm.malloc(stack_size)
|
||||
if stack is None: continue
|
||||
stack_top: uint64 = uint64(stack) + stack_size
|
||||
stack_top = stack_top & ~uint64(15)
|
||||
|
||||
_setup_trampoline(uint64(ap_entry), stack_top, cr3_val)
|
||||
|
||||
_send_ipi(i, 0, LAPIC_ICR_INIT)
|
||||
timer.timer_msleep(10)
|
||||
_send_ipi(i, (AP_TRAMPOLINE_ADDR >> 12) & 0xFF, LAPIC_ICR_STARTUP)
|
||||
timer.timer_msleep(1)
|
||||
_send_ipi(i, (AP_TRAMPOLINE_ADDR >> 12) & 0xFF, LAPIC_ICR_STARTUP)
|
||||
|
||||
wait: uint32 = 0
|
||||
while _ap_ready == 0 and wait < 5000:
|
||||
timer.timer_msleep(1)
|
||||
wait += 1
|
||||
|
||||
def early_init():
|
||||
global _cpu_count, _bsp_lapic_id
|
||||
# 直接以 IA32_APIC_BASE 的 EN 位(bit 11)判断 APIC 是否可用:
|
||||
# QEMU/OVMF 必启用,且 msr_read 路径已在前置流程验证可用;
|
||||
# 比依赖 cpuid 特性位更可靠(避免 cpuid 包装被误判时静默跳过 init)。
|
||||
msr_val: uint64 = cpu.msr_read(IA32_APIC_BASE)
|
||||
if msr_val & APIC_BASE_MSR_ENABLE:
|
||||
init()
|
||||
_cpu_count = detect_cpu_count()
|
||||
else:
|
||||
_cpu_count = 1
|
||||
|
||||
def get_cpu_count() -> uint32:
|
||||
return _cpu_count
|
||||
|
||||
def get_base() -> uint64:
|
||||
return _lapic_base
|
||||
|
||||
def get_lapic_id() -> uint32:
|
||||
return get_id()
|
||||
@@ -38,38 +38,38 @@ CPU_FEATURE_PBE: t.CDefine = (1 << 25)
|
||||
class cpu_info(t.CStruct):
|
||||
vendor_id: t.CArray[t.CChar, 13]
|
||||
brand_string: t.CArray[t.CChar, 48]
|
||||
features: t.CUInt32T
|
||||
family: t.CUInt32T
|
||||
model: t.CUInt32T
|
||||
stepping: t.CUInt32T
|
||||
cpu_type: t.CUInt32T
|
||||
ext_model: t.CUInt32T
|
||||
ext_family: t.CUInt32T
|
||||
cpu_freq: t.CUInt64T
|
||||
features: uint32
|
||||
family: uint32
|
||||
model: uint32
|
||||
stepping: uint32
|
||||
cpu_type: uint32
|
||||
ext_model: uint32
|
||||
ext_family: uint32
|
||||
cpu_freq: uint64
|
||||
|
||||
@c.Attribute(t.attr.packed)
|
||||
class _tss:
|
||||
reserved0: t.CUInt64T
|
||||
rsp0: t.CUInt64T
|
||||
rsp1: t.CUInt64T
|
||||
rsp2: t.CUInt64T
|
||||
reserved1: t.CUInt64T
|
||||
ist1: t.CUInt64T
|
||||
ist2: t.CUInt64T
|
||||
ist3: t.CUInt64T
|
||||
ist4: t.CUInt64T
|
||||
ist5: t.CUInt64T
|
||||
ist6: t.CUInt64T
|
||||
ist7: t.CUInt64T
|
||||
reserved2: t.CUInt64T
|
||||
reserved3: t.CUInt16T
|
||||
io_map_base: t.CUInt16T
|
||||
reserved0: uint64
|
||||
rsp0: uint64
|
||||
rsp1: uint64
|
||||
rsp2: uint64
|
||||
reserved1: uint64
|
||||
ist1: uint64
|
||||
ist2: uint64
|
||||
ist3: uint64
|
||||
ist4: uint64
|
||||
ist5: uint64
|
||||
ist6: uint64
|
||||
ist7: uint64
|
||||
reserved2: uint64
|
||||
reserved3: uint16
|
||||
io_map_base: uint16
|
||||
|
||||
class cpuid_result(t.CStruct):
|
||||
eax: t.CUInt32T
|
||||
ebx: t.CUInt32T
|
||||
ecx: t.CUInt32T
|
||||
edx: t.CUInt32T
|
||||
eax: uint32
|
||||
ebx: uint32
|
||||
ecx: uint32
|
||||
edx: uint32
|
||||
|
||||
@c.Attribute(t.attr.naked)
|
||||
def _rdmsr_naked():
|
||||
@@ -91,17 +91,17 @@ def _wrmsr_naked():
|
||||
ret""",
|
||||
op=[t.ASM_DESCR.CLOBBER_RAX, t.ASM_DESCR.CLOBBER_RDX])
|
||||
|
||||
def msr_read(msr: t.CUInt32T) -> t.CUInt64T:
|
||||
result: t.CUInt64T = 0
|
||||
func: t.CVoid | t.CPtr = _rdmsr_naked
|
||||
def msr_read(msr: uint32) -> uint64:
|
||||
result: uint64 = 0
|
||||
func: t.CPtr = _rdmsr_naked
|
||||
c.Asm(f"""mov ecx, {c.AsmInp(msr, t.ASM_DESCR.REG_ANY)}
|
||||
call {c.AsmInp(func, t.ASM_DESCR.REG_ANY)}
|
||||
mov {c.AsmOut(result, t.ASM_DESCR.OUTPUT_REG)}, rax""",
|
||||
op=[t.ASM_DESCR.CLOBBER_RAX, t.ASM_DESCR.CLOBBER_RCX, t.ASM_DESCR.CLOBBER_RDX])
|
||||
return result
|
||||
|
||||
def msr_write(msr: t.CUInt32T, value: t.CUInt64T):
|
||||
func: t.CVoid | t.CPtr = _wrmsr_naked
|
||||
def msr_write(msr: uint32, value: uint64):
|
||||
func: t.CPtr = _wrmsr_naked
|
||||
c.Asm(f"""mov ecx, {c.AsmInp(msr, t.ASM_DESCR.REG_ANY)}
|
||||
mov r8, {c.AsmInp(value, t.ASM_DESCR.REG_ANY)}
|
||||
call {c.AsmInp(func, t.ASM_DESCR.REG_ANY)}""",
|
||||
@@ -137,8 +137,8 @@ def _cpuid_sub_naked():
|
||||
t.ASM_DESCR.CLOBBER_RDX])
|
||||
|
||||
@c.Attribute(t.attr.noinline)
|
||||
def cpuid(leaf: t.CUInt32T, out: cpuid_result | t.CPtr):
|
||||
func: t.CVoid | t.CPtr = _cpuid_naked
|
||||
def cpuid(leaf: uint32, out: cpuid_result | t.CPtr):
|
||||
func: t.CPtr = _cpuid_naked
|
||||
c.Asm(f"""mov ecx, {c.AsmInp(leaf, t.ASM_DESCR.REG_ANY)}
|
||||
mov rdx, {c.AsmInp(out, t.ASM_DESCR.REG_ANY)}
|
||||
call {c.AsmInp(func, t.ASM_DESCR.REG_ANY)}""",
|
||||
@@ -148,8 +148,8 @@ def cpuid(leaf: t.CUInt32T, out: cpuid_result | t.CPtr):
|
||||
t.ASM_DESCR.CLOBBER_R11])
|
||||
|
||||
@c.Attribute(t.attr.noinline)
|
||||
def cpuid_sub(leaf: t.CUInt32T, sub: t.CUInt32T, out: cpuid_result | t.CPtr):
|
||||
func: t.CVoid | t.CPtr = _cpuid_sub_naked
|
||||
def cpuid_sub(leaf: uint32, sub: uint32, out: cpuid_result | t.CPtr):
|
||||
func: t.CPtr = _cpuid_sub_naked
|
||||
c.Asm(f"""mov ecx, {c.AsmInp(leaf, t.ASM_DESCR.REG_ANY)}
|
||||
mov r8d, {c.AsmInp(sub, t.ASM_DESCR.REG_ANY)}
|
||||
mov rdx, {c.AsmInp(out, t.ASM_DESCR.REG_ANY)}
|
||||
@@ -160,8 +160,8 @@ def cpuid_sub(leaf: t.CUInt32T, sub: t.CUInt32T, out: cpuid_result | t.CPtr):
|
||||
t.ASM_DESCR.CLOBBER_R11])
|
||||
|
||||
@c.Attribute(t.attr.noinline)
|
||||
def detect_features_static() -> t.CUInt32T:
|
||||
features: t.CUInt32T = 0
|
||||
def detect_features_static() -> uint32:
|
||||
features: uint32 = 0
|
||||
res: cpuid_result
|
||||
cpuid(1, c.Addr(res))
|
||||
if res.edx & (1 << 0): features |= CPU_FEATURE_FPU
|
||||
@@ -194,18 +194,18 @@ def detect_features_static() -> t.CUInt32T:
|
||||
|
||||
@c.Attribute(t.attr.packed)
|
||||
class per_cpu_data:
|
||||
user_rsp: t.CUInt64T
|
||||
kernel_rsp0: t.CUInt64T
|
||||
current_pid: t.CInt
|
||||
_pad0: t.CUInt32T
|
||||
_pad1: t.CUInt64T
|
||||
user_rsp: uint64
|
||||
kernel_rsp0: uint64
|
||||
current_pid: int
|
||||
_pad0: uint32
|
||||
_pad1: uint64
|
||||
|
||||
_per_cpu: per_cpu_data
|
||||
|
||||
@t.Object
|
||||
class _CPUObject:
|
||||
tss: _tss
|
||||
features: t.CUInt32T
|
||||
features: uint32
|
||||
def __init__(self):
|
||||
self.__init_tss__()
|
||||
|
||||
@@ -214,21 +214,21 @@ class _CPUObject:
|
||||
string.memset(c.Addr(self.tss), 0, self.tss.__sizeof__())
|
||||
self.tss.io_map_base = self.tss.__sizeof__()
|
||||
string.memset(c.Addr(_per_cpu), 0, per_cpu_data.__sizeof__())
|
||||
gdt.setTSS64(5, t.CUInt64T(c.Addr(self.tss)), self.tss.__sizeof__() - 1)
|
||||
gdt.setTSS64(5, uint64(c.Addr(self.tss)), self.tss.__sizeof__() - 1)
|
||||
gdt.flush()
|
||||
# IA32_KERNEL_GS_BASE holds the per_cpu address for swapgs.
|
||||
# When entering from Ring 3, swapgs swaps IA32_GS_BASE (0) with
|
||||
# IA32_KERNEL_GS_BASE (_per_cpu), making gs: accessible in kernel.
|
||||
# When returning to Ring 3, swapgs swaps back, restoring GS base to 0.
|
||||
msr_write(IA32_KERNEL_GS_BASE, t.CUInt64T(c.Addr(_per_cpu)))
|
||||
msr_write(IA32_KERNEL_GS_BASE, uint64(c.Addr(_per_cpu)))
|
||||
|
||||
def getInfo(self, info: cpu_info | t.CPtr):
|
||||
if not info: return
|
||||
res: cpuid_result
|
||||
cpuid(0, c.Addr(res))
|
||||
(t.CUInt32T(info.vendor_id, t.CPtr))[0] = res.ebx
|
||||
(t.CUInt32T(info.vendor_id, t.CPtr))[1] = res.edx
|
||||
(t.CUInt32T(info.vendor_id, t.CPtr))[2] = res.ecx
|
||||
(uint32(info.vendor_id, t.CPtr))[0] = res.ebx
|
||||
(uint32(info.vendor_id, t.CPtr))[1] = res.edx
|
||||
(uint32(info.vendor_id, t.CPtr))[2] = res.ecx
|
||||
info.vendor_id[12] = '\0'
|
||||
info.features = self.detectFeatures()
|
||||
cpuid(1, c.Addr(res))
|
||||
@@ -238,18 +238,23 @@ class _CPUObject:
|
||||
info.cpu_type = (res.eax >> 12) & 0x03
|
||||
info.ext_model = (res.eax >> 16) & 0x0F
|
||||
info.ext_family = (res.eax >> 20) & 0xFF
|
||||
for i in range(4):
|
||||
# CPUID 品牌串:0x80000002..0x80000004 共 3 个叶 × 16 字节 = 48,
|
||||
# 与 brand_string[48] 等长(此前 range(4) 会写 64 字节 → 越界 16 字节)。
|
||||
# 逐 u32 按字节地址显式写入,避免 uint32|t.CPtr 被降级为 i8* 后
|
||||
# 下标按字节偏移且被截断为 i8(只写低字节、偏移不乘 4)。
|
||||
brand_addr: uint64 = uint64(uint32(info.brand_string, t.CPtr))
|
||||
for i in range(3):
|
||||
cpuid(0x80000002 + i, c.Addr(res))
|
||||
base: t.CUInt32T | t.CPtr = t.CUInt32T(info.brand_string, t.CPtr)
|
||||
base[i * 4 + 0] = res.eax
|
||||
base[i * 4 + 1] = res.ebx
|
||||
base[i * 4 + 2] = res.ecx
|
||||
base[i * 4 + 3] = res.edx
|
||||
off_b: uint64 = uint64(i) * 16
|
||||
c.Set(c.Deref(uint32(brand_addr + off_b, t.CPtr)), res.eax)
|
||||
c.Set(c.Deref(uint32(brand_addr + off_b + 4, t.CPtr)), res.ebx)
|
||||
c.Set(c.Deref(uint32(brand_addr + off_b + 8, t.CPtr)), res.ecx)
|
||||
c.Set(c.Deref(uint32(brand_addr + off_b + 12, t.CPtr)), res.edx)
|
||||
info.brand_string[47] = '\0'
|
||||
info.cpu_freq = 2000000000
|
||||
|
||||
def detectFeatures(self) -> t.CUInt32T:
|
||||
features: t.CInt32T = 0
|
||||
def detectFeatures(self) -> uint32:
|
||||
features: int32 = 0
|
||||
res: cpuid_result
|
||||
cpuid(1, c.Addr(res))
|
||||
if res.edx & (1 << 0): features |= CPU_FEATURE_FPU
|
||||
@@ -287,61 +292,61 @@ class _CPUObject:
|
||||
c.Asm("cli", [t.ASM_DESCR.CLOBBER_MEMORY])
|
||||
|
||||
def enableNmis(self):
|
||||
current: t.CUInt8T = asm.inb(0x70)
|
||||
current: uint8 = asm.inb(0x70)
|
||||
asm.outb(0x70, current & 0x7F)
|
||||
|
||||
def disableNmis(self):
|
||||
current: t.CUInt8T = asm.inb(0x70)
|
||||
current: uint8 = asm.inb(0x70)
|
||||
asm.outb(0x70, current | 0x80)
|
||||
|
||||
def readCR0(self) -> t.CUInt64T:
|
||||
cr0: t.CUInt64T
|
||||
def readCR0(self) -> uint64:
|
||||
cr0: uint64
|
||||
c.Asm(f"""mov rax, cr0
|
||||
mov {c.AsmOut(cr0, t.ASM_DESCR.OUTPUT_REG)}, rax""",
|
||||
[t.ASM_DESCR.CLOBBER_RAX])
|
||||
return cr0
|
||||
|
||||
def writeCR0(self, value: t.CUInt64T):
|
||||
def writeCR0(self, value: uint64):
|
||||
c.Asm(f"""mov rax, {c.AsmInp(value, t.ASM_DESCR.REG_ANY)}
|
||||
mov cr0, rax""",
|
||||
[t.ASM_DESCR.CLOBBER_RAX])
|
||||
|
||||
def readCR3(self) -> t.CUInt64T:
|
||||
cr3: t.CUInt64T
|
||||
def readCR3(self) -> uint64:
|
||||
cr3: uint64
|
||||
c.Asm(f"""mov rax, cr3
|
||||
mov {c.AsmOut(cr3, t.ASM_DESCR.OUTPUT_REG)}, rax""",
|
||||
[t.ASM_DESCR.CLOBBER_RAX])
|
||||
return cr3
|
||||
|
||||
def writeCR3(self, value: t.CUInt64T):
|
||||
def writeCR3(self, value: uint64):
|
||||
c.Asm(f"""mov rax, {c.AsmInp(value, t.ASM_DESCR.REG_ANY)}
|
||||
mov cr3, rax""",
|
||||
[t.ASM_DESCR.CLOBBER_RAX])
|
||||
|
||||
def readCR4(self) -> t.CUInt64T:
|
||||
cr4: t.CUInt64T
|
||||
def readCR4(self) -> uint64:
|
||||
cr4: uint64
|
||||
c.Asm(f"""mov rax, cr4
|
||||
mov {c.AsmOut(cr4, t.ASM_DESCR.OUTPUT_REG)}, rax""",
|
||||
[t.ASM_DESCR.CLOBBER_RAX])
|
||||
return cr4
|
||||
|
||||
def writeCR4(self, value: t.CUInt64T):
|
||||
def writeCR4(self, value: uint64):
|
||||
c.Asm(f"""mov rax, {c.AsmInp(value, t.ASM_DESCR.REG_ANY)}
|
||||
mov cr4, rax""",
|
||||
[t.ASM_DESCR.CLOBBER_RAX])
|
||||
|
||||
def readMSR(self, msr: t.CUInt32T) -> t.CUInt64T:
|
||||
def readMSR(self, msr: uint32) -> uint64:
|
||||
return msr_read(msr)
|
||||
|
||||
def writeMSR(self, msr: t.CUInt32T, value: t.CUInt64T):
|
||||
def writeMSR(self, msr: uint32, value: uint64):
|
||||
msr_write(msr, value)
|
||||
|
||||
def setTSSRSP0(self, rsp0: t.CUInt64T):
|
||||
def setTSSRSP0(self, rsp0: uint64):
|
||||
global _per_cpu
|
||||
self.tss.rsp0 = rsp0
|
||||
_per_cpu.kernel_rsp0 = rsp0
|
||||
|
||||
def set_kernel_rsp0(rsp0: t.CUInt64T):
|
||||
def set_kernel_rsp0(rsp0: uint64):
|
||||
global _per_cpu
|
||||
_per_cpu.kernel_rsp0 = rsp0
|
||||
|
||||
@@ -349,20 +354,20 @@ def set_kernel_rsp0(rsp0: t.CUInt64T):
|
||||
# OVMF/UEFI 启动后 CR4.OSFXSR 未置位,任何 movaps 都 #GP(err=0)——变参函数
|
||||
# 传 float/double 时保存 xmm 寄存器触发(serial.printf / snprintf("%.2f") 崩溃根因)。
|
||||
def enable_sse():
|
||||
cr0_v: t.CUInt64T = 0
|
||||
cr0_v: uint64 = 0
|
||||
c.Asm(f"""mov rax, cr0
|
||||
mov {c.AsmOut(cr0_v, t.ASM_DESCR.OUTPUT_REG)}, rax""",
|
||||
op=[t.ASM_DESCR.CLOBBER_RAX])
|
||||
cr0_v = cr0_v & ~t.CUInt64T(4) # 清 EM(禁止 FPU 仿真)
|
||||
cr0_v = cr0_v | t.CUInt64T(2) # 置 MP(监控协处理器)
|
||||
cr0_v = cr0_v & ~uint64(4) # 清 EM(禁止 FPU 仿真)
|
||||
cr0_v = cr0_v | uint64(2) # 置 MP(监控协处理器)
|
||||
c.Asm(f"""mov rax, {c.AsmInp(cr0_v, t.ASM_DESCR.REG_ANY)}
|
||||
mov cr0, rax""",
|
||||
op=[t.ASM_DESCR.CLOBBER_RAX])
|
||||
cr4_v: t.CUInt64T = 0
|
||||
cr4_v: uint64 = 0
|
||||
c.Asm(f"""mov rax, cr4
|
||||
mov {c.AsmOut(cr4_v, t.ASM_DESCR.OUTPUT_REG)}, rax""",
|
||||
op=[t.ASM_DESCR.CLOBBER_RAX])
|
||||
cr4_v = cr4_v | t.CUInt64T(0x600) # OSFXSR | OSXMMEXCPT
|
||||
cr4_v = cr4_v | uint64(0x600) # OSFXSR | OSXMMEXCPT
|
||||
c.Asm(f"""mov rax, {c.AsmInp(cr4_v, t.ASM_DESCR.REG_ANY)}
|
||||
mov cr4, rax""",
|
||||
op=[t.ASM_DESCR.CLOBBER_RAX])
|
||||
|
||||
@@ -5,7 +5,7 @@ import t, c
|
||||
# FPU上下文结构体
|
||||
@c.Attribute(t.attr.aligned(16))
|
||||
class fpu_context:
|
||||
data: t.CArray[t.CUInt8T, 512] # FXSAVE区域大小
|
||||
data: t.CArray[uint8, 512] # FXSAVE区域大小
|
||||
|
||||
|
||||
@t.Object
|
||||
@@ -18,14 +18,14 @@ class _FPUObject:
|
||||
c.Asm("fninit", [t.ASM_DESCR.CLOBBER_MEMORY])
|
||||
# 启用FPU
|
||||
def enable(self):
|
||||
cr0: t.CUInt64T = self.CPUObject.readCR0()
|
||||
cr0: uint64 = self.CPUObject.readCR0()
|
||||
# 清除EM位(禁用仿真),设置MP位(监控协处理器)
|
||||
cr0 &= ~(1 << 2); # 清除EM位
|
||||
cr0 |= (1 << 1); # 设置MP位
|
||||
# 写入CR0寄存器
|
||||
self.CPUObject.writeCR0(cr0)
|
||||
# 读取CR4寄存器
|
||||
cr4: t.CUInt64T = self.CPUObject.readCR4()
|
||||
cr4: uint64 = self.CPUObject.readCR4()
|
||||
# 设置OSFXSR位和OSXMMEXCPT位,启用SSE
|
||||
cr4 |= (1 << 9) | (1 << 10)
|
||||
# 写入CR4寄存器
|
||||
@@ -34,7 +34,7 @@ class _FPUObject:
|
||||
c.Asm("fninit", [t.ASM_DESCR.CLOBBER_MEMORY])
|
||||
# 禁用FPU
|
||||
def disable(self):
|
||||
cr0: t.CUInt64T = self.CPUObject.readCR0()
|
||||
cr0: uint64 = self.CPUObject.readCR0()
|
||||
# 设置EM位(启用仿真),清除MP位(禁用监控协处理器)
|
||||
cr0 |= (1 << 2) # 设置EM位
|
||||
cr0 &= ~(1 << 1) # 清除MP位
|
||||
|
||||
@@ -10,15 +10,15 @@ MAX_DIRECTORIES: t.CDefine = 16
|
||||
PATH_BUFFER_SIZE: t.CDefine = 256
|
||||
|
||||
directories: t.CArray[devfs_directory, MAX_DIRECTORIES] = [0]
|
||||
directory_count: t.CStatic | t.CInt = 0
|
||||
directory_count: t.CStatic | int = 0
|
||||
|
||||
files: t.CArray[devfs_file, MAX_DEVICE_FILES] = [0]
|
||||
file_count: t.CStatic | t.CInt = 0
|
||||
file_count: t.CStatic | int = 0
|
||||
|
||||
|
||||
class _fd_table:
|
||||
file: devfs_file | t.CPtr
|
||||
flags: t.CInt
|
||||
flags: int
|
||||
|
||||
fd_table: t.CArray[_fd_table, MAX_FILE_DESCRIPTORS] = [0]
|
||||
|
||||
@@ -35,7 +35,7 @@ class devfs_directory:
|
||||
|
||||
current_dir: devfs_directory | t.CPtr = root_directory
|
||||
result: t.CArray[str, PATH_BUFFER_SIZE]
|
||||
token = string.split(path, "/", result)
|
||||
token = string.split(path, "/", result, PATH_BUFFER_SIZE)
|
||||
|
||||
# `for i in result` 按 NULL 终止语义遍历(i8* 元素,split 尾哨兵 NULL 停):
|
||||
# 编译器 _handle_array_iter 已实现"长度上限 + 解引用为空提前终止"。
|
||||
@@ -63,12 +63,12 @@ class devfs_directory:
|
||||
@staticmethod
|
||||
def list_subdirs(dir_ptr: devfs_directory | t.CPtr,
|
||||
buffer: str,
|
||||
size: t.CUInt32T,
|
||||
pos: t.CInt) -> t.CInt:
|
||||
size: uint32,
|
||||
pos: int) -> int:
|
||||
for d in range(directory_count):
|
||||
dirp: devfs_directory = c.Addr(directories[d])
|
||||
if dirp.parent == dir_ptr:
|
||||
name_len: t.CInt = string.strlen(dirp.name)
|
||||
name_len: int = string.strlen(dirp.name)
|
||||
if pos + name_len + 1 > size:
|
||||
break
|
||||
string.strcpy(buffer + pos, dirp.name)
|
||||
@@ -81,7 +81,7 @@ class devfs_directory:
|
||||
@t.CVTable
|
||||
class devfs_file:
|
||||
name: t.CArray[t.CChar, 64]
|
||||
private_data: t.CVoid | t.CPtr
|
||||
private_data: t.CPtr
|
||||
parent_dir: 'devfs_directory' | t.CPtr
|
||||
|
||||
@staticmethod
|
||||
@@ -96,12 +96,12 @@ class devfs_file:
|
||||
@staticmethod
|
||||
def list_in_dir(dir_ptr: devfs_directory | t.CPtr,
|
||||
buffer: str,
|
||||
size: t.CUInt32T,
|
||||
pos: t.CInt) -> t.CInt:
|
||||
size: uint32,
|
||||
pos: int) -> int:
|
||||
for f in range(file_count):
|
||||
filep: devfs_file | t.CPtr = c.Addr(files[f])
|
||||
if filep.parent_dir == dir_ptr:
|
||||
name_len: t.CInt = string.strlen(filep.name)
|
||||
name_len: int = string.strlen(filep.name)
|
||||
if pos + name_len + 1 > size:
|
||||
break
|
||||
string.strcpy(buffer + pos, filep.name)
|
||||
@@ -110,19 +110,19 @@ class devfs_file:
|
||||
pos += 1
|
||||
return pos
|
||||
|
||||
def open(self, path: t.CConst | str, flags: t.CInt) -> t.CInt:
|
||||
def open(self, path: t.CConst | str, flags: int) -> int:
|
||||
return 0
|
||||
|
||||
def close(self, fd: t.CInt) -> t.CInt:
|
||||
def close(self, fd: int) -> int:
|
||||
return 0
|
||||
|
||||
def read(self, fd: t.CInt, buffer: t.CVoid | t.CPtr, size: t.CUInt32T) -> t.CInt:
|
||||
def read(self, fd: int, buffer: t.CPtr, size: uint32) -> int:
|
||||
return 0
|
||||
|
||||
def write(self, fd: t.CInt, buffer: t.CConst | t.CVoid | t.CPtr, size: t.CUInt32T) -> t.CInt:
|
||||
def write(self, fd: int, buffer: t.CConst | t.CPtr, size: uint32) -> int:
|
||||
return 0
|
||||
|
||||
def ioctl(self, fd: t.CInt, request: t.CInt, arg: t.CVoid | t.CPtr) -> t.CInt:
|
||||
def ioctl(self, fd: int, request: int, arg: t.CPtr) -> int:
|
||||
return 0
|
||||
|
||||
@t.Object
|
||||
@@ -168,8 +168,8 @@ class _DevFSObject:
|
||||
current: devfs_directory | t.CPtr = self.root_directory
|
||||
buf: t.CArray[t.CChar, PATH_BUFFER_SIZE]
|
||||
string.memset(c.Addr(buf), 0, PATH_BUFFER_SIZE)
|
||||
buf_idx: t.CInt = 0
|
||||
p: t.CInt = 0
|
||||
buf_idx: int = 0
|
||||
p: int = 0
|
||||
if path[p] == '/':
|
||||
p += 1
|
||||
serial.puts("C")
|
||||
@@ -199,12 +199,12 @@ class _DevFSObject:
|
||||
|
||||
return current
|
||||
|
||||
def init(self) -> t.CInt:
|
||||
def init(self) -> int:
|
||||
self.create_directory("/dev")
|
||||
self.create_directory("/dev/input")
|
||||
return 0
|
||||
|
||||
def create_directory(self, path: t.CConst | str) -> t.CInt:
|
||||
def create_directory(self, path: t.CConst | str) -> int:
|
||||
serial.puts("T1")
|
||||
dir_ptr: devfs_directory | t.CPtr = self.find_or_create_directory(path)
|
||||
serial.puts("T2")
|
||||
@@ -212,7 +212,7 @@ class _DevFSObject:
|
||||
|
||||
def create_file(self, path: t.CConst | str,
|
||||
file_ptr: devfs_file | t.CPtr,
|
||||
private_data: t.CVoid | t.CPtr) -> t.CInt:
|
||||
private_data: t.CPtr) -> int:
|
||||
global file_count
|
||||
path_copy: t.CArray[t.CChar, PATH_BUFFER_SIZE]
|
||||
string.memset(c.Addr(path_copy), 0, PATH_BUFFER_SIZE)
|
||||
@@ -237,7 +237,7 @@ class _DevFSObject:
|
||||
if file_ptr:
|
||||
# [DIAG] 定位 register 阶段 strcpy 目标:打印 file_ptr(用后移除)
|
||||
_dbg3: t.CArray[t.CChar, 80]
|
||||
viperlib.snprintf(c.Addr(_dbg3), 80, "[cf] fp=%lx\n", t.CUInt64T(file_ptr))
|
||||
viperlib.snprintf(c.Addr(_dbg3), 80, "[cf] fp=%lx\n", uint64(file_ptr))
|
||||
serial.puts(c.Addr(_dbg3))
|
||||
string.strcpy(file_ptr.name, file_name)
|
||||
file_ptr.private_data = private_data
|
||||
@@ -252,7 +252,7 @@ class _DevFSObject:
|
||||
file_count += 1
|
||||
return 0
|
||||
|
||||
def open(self, path: t.CConst | str, flags: t.CInt) -> t.CInt:
|
||||
def open(self, path: t.CConst | str, flags: int) -> int:
|
||||
path_copy: t.CArray[t.CChar, PATH_BUFFER_SIZE]
|
||||
string.memset(c.Addr(path_copy), 0, PATH_BUFFER_SIZE)
|
||||
string.strcpy(path_copy, path)
|
||||
@@ -273,12 +273,12 @@ class _DevFSObject:
|
||||
|
||||
# [DIAG] 定位 vtable 悬垂:打印 file_ptr 与对象首字段(vtable 指针)(用后移除)
|
||||
_dbg_buf: t.CArray[t.CChar, 96]
|
||||
_dbg_vt: t.CUInt64T = t.CUInt64T(file_ptr, t.CPtr)[0]
|
||||
_dbg_vt: uint64 = uint64(file_ptr, t.CPtr)[0]
|
||||
viperlib.snprintf(c.Addr(_dbg_buf), 96, "[open] fp=%lx vt=%lx\n",
|
||||
t.CUInt64T(file_ptr), _dbg_vt)
|
||||
uint64(file_ptr), _dbg_vt)
|
||||
serial.puts(c.Addr(_dbg_buf))
|
||||
|
||||
fd: t.CInt = -1
|
||||
fd: int = -1
|
||||
for i in range(MAX_FILE_DESCRIPTORS):
|
||||
if not fd_table[i].file:
|
||||
fd = i
|
||||
@@ -286,14 +286,14 @@ class _DevFSObject:
|
||||
|
||||
if fd == -1: return -1
|
||||
|
||||
ret: t.CInt = file_ptr.open(path, flags)
|
||||
ret: int = file_ptr.open(path, flags)
|
||||
if ret != 0: return ret
|
||||
|
||||
fd_table[fd].file = file_ptr
|
||||
fd_table[fd].flags = flags
|
||||
return fd
|
||||
|
||||
def close(self, fd: t.CInt) -> t.CInt:
|
||||
def close(self, fd: int) -> int:
|
||||
if fd < 0 or fd >= MAX_FILE_DESCRIPTORS or not fd_table[fd].file:
|
||||
return -1
|
||||
file_ptr: devfs_file | t.CPtr = fd_table[fd].file
|
||||
@@ -302,19 +302,19 @@ class _DevFSObject:
|
||||
fd_table[fd].flags = 0
|
||||
return 0
|
||||
|
||||
def read(self, fd: t.CInt, buffer: t.CVoid | t.CPtr, size: t.CUInt32T) -> t.CInt:
|
||||
def read(self, fd: int, buffer: t.CPtr, size: uint32) -> int:
|
||||
if fd < 0 or fd >= MAX_FILE_DESCRIPTORS or not fd_table[fd].file:
|
||||
return -1
|
||||
file_ptr: devfs_file | t.CPtr = fd_table[fd].file
|
||||
return file_ptr.read(fd, buffer, size)
|
||||
|
||||
def write(self, fd: t.CInt, buffer: t.CConst | t.CVoid | t.CPtr, size: t.CUInt32T) -> t.CInt:
|
||||
def write(self, fd: int, buffer: t.CConst | t.CPtr, size: uint32) -> int:
|
||||
if fd < 0 or fd >= MAX_FILE_DESCRIPTORS or not fd_table[fd].file:
|
||||
return -1
|
||||
file_ptr: devfs_file | t.CPtr = fd_table[fd].file
|
||||
return file_ptr.write(fd, buffer, size)
|
||||
|
||||
def ioctl(self, fd: t.CInt, cmd: t.CUInt32T, arg: t.CVoid | t.CPtr) -> t.CInt:
|
||||
def ioctl(self, fd: int, cmd: uint32, arg: t.CPtr) -> int:
|
||||
if fd < 0 or fd >= MAX_FILE_DESCRIPTORS or not fd_table[fd].file:
|
||||
return -1
|
||||
file_ptr: devfs_file | t.CPtr = fd_table[fd].file
|
||||
@@ -322,11 +322,11 @@ class _DevFSObject:
|
||||
|
||||
def list_directory(self, path: t.CConst | str,
|
||||
buffer: str,
|
||||
size: t.CUInt32T) -> t.CInt:
|
||||
size: uint32) -> int:
|
||||
dir_ptr: devfs_directory | t.CPtr = devfs_directory.find(path, self.root_directory)
|
||||
if not dir_ptr or not buffer or size == 0: return -1
|
||||
|
||||
pos: t.CInt = devfs_directory.list_subdirs(dir_ptr, buffer, size, 0)
|
||||
pos: int = devfs_directory.list_subdirs(dir_ptr, buffer, size, 0)
|
||||
pos = devfs_file.list_in_dir(dir_ptr, buffer, size, pos)
|
||||
|
||||
return pos
|
||||
@@ -335,7 +335,7 @@ DevFSObject: _DevFSObject | t.CPtr
|
||||
_DevFSObject_instance: _DevFSObject
|
||||
|
||||
|
||||
def devfs_init() -> t.CInt:
|
||||
def devfs_init() -> int:
|
||||
global DevFSObject, _DevFSObject_instance
|
||||
DevFSObject = c.Addr(_DevFSObject_instance)
|
||||
_DevFSObject_instance = _DevFSObject()
|
||||
@@ -343,57 +343,57 @@ def devfs_init() -> t.CInt:
|
||||
DevFSObject.init()
|
||||
return 0
|
||||
|
||||
def devfs_create_directory(path: t.CConst | str) -> t.CInt:
|
||||
def devfs_create_directory(path: t.CConst | str) -> int:
|
||||
return DevFSObject.create_directory(path)
|
||||
|
||||
def devfs_create_file(path: t.CConst | str,
|
||||
file_ptr: devfs_file | t.CPtr,
|
||||
private_data: t.CVoid | t.CPtr) -> t.CInt:
|
||||
private_data: t.CPtr) -> int:
|
||||
return DevFSObject.create_file(path, file_ptr, private_data)
|
||||
|
||||
def devfs_open(path: t.CConst | str, flags: t.CInt) -> t.CInt:
|
||||
def devfs_open(path: t.CConst | str, flags: int) -> int:
|
||||
return DevFSObject.open(path, flags)
|
||||
|
||||
def devfs_close(fd: t.CInt) -> t.CInt:
|
||||
def devfs_close(fd: int) -> int:
|
||||
return DevFSObject.close(fd)
|
||||
|
||||
def devfs_read(fd: t.CInt, buffer: t.CVoid | t.CPtr, size: t.CUInt32T) -> t.CInt:
|
||||
def devfs_read(fd: int, buffer: t.CPtr, size: uint32) -> int:
|
||||
return DevFSObject.read(fd, buffer, size)
|
||||
|
||||
def devfs_write(fd: t.CInt, buffer: t.CConst | t.CVoid | t.CPtr, size: t.CUInt32T) -> t.CInt:
|
||||
def devfs_write(fd: int, buffer: t.CConst | t.CPtr, size: uint32) -> int:
|
||||
return DevFSObject.write(fd, buffer, size)
|
||||
|
||||
def devfs_ioctl(fd: t.CInt, cmd: t.CUInt32T, arg: t.CVoid | t.CPtr) -> t.CInt:
|
||||
def devfs_ioctl(fd: int, cmd: uint32, arg: t.CPtr) -> int:
|
||||
return DevFSObject.ioctl(fd, cmd, arg)
|
||||
|
||||
def devfs_list_directory(path: t.CConst | str,
|
||||
buffer: str,
|
||||
size: t.CUInt32T) -> t.CInt:
|
||||
size: uint32) -> int:
|
||||
return DevFSObject.list_directory(path, buffer, size)
|
||||
|
||||
serial0_file: devfs_file
|
||||
|
||||
def serial0_open(self: t.CVoid | t.CPtr, path: t.CConst | str, flags: t.CInt) -> t.CInt:
|
||||
def serial0_open(self: t.CPtr, path: t.CConst | str, flags: int) -> int:
|
||||
serial.puts("[serial0] open: ")
|
||||
serial.puts(path)
|
||||
serial.puts("\n")
|
||||
return 0
|
||||
|
||||
def serial0_close(self: t.CVoid | t.CPtr, fd: t.CInt) -> t.CInt:
|
||||
def serial0_close(self: t.CPtr, fd: int) -> int:
|
||||
serial.puts("[serial0] close\n")
|
||||
return 0
|
||||
|
||||
def serial0_read(self: t.CVoid | t.CPtr, fd: t.CInt, buffer: t.CVoid | t.CPtr, size: t.CUInt32T) -> t.CInt:
|
||||
def serial0_read(self: t.CPtr, fd: int, buffer: t.CPtr, size: uint32) -> int:
|
||||
serial.puts("[serial0] read\n")
|
||||
return 0
|
||||
|
||||
def serial0_write(self: t.CVoid | t.CPtr, fd: t.CInt, buffer: t.CConst | t.CVoid | t.CPtr, size: t.CUInt32T) -> t.CInt:
|
||||
def serial0_write(self: t.CPtr, fd: int, buffer: t.CConst | t.CPtr, size: uint32) -> int:
|
||||
serial.puts("[serial0] write\n")
|
||||
serial.puts(str(buffer))
|
||||
serial.puts("\n")
|
||||
return size
|
||||
|
||||
def devfs_register_serial0() -> t.CInt:
|
||||
def devfs_register_serial0() -> int:
|
||||
global serial0_file
|
||||
serial0_file = devfs_file()
|
||||
serial0_file.open = serial0_open
|
||||
@@ -405,21 +405,21 @@ def devfs_register_serial0() -> t.CInt:
|
||||
@t.Object
|
||||
@t.CVTable
|
||||
class serial1_device(devfs_file):
|
||||
def open(self, path: t.CConst | str, flags: t.CInt) -> t.CInt:
|
||||
def open(self, path: t.CConst | str, flags: int) -> int:
|
||||
serial.puts("[serial1] open: ")
|
||||
serial.puts(path)
|
||||
serial.puts("\n")
|
||||
return 0
|
||||
|
||||
def close(self, fd: t.CInt) -> t.CInt:
|
||||
def close(self, fd: int) -> int:
|
||||
serial.puts("[serial1] close\n")
|
||||
return 0
|
||||
|
||||
def read(self, fd: t.CInt, buffer: t.CVoid | t.CPtr, size: t.CUInt32T) -> t.CInt:
|
||||
def read(self, fd: int, buffer: t.CPtr, size: uint32) -> int:
|
||||
serial.puts("[serial1] read\n")
|
||||
return 0
|
||||
|
||||
def write(self, fd: t.CInt, buffer: t.CConst | t.CVoid | t.CPtr, size: t.CUInt32T) -> t.CInt:
|
||||
def write(self, fd: int, buffer: t.CConst | t.CPtr, size: uint32) -> int:
|
||||
serial.puts("[serial1] write\n")
|
||||
serial.puts(str(buffer))
|
||||
serial.puts("\n")
|
||||
@@ -427,7 +427,7 @@ class serial1_device(devfs_file):
|
||||
|
||||
serial1_file: serial1_device
|
||||
|
||||
def devfs_register_serial1() -> t.CInt:
|
||||
def devfs_register_serial1() -> int:
|
||||
global serial1_file
|
||||
serial1_file = serial1_device()
|
||||
return devfs_create_file("/dev/serial1", serial1_file, None)
|
||||
@@ -438,16 +438,16 @@ import drivers.input.mouse.mouse as mouse
|
||||
@t.Object
|
||||
@t.CVTable
|
||||
class keyboard_device(devfs_file):
|
||||
def open(self, path: t.CConst | str, flags: t.CInt) -> t.CInt:
|
||||
def open(self, path: t.CConst | str, flags: int) -> int:
|
||||
return 0
|
||||
|
||||
def close(self, fd: t.CInt) -> t.CInt:
|
||||
def close(self, fd: int) -> int:
|
||||
return 0
|
||||
|
||||
def read(self, fd: t.CInt, buffer: t.CVoid | t.CPtr, size: t.CUInt32T) -> t.CInt:
|
||||
count: t.CUInt32T = 0
|
||||
def read(self, fd: int, buffer: t.CPtr, size: uint32) -> int:
|
||||
count: uint32 = 0
|
||||
while count < size and keyboard.has_data():
|
||||
sc: t.CUInt8T = keyboard.read_scancode()
|
||||
sc: uint8 = keyboard.read_scancode()
|
||||
ch: t.CChar = keyboard.scancode_to_ascii(sc)
|
||||
if ch != '\0':
|
||||
# c.Set(t.CChar(...)[count], ch) 是 Subscript 左值,translate_c_set
|
||||
@@ -456,15 +456,15 @@ class keyboard_device(devfs_file):
|
||||
count += 1
|
||||
return count
|
||||
|
||||
def write(self, fd: t.CInt, buffer: t.CConst | t.CVoid | t.CPtr, size: t.CUInt32T) -> t.CInt:
|
||||
def write(self, fd: int, buffer: t.CConst | t.CPtr, size: uint32) -> int:
|
||||
return -1
|
||||
|
||||
def ioctl(self, fd: t.CInt, request: t.CInt, arg: t.CVoid | t.CPtr) -> t.CInt:
|
||||
def ioctl(self, fd: int, request: int, arg: t.CPtr) -> int:
|
||||
return 0
|
||||
|
||||
kbd_file: keyboard_device
|
||||
|
||||
def devfs_register_keyboard() -> t.CInt:
|
||||
def devfs_register_keyboard() -> int:
|
||||
global kbd_file
|
||||
kbd_file = keyboard_device()
|
||||
keyboard.init()
|
||||
@@ -473,34 +473,35 @@ def devfs_register_keyboard() -> t.CInt:
|
||||
@t.Object
|
||||
@t.CVTable
|
||||
class mouse_device(devfs_file):
|
||||
def open(self, path: t.CConst | str, flags: t.CInt) -> t.CInt:
|
||||
def open(self, path: t.CConst | str, flags: int) -> int:
|
||||
return 0
|
||||
|
||||
def close(self, fd: t.CInt) -> t.CInt:
|
||||
def close(self, fd: int) -> int:
|
||||
return 0
|
||||
|
||||
def read(self, fd: t.CInt, buffer: t.CVoid | t.CPtr, size: t.CUInt32T) -> t.CInt:
|
||||
def read(self, fd: int, buffer: t.CPtr, size: uint32) -> int:
|
||||
if not mouse.has_data(): return 0
|
||||
pkt: mouse.mouse_packet
|
||||
mouse.read_packet(c.Addr(pkt))
|
||||
if size >= 1:
|
||||
t.CUInt8T(buffer, t.CPtr)[0] = pkt.buttons
|
||||
if size >= 5:
|
||||
buf: t.CUInt32T | t.CPtr = t.CVoid(t.CUInt64T(buffer) + 1, t.CPtr)
|
||||
t.CInt32T(buf, t.CPtr)[0] = mouse.get_x()
|
||||
t.CInt32T(buf, t.CPtr)[1] = mouse.get_y()
|
||||
return 5
|
||||
uint8(buffer, t.CPtr)[0] = pkt.buttons
|
||||
# 完整包需要 1(buttons) + 4(x) + 4(y) = 9 字节,否则越界写
|
||||
if size >= 9:
|
||||
buf: uint32 | t.CPtr = t.CVoid(uint64(buffer) + 1, t.CPtr)
|
||||
int32(buf, t.CPtr)[0] = mouse.get_x()
|
||||
int32(buf, t.CPtr)[1] = mouse.get_y()
|
||||
return 9
|
||||
return 1
|
||||
|
||||
def write(self, fd: t.CInt, buffer: t.CConst | t.CVoid | t.CPtr, size: t.CUInt32T) -> t.CInt:
|
||||
def write(self, fd: int, buffer: t.CConst | t.CPtr, size: uint32) -> int:
|
||||
return -1
|
||||
|
||||
def ioctl(self, fd: t.CInt, request: t.CInt, arg: t.CVoid | t.CPtr) -> t.CInt:
|
||||
def ioctl(self, fd: int, request: int, arg: t.CPtr) -> int:
|
||||
return 0
|
||||
|
||||
mse_file: mouse_device
|
||||
|
||||
def devfs_register_mouse() -> t.CInt:
|
||||
def devfs_register_mouse() -> int:
|
||||
global mse_file
|
||||
mse_file = mouse_device()
|
||||
mouse.init()
|
||||
|
||||
@@ -1,238 +1,238 @@
|
||||
from stdint import *
|
||||
import fat32 as fs
|
||||
import fat32_types as types
|
||||
import fat32_part as part
|
||||
import fat32_mkfs as mkfs_mod
|
||||
import string
|
||||
import t, c
|
||||
|
||||
|
||||
def print_fresult(res: types.FRESULT, msg: t.CConst | str) -> t.CInt:
|
||||
if res == types.FRESULT.FR_OK:
|
||||
print(f"[成功] {msg}")
|
||||
return 0
|
||||
else:
|
||||
print(f"[失败] {msg}: {res}")
|
||||
return -1
|
||||
|
||||
|
||||
def print_fresult_void(res: types.FRESULT, msg: t.CConst | str):
|
||||
print_fresult(res, msg)
|
||||
|
||||
|
||||
def example_main() -> t.CInt:
|
||||
print("=== FAT32 文件系统完整示例 ===")
|
||||
print()
|
||||
|
||||
# 1. 扫描可用驱动器
|
||||
print("--- 1. 扫描可用驱动器 ---")
|
||||
res: types.FRESULT = fs.scan_drives()
|
||||
print_fresult_void(res, "扫描驱动器")
|
||||
|
||||
drive_count: t.CInt = fs.get_drive_count()
|
||||
print(f"找到 {drive_count} 个驱动器")
|
||||
i: t.CInt
|
||||
for i in range(drive_count):
|
||||
letter: t.CChar = fs.get_drive_letter(i)
|
||||
part_count: t.CInt = fs.get_partition_count(letter)
|
||||
print(f" 驱动器 {i}: {letter}")
|
||||
for j in range(part_count):
|
||||
is_fat32: t.CInt = fs.is_partition_fat32(letter, j)
|
||||
print(f" 分区 {j}: FAT32={is_fat32}")
|
||||
print()
|
||||
|
||||
# 2. 挂载文件系统
|
||||
print("--- 2. 挂载文件系统 ---")
|
||||
res = fs.mount()
|
||||
if print_fresult(res, "挂载文件系统") != 0:
|
||||
print("提示: 可能需要先格式化磁盘")
|
||||
print()
|
||||
|
||||
# 3. 文件系统信息
|
||||
print("--- 3. 文件系统信息 ---")
|
||||
mounted: t.CInt = fs.is_mounted()
|
||||
print(f"已挂载: {mounted}")
|
||||
if mounted:
|
||||
total_clusters: t.CUInt32T = fs.get_total()
|
||||
free_clusters: t.CUInt32T = fs.get_free()
|
||||
cluster_size: t.CUInt32T = fs.get_cluster_size()
|
||||
total_bytes: t.CUInt64T = t.CUInt64T(total_clusters) * t.CUInt64T(cluster_size)
|
||||
free_bytes: t.CUInt64T = t.CUInt64T(free_clusters) * t.CUInt64T(cluster_size)
|
||||
print(f"总簇数: {total_clusters}")
|
||||
print(f"空闲簇数: {free_clusters}")
|
||||
print(f"簇大小: {cluster_size} 字节")
|
||||
print(f"总大小: {total_bytes} 字节")
|
||||
print(f"空闲大小: {free_bytes} 字节")
|
||||
print()
|
||||
|
||||
# 4. 元数据操作
|
||||
print("--- 4. 元数据操作 ---")
|
||||
fs.set_metadata(0x12345678)
|
||||
metadata: t.CUInt32T = fs.get_metadata()
|
||||
print(f"设置的元数据: 0x{metadata:08X}")
|
||||
print()
|
||||
|
||||
# 5. 获取 FAT 时间
|
||||
print("--- 5. 获取 FAT 时间 ---")
|
||||
fattime: t.CUInt32T = fs.get_fattime()
|
||||
print(f"当前 FAT 时间: 0x{fattime:08X}")
|
||||
print()
|
||||
|
||||
# 6. 目录操作
|
||||
if fs.is_mounted():
|
||||
print("--- 6. 目录操作 ---")
|
||||
|
||||
# 创建目录
|
||||
res = fs.mkdir("/test_dir_1")
|
||||
print_fresult_void(res, "创建目录 /test_dir_1")
|
||||
|
||||
res = fs.mkdir("/test_dir_1/subdir")
|
||||
print_fresult_void(res, "创建子目录 /test_dir_1/subdir")
|
||||
|
||||
res = fs.mkdir("/test_dir_2")
|
||||
print_fresult_void(res, "创建目录 /test_dir_2")
|
||||
print()
|
||||
|
||||
# 7. 文件操作
|
||||
print("--- 7. 文件操作 ---")
|
||||
|
||||
# 创建并写入文件
|
||||
fp1: types.fileobj | t.CPtr = fs.open("/test_dir_1/file1.txt", types.FA_CREATE_ALWAYS | types.FA_WRITE)
|
||||
if fp1 is not None:
|
||||
test_data1: t.CConst | str = "Hello, World!"
|
||||
written: t.CUInt32T = fs.write(fp1, test_data1, 13)
|
||||
print(f"写入文件 /test_dir_1/file1.txt: {written} 字节")
|
||||
fs.close(fp1)
|
||||
|
||||
# 打开追加
|
||||
fp2: types.fileobj | t.CPtr = fs.open("/test_dir_1/file1.txt", types.FA_OPEN_ALWAYS | types.FA_WRITE | types.FA_OPEN_APPEND)
|
||||
if fp2 is not None:
|
||||
test_data2: t.CConst | str = " Append data!"
|
||||
written2: t.CUInt32T = fs.write(fp2, test_data2, 13)
|
||||
print(f"追加写入: {written2} 字节")
|
||||
fs.close(fp2)
|
||||
|
||||
# 读取文件
|
||||
fp3: types.fileobj | t.CPtr = fs.open("/test_dir_1/file1.txt", types.FA_OPEN_EXISTING | types.FA_READ)
|
||||
if fp3 is not None:
|
||||
buf: t.CArray[t.CUInt8T, 256]
|
||||
read_bytes: t.CUInt32T = fs.read(fp3, t.CVoid(c.Addr(buf[0]), t.CPtr), 256)
|
||||
print(f"读取字节数: {read_bytes}")
|
||||
print(f"文件内容: {t.CChar(c.Addr(buf[0]), t.CPtr)}")
|
||||
|
||||
# seek 和 tell
|
||||
fs.seek(fp3, 5)
|
||||
pos: t.CUInt32T = fs.tell(fp3)
|
||||
print(f"seek 到位置 5, 当前位置: {pos}")
|
||||
|
||||
read_bytes2: t.CUInt32T = fs.read(fp3, t.CVoid(c.Addr(buf[0]), t.CPtr), 256)
|
||||
print(f"从位置 5 读取: {t.CChar(c.Addr(buf[0]), t.CPtr)}")
|
||||
|
||||
# 获取文件大小
|
||||
fsize: t.CUInt32T = fs.size(fp3)
|
||||
print(f"文件大小: {fsize} 字节")
|
||||
|
||||
fs.close(fp3)
|
||||
|
||||
# 创建另一个文件
|
||||
fp4: types.fileobj | t.CPtr = fs.open("/test_dir_1/large_file.txt", types.FA_CREATE_ALWAYS | types.FA_WRITE)
|
||||
if fp4 is not None:
|
||||
large_data: t.CArray[t.CUInt8T, 1024]
|
||||
k: t.CInt
|
||||
for k in range(1024):
|
||||
large_data[k] = t.CUInt8T(ord('A') + (k % 26))
|
||||
written3: t.CUInt32T = fs.write(fp4, t.CVoid(c.Addr(large_data[0]), t.CPtr), 1024)
|
||||
print(f"创建大文件, 写入: {written3} 字节")
|
||||
fs.close(fp4)
|
||||
print()
|
||||
|
||||
# 8. 文件状态和属性
|
||||
print("--- 8. 文件状态和属性 ---")
|
||||
|
||||
info: types.fileinfo
|
||||
res = fs.stat("/test_dir_1/file1.txt", c.Addr(info))
|
||||
print_fresult_void(res, "获取文件信息")
|
||||
if res == types.FRESULT.FR_OK:
|
||||
print(f" 文件名: {info.fname}")
|
||||
print(f" 大小: {info.file_size} 字节")
|
||||
print(f" 属性: 0x{info.attr:02X}")
|
||||
print(f" 创建时间: 0x{info.ctime:04X}")
|
||||
print(f" 创建日期: 0x{info.cdate:04X}")
|
||||
print(f" 修改时间: 0x{info.mtime:04X}")
|
||||
print(f" 修改日期: 0x{info.mdate:04X}")
|
||||
print(f" 访问日期: 0x{info.adate:04X}")
|
||||
|
||||
# 修改属性
|
||||
res = fs.chmod("/test_dir_1/file1.txt", types.AM_RDO, types.AM_RDO)
|
||||
print_fresult_void(res, "设置文件为只读")
|
||||
print()
|
||||
|
||||
# 9. 重命名和移动
|
||||
print("--- 9. 重命名和移动 ---")
|
||||
|
||||
res = fs.rename("/test_dir_1/file1.txt", "/test_dir_1/renamed.txt")
|
||||
print_fresult_void(res, "重命名文件")
|
||||
|
||||
res = fs.move("/test_dir_1/renamed.txt", "/test_dir_2/moved.txt")
|
||||
print_fresult_void(res, "移动文件")
|
||||
|
||||
res = fs.rename("/test_dir_2", "/test_dir_renamed")
|
||||
print_fresult_void(res, "重命名目录")
|
||||
print()
|
||||
|
||||
# 10. 列出目录
|
||||
print("--- 10. 列出目录 ---")
|
||||
|
||||
dp: types.dirobj
|
||||
res = fs.opendir("/", c.Addr(dp))
|
||||
if res == types.FRESULT.FR_OK:
|
||||
print("根目录内容:")
|
||||
dir_info: types.fileinfo
|
||||
while True:
|
||||
res = fs.readdir(c.Addr(dp), c.Addr(dir_info))
|
||||
if res != types.FRESULT.FR_OK:
|
||||
break
|
||||
attr_str: t.CArray[t.CChar, 8] = [0]
|
||||
if dir_info.attr & types.AM_DIR:
|
||||
string.strcat(attr_str, "D")
|
||||
else:
|
||||
string.strcat(attr_str, "F")
|
||||
if dir_info.attr & types.AM_RDO:
|
||||
string.strcat(attr_str, "R")
|
||||
if dir_info.attr & types.AM_HID:
|
||||
string.strcat(attr_str, "H")
|
||||
if dir_info.attr & types.AM_SYS:
|
||||
string.strcat(attr_str, "S")
|
||||
if dir_info.attr & types.AM_ARC:
|
||||
string.strcat(attr_str, "A")
|
||||
print(f" [{attr_str}] {dir_info.fname} ({dir_info.file_size} 字节)")
|
||||
fs.closedir(c.Addr(dp))
|
||||
print()
|
||||
|
||||
# 11. 删除文件和目录
|
||||
print("--- 11. 删除文件和目录 ---")
|
||||
|
||||
res = fs.remove("/test_dir_renamed/moved.txt")
|
||||
print_fresult_void(res, "删除文件")
|
||||
|
||||
res = fs.remove("/test_dir_1/large_file.txt")
|
||||
print_fresult_void(res, "删除大文件")
|
||||
|
||||
res = fs.rmdir("/test_dir_1/subdir")
|
||||
print_fresult_void(res, "删除子目录")
|
||||
|
||||
res = fs.rmdir("/test_dir_1")
|
||||
print_fresult_void(res, "删除目录 /test_dir_1")
|
||||
|
||||
res = fs.rmdir("/test_dir_renamed")
|
||||
print_fresult_void(res, "删除目录 /test_dir_renamed")
|
||||
print()
|
||||
|
||||
# 12. 卸载文件系统
|
||||
print("--- 12. 卸载文件系统 ---")
|
||||
res = fs.unmount()
|
||||
print_fresult_void(res, "卸载文件系统")
|
||||
print()
|
||||
|
||||
print("=== 示例完成 ===")
|
||||
return 0
|
||||
from stdint import *
|
||||
import fat32 as fs
|
||||
import fat32_types as types
|
||||
import fat32_part as part
|
||||
import fat32_mkfs as mkfs_mod
|
||||
import string
|
||||
import t, c
|
||||
|
||||
|
||||
def print_fresult(res: types.FRESULT, msg: t.CConst | str) -> int:
|
||||
if res == types.FRESULT.FR_OK:
|
||||
print(f"[成功] {msg}")
|
||||
return 0
|
||||
else:
|
||||
print(f"[失败] {msg}: {res}")
|
||||
return -1
|
||||
|
||||
|
||||
def print_fresult_void(res: types.FRESULT, msg: t.CConst | str):
|
||||
print_fresult(res, msg)
|
||||
|
||||
|
||||
def example_main() -> int:
|
||||
print("=== FAT32 文件系统完整示例 ===")
|
||||
print()
|
||||
|
||||
# 1. 扫描可用驱动器
|
||||
print("--- 1. 扫描可用驱动器 ---")
|
||||
res: types.FRESULT = fs.scan_drives()
|
||||
print_fresult_void(res, "扫描驱动器")
|
||||
|
||||
drive_count: int = fs.get_drive_count()
|
||||
print(f"找到 {drive_count} 个驱动器")
|
||||
i: int
|
||||
for i in range(drive_count):
|
||||
letter: t.CChar = fs.get_drive_letter(i)
|
||||
part_count: int = fs.get_partition_count(letter)
|
||||
print(f" 驱动器 {i}: {letter}")
|
||||
for j in range(part_count):
|
||||
is_fat32: int = fs.is_partition_fat32(letter, j)
|
||||
print(f" 分区 {j}: FAT32={is_fat32}")
|
||||
print()
|
||||
|
||||
# 2. 挂载文件系统
|
||||
print("--- 2. 挂载文件系统 ---")
|
||||
res = fs.mount()
|
||||
if print_fresult(res, "挂载文件系统") != 0:
|
||||
print("提示: 可能需要先格式化磁盘")
|
||||
print()
|
||||
|
||||
# 3. 文件系统信息
|
||||
print("--- 3. 文件系统信息 ---")
|
||||
mounted: int = fs.is_mounted()
|
||||
print(f"已挂载: {mounted}")
|
||||
if mounted:
|
||||
total_clusters: uint32 = fs.get_total()
|
||||
free_clusters: uint32 = fs.get_free()
|
||||
cluster_size: uint32 = fs.get_cluster_size()
|
||||
total_bytes: uint64 = uint64(total_clusters) * uint64(cluster_size)
|
||||
free_bytes: uint64 = uint64(free_clusters) * uint64(cluster_size)
|
||||
print(f"总簇数: {total_clusters}")
|
||||
print(f"空闲簇数: {free_clusters}")
|
||||
print(f"簇大小: {cluster_size} 字节")
|
||||
print(f"总大小: {total_bytes} 字节")
|
||||
print(f"空闲大小: {free_bytes} 字节")
|
||||
print()
|
||||
|
||||
# 4. 元数据操作
|
||||
print("--- 4. 元数据操作 ---")
|
||||
fs.set_metadata(0x12345678)
|
||||
metadata: uint32 = fs.get_metadata()
|
||||
print(f"设置的元数据: 0x{metadata:08X}")
|
||||
print()
|
||||
|
||||
# 5. 获取 FAT 时间
|
||||
print("--- 5. 获取 FAT 时间 ---")
|
||||
fattime: uint32 = fs.get_fattime()
|
||||
print(f"当前 FAT 时间: 0x{fattime:08X}")
|
||||
print()
|
||||
|
||||
# 6. 目录操作
|
||||
if fs.is_mounted():
|
||||
print("--- 6. 目录操作 ---")
|
||||
|
||||
# 创建目录
|
||||
res = fs.mkdir("/test_dir_1")
|
||||
print_fresult_void(res, "创建目录 /test_dir_1")
|
||||
|
||||
res = fs.mkdir("/test_dir_1/subdir")
|
||||
print_fresult_void(res, "创建子目录 /test_dir_1/subdir")
|
||||
|
||||
res = fs.mkdir("/test_dir_2")
|
||||
print_fresult_void(res, "创建目录 /test_dir_2")
|
||||
print()
|
||||
|
||||
# 7. 文件操作
|
||||
print("--- 7. 文件操作 ---")
|
||||
|
||||
# 创建并写入文件
|
||||
fp1: types.fileobj | t.CPtr = fs.open("/test_dir_1/file1.txt", types.FA_CREATE_ALWAYS | types.FA_WRITE)
|
||||
if fp1 is not None:
|
||||
test_data1: t.CConst | str = "Hello, World!"
|
||||
written: uint32 = fs.write(fp1, test_data1, 13)
|
||||
print(f"写入文件 /test_dir_1/file1.txt: {written} 字节")
|
||||
fs.close(fp1)
|
||||
|
||||
# 打开追加
|
||||
fp2: types.fileobj | t.CPtr = fs.open("/test_dir_1/file1.txt", types.FA_OPEN_ALWAYS | types.FA_WRITE | types.FA_OPEN_APPEND)
|
||||
if fp2 is not None:
|
||||
test_data2: t.CConst | str = " Append data!"
|
||||
written2: uint32 = fs.write(fp2, test_data2, 13)
|
||||
print(f"追加写入: {written2} 字节")
|
||||
fs.close(fp2)
|
||||
|
||||
# 读取文件
|
||||
fp3: types.fileobj | t.CPtr = fs.open("/test_dir_1/file1.txt", types.FA_OPEN_EXISTING | types.FA_READ)
|
||||
if fp3 is not None:
|
||||
buf: t.CArray[uint8, 256]
|
||||
read_bytes: uint32 = fs.read(fp3, t.CVoid(c.Addr(buf[0]), t.CPtr), 256)
|
||||
print(f"读取字节数: {read_bytes}")
|
||||
print(f"文件内容: {t.CChar(c.Addr(buf[0]), t.CPtr)}")
|
||||
|
||||
# seek 和 tell
|
||||
fs.seek(fp3, 5)
|
||||
pos: uint32 = fs.tell(fp3)
|
||||
print(f"seek 到位置 5, 当前位置: {pos}")
|
||||
|
||||
read_bytes2: uint32 = fs.read(fp3, t.CVoid(c.Addr(buf[0]), t.CPtr), 256)
|
||||
print(f"从位置 5 读取: {t.CChar(c.Addr(buf[0]), t.CPtr)}")
|
||||
|
||||
# 获取文件大小
|
||||
fsize: uint32 = fs.size(fp3)
|
||||
print(f"文件大小: {fsize} 字节")
|
||||
|
||||
fs.close(fp3)
|
||||
|
||||
# 创建另一个文件
|
||||
fp4: types.fileobj | t.CPtr = fs.open("/test_dir_1/large_file.txt", types.FA_CREATE_ALWAYS | types.FA_WRITE)
|
||||
if fp4 is not None:
|
||||
large_data: t.CArray[uint8, 1024]
|
||||
k: int
|
||||
for k in range(1024):
|
||||
large_data[k] = uint8(ord('A') + (k % 26))
|
||||
written3: uint32 = fs.write(fp4, t.CVoid(c.Addr(large_data[0]), t.CPtr), 1024)
|
||||
print(f"创建大文件, 写入: {written3} 字节")
|
||||
fs.close(fp4)
|
||||
print()
|
||||
|
||||
# 8. 文件状态和属性
|
||||
print("--- 8. 文件状态和属性 ---")
|
||||
|
||||
info: types.fileinfo
|
||||
res = fs.stat("/test_dir_1/file1.txt", c.Addr(info))
|
||||
print_fresult_void(res, "获取文件信息")
|
||||
if res == types.FRESULT.FR_OK:
|
||||
print(f" 文件名: {info.fname}")
|
||||
print(f" 大小: {info.file_size} 字节")
|
||||
print(f" 属性: 0x{info.attr:02X}")
|
||||
print(f" 创建时间: 0x{info.ctime:04X}")
|
||||
print(f" 创建日期: 0x{info.cdate:04X}")
|
||||
print(f" 修改时间: 0x{info.mtime:04X}")
|
||||
print(f" 修改日期: 0x{info.mdate:04X}")
|
||||
print(f" 访问日期: 0x{info.adate:04X}")
|
||||
|
||||
# 修改属性
|
||||
res = fs.chmod("/test_dir_1/file1.txt", types.AM_RDO, types.AM_RDO)
|
||||
print_fresult_void(res, "设置文件为只读")
|
||||
print()
|
||||
|
||||
# 9. 重命名和移动
|
||||
print("--- 9. 重命名和移动 ---")
|
||||
|
||||
res = fs.rename("/test_dir_1/file1.txt", "/test_dir_1/renamed.txt")
|
||||
print_fresult_void(res, "重命名文件")
|
||||
|
||||
res = fs.move("/test_dir_1/renamed.txt", "/test_dir_2/moved.txt")
|
||||
print_fresult_void(res, "移动文件")
|
||||
|
||||
res = fs.rename("/test_dir_2", "/test_dir_renamed")
|
||||
print_fresult_void(res, "重命名目录")
|
||||
print()
|
||||
|
||||
# 10. 列出目录
|
||||
print("--- 10. 列出目录 ---")
|
||||
|
||||
dp: types.dirobj
|
||||
res = fs.opendir("/", c.Addr(dp))
|
||||
if res == types.FRESULT.FR_OK:
|
||||
print("根目录内容:")
|
||||
dir_info: types.fileinfo
|
||||
while True:
|
||||
res = fs.readdir(c.Addr(dp), c.Addr(dir_info))
|
||||
if res != types.FRESULT.FR_OK:
|
||||
break
|
||||
attr_str: t.CArray[t.CChar, 8] = [0]
|
||||
if dir_info.attr & types.AM_DIR:
|
||||
string.strcat(attr_str, "D")
|
||||
else:
|
||||
string.strcat(attr_str, "F")
|
||||
if dir_info.attr & types.AM_RDO:
|
||||
string.strcat(attr_str, "R")
|
||||
if dir_info.attr & types.AM_HID:
|
||||
string.strcat(attr_str, "H")
|
||||
if dir_info.attr & types.AM_SYS:
|
||||
string.strcat(attr_str, "S")
|
||||
if dir_info.attr & types.AM_ARC:
|
||||
string.strcat(attr_str, "A")
|
||||
print(f" [{attr_str}] {dir_info.fname} ({dir_info.file_size} 字节)")
|
||||
fs.closedir(c.Addr(dp))
|
||||
print()
|
||||
|
||||
# 11. 删除文件和目录
|
||||
print("--- 11. 删除文件和目录 ---")
|
||||
|
||||
res = fs.remove("/test_dir_renamed/moved.txt")
|
||||
print_fresult_void(res, "删除文件")
|
||||
|
||||
res = fs.remove("/test_dir_1/large_file.txt")
|
||||
print_fresult_void(res, "删除大文件")
|
||||
|
||||
res = fs.rmdir("/test_dir_1/subdir")
|
||||
print_fresult_void(res, "删除子目录")
|
||||
|
||||
res = fs.rmdir("/test_dir_1")
|
||||
print_fresult_void(res, "删除目录 /test_dir_1")
|
||||
|
||||
res = fs.rmdir("/test_dir_renamed")
|
||||
print_fresult_void(res, "删除目录 /test_dir_renamed")
|
||||
print()
|
||||
|
||||
# 12. 卸载文件系统
|
||||
print("--- 12. 卸载文件系统 ---")
|
||||
res = fs.unmount()
|
||||
print_fresult_void(res, "卸载文件系统")
|
||||
print()
|
||||
|
||||
print("=== 示例完成 ===")
|
||||
return 0
|
||||
@@ -1,214 +1,214 @@
|
||||
from stdint import *
|
||||
import string
|
||||
import fat32_types as types
|
||||
import fat32_time as ftime
|
||||
import fat32_mkfs as mkfs_mod
|
||||
import fat32_part as part
|
||||
import fat32_diskio as diskio
|
||||
import sched.sched as sched
|
||||
import viperlib
|
||||
import drivers.serial.uart.serial as serial
|
||||
import t, c
|
||||
|
||||
|
||||
default_fs: types.volinfo = types.volinfo()
|
||||
_fs_lock: t.CInt = 0
|
||||
|
||||
def lock():
|
||||
global _fs_lock
|
||||
while True:
|
||||
c.Asm("cli")
|
||||
if _fs_lock == 0:
|
||||
_fs_lock = 1
|
||||
c.Asm("sti")
|
||||
return
|
||||
c.Asm("sti")
|
||||
sched.Scheduler._yield()
|
||||
|
||||
def unlock():
|
||||
global _fs_lock
|
||||
_fs_lock = 0
|
||||
|
||||
def mount() -> types.FRESULT:
|
||||
default_fs.pdrv = 0
|
||||
default_fs.hidden_sectors = 0
|
||||
buf: t.CArray[t.CUInt8T, 512]
|
||||
dres: types.DRESULT = diskio.read(0, c.Addr(buf[0]), 0, 1)
|
||||
if dres == types.DRESULT.RES_OK:
|
||||
if buf[0] == 0xEB or buf[0] == 0xE9:
|
||||
default_fs.hidden_sectors = 0
|
||||
else:
|
||||
sig: t.CUInt16T = t.CUInt16T(buf[510]) | (t.CUInt16T(buf[511]) << 8)
|
||||
if sig == 0xAA55:
|
||||
ptype: t.CUInt8T = buf[450]
|
||||
if ptype != 0:
|
||||
slba: t.CUInt32T = t.CUInt32T(buf[454]) | (t.CUInt32T(buf[455]) << 8) | (t.CUInt32T(buf[456]) << 16) | (t.CUInt32T(buf[457]) << 24)
|
||||
default_fs.hidden_sectors = slba
|
||||
if default_fs.mounted: return types.FRESULT.FR_OK
|
||||
dsk_res: types.DRESULT = diskio.status(default_fs.pdrv)
|
||||
if dsk_res != types.DRESULT.RES_OK:
|
||||
dsk_res = diskio.init(default_fs.pdrv)
|
||||
if dsk_res != types.DRESULT.RES_OK: return types.FRESULT.FR_NOT_READY
|
||||
default_fs.winsect = 0xFFFFFFFFFFFFFFFF
|
||||
default_fs.fat_winsect = 0xFFFFFFFFFFFFFFFF
|
||||
wres: types.FRESULT = default_fs.win_read(0)
|
||||
if wres != types.FRESULT.FR_OK: return types.FRESULT.FR_DISK_ERR
|
||||
bps: t.CUInt16T = default_fs.win[11] | (t.CUInt16T(default_fs.win[12]) << 8)
|
||||
spc: t.CUInt8T = default_fs.win[13]
|
||||
rsc: t.CUInt16T = default_fs.win[14] | (t.CUInt16T(default_fs.win[15]) << 8)
|
||||
nf: t.CUInt8T = default_fs.win[16]
|
||||
if bps != 512: return types.FRESULT.FR_NO_FILESYSTEM
|
||||
if spc == 0 or (spc & (spc - 1)) != 0: return types.FRESULT.FR_NO_FILESYSTEM
|
||||
if rsc == 0: return types.FRESULT.FR_NO_FILESYSTEM
|
||||
if nf == 0: return types.FRESULT.FR_NO_FILESYSTEM
|
||||
root_ent: t.CUInt16T = default_fs.win[17] | (t.CUInt16T(default_fs.win[18]) << 8)
|
||||
fat16sz: t.CUInt16T = default_fs.win[22] | (t.CUInt16T(default_fs.win[23]) << 8)
|
||||
tot32: t.CUInt32T = t.CUInt32T(default_fs.win[32]) | (t.CUInt32T(default_fs.win[33]) << 8) | (t.CUInt32T(default_fs.win[34]) << 16) | (t.CUInt32T(default_fs.win[35]) << 24)
|
||||
fat32sz: t.CUInt32T = t.CUInt32T(default_fs.win[36]) | (t.CUInt32T(default_fs.win[37]) << 8) | (t.CUInt32T(default_fs.win[38]) << 16) | (t.CUInt32T(default_fs.win[39]) << 24)
|
||||
root_clus: t.CUInt32T = t.CUInt32T(default_fs.win[44]) | (t.CUInt32T(default_fs.win[45]) << 8) | (t.CUInt32T(default_fs.win[46]) << 16) | (t.CUInt32T(default_fs.win[47]) << 24)
|
||||
if root_ent != 0 or fat16sz != 0: return types.FRESULT.FR_NO_FILESYSTEM
|
||||
if fat32sz == 0: return types.FRESULT.FR_NO_FILESYSTEM
|
||||
if tot32 == 0: return types.FRESULT.FR_NO_FILESYSTEM
|
||||
if default_fs.win[510] != 0x55 or default_fs.win[511] != 0xAA: return types.FRESULT.FR_NO_FILESYSTEM
|
||||
fsinfo_sec: t.CUInt16T = default_fs.win[48] | (t.CUInt16T(default_fs.win[49]) << 8)
|
||||
bkboot_sec: t.CUInt16T = default_fs.win[50] | (t.CUInt16T(default_fs.win[51]) << 8)
|
||||
default_fs.sector_size = 512
|
||||
default_fs.cluster_sectors = spc
|
||||
default_fs.cluster_size = t.CUInt32T(spc) * 512
|
||||
default_fs.num_fats = nf
|
||||
default_fs.reserved_sectors = rsc
|
||||
default_fs.fat_size = fat32sz
|
||||
default_fs.fat_start = t.CUInt64T(rsc)
|
||||
default_fs.total_sectors = t.CUInt64T(tot32)
|
||||
default_fs.root_cluster = root_clus
|
||||
default_fs.fsinfo_sector = fsinfo_sec
|
||||
default_fs.backup_sector = bkboot_sec
|
||||
default_fs.vol_id = t.CUInt32T(default_fs.win[67]) | (t.CUInt32T(default_fs.win[68]) << 8) | (t.CUInt32T(default_fs.win[69]) << 16) | (t.CUInt32T(default_fs.win[70]) << 24)
|
||||
data_sectors: t.CUInt64T = default_fs.total_sectors - t.CUInt64T(rsc) - t.CUInt64T(t.CUInt64T(nf) * t.CUInt64T(fat32sz))
|
||||
default_fs.total_clusters = t.CUInt32T(data_sectors / t.CUInt64T(spc))
|
||||
default_fs.data_start = default_fs.fat_start + t.CUInt64T(t.CUInt64T(nf) * t.CUInt64T(fat32sz))
|
||||
default_fs.last_alloc = 2
|
||||
default_fs.free_clusters = 0xFFFFFFFF
|
||||
if fsinfo_sec != 0:
|
||||
default_fs.fsinfo_read()
|
||||
default_fs.mounted = 1
|
||||
return types.FRESULT.FR_OK
|
||||
|
||||
def unmount() -> types.FRESULT:
|
||||
return default_fs.unmount()
|
||||
|
||||
def format(sec_per_clus: t.CUInt8T = 0, vol_id: t.CUInt32T = 0) -> types.FRESULT:
|
||||
return mkfs_mod.mkfs(default_fs.pdrv, sec_per_clus, vol_id)
|
||||
|
||||
def open(path: t.CConst | str, mode: t.CUInt8T) -> types.fileobj | t.CPtr:
|
||||
return default_fs.file_open(path, mode)
|
||||
|
||||
def close(fp: types.fileobj | t.CPtr) -> types.FRESULT:
|
||||
return fp.close()
|
||||
|
||||
def read(fp: types.fileobj | t.CPtr, buff: t.CVoid | t.CPtr, btr: t.CUInt32T) -> t.CUInt32T:
|
||||
br: t.CUInt32T = 0
|
||||
fp.read(buff, btr, c.Addr(br))
|
||||
# [RD2-DIAG] 确认 br 是否被 c.Set 写入(types 内 total_read=64 但外部可能收不到)
|
||||
_rd2: t.CArray[t.CChar, 96]
|
||||
viperlib.snprintf(c.Addr(_rd2), 96, "[fat32.vp] read br=%lu\n", br)
|
||||
serial.puts(c.Addr(_rd2))
|
||||
return br
|
||||
|
||||
def write(fp: types.fileobj | t.CPtr, buff: t.CConst | t.CVoid | t.CPtr, btw: t.CUInt32T) -> t.CUInt32T:
|
||||
bw: t.CUInt32T = 0
|
||||
fp.write(buff, btw, c.Addr(bw))
|
||||
return bw
|
||||
|
||||
def seek(fp: types.fileobj | t.CPtr, offset: t.CUInt32T) -> types.FRESULT:
|
||||
return fp.seek(offset)
|
||||
|
||||
def tell(fp: types.fileobj | t.CPtr) -> t.CUInt32T:
|
||||
return fp.tell()
|
||||
|
||||
def size(fp: types.fileobj | t.CPtr) -> t.CUInt32T:
|
||||
return fp.size()
|
||||
|
||||
def truncate(fp: types.fileobj | t.CPtr) -> types.FRESULT:
|
||||
return fp.truncate()
|
||||
|
||||
def remove(path: t.CConst | str) -> types.FRESULT:
|
||||
return default_fs.file_delete(path)
|
||||
|
||||
def rename(old_path: t.CConst | str, new_path: t.CConst | str) -> types.FRESULT:
|
||||
return default_fs.file_rename(old_path, new_path)
|
||||
|
||||
def move(old_path: t.CConst | str, new_path: t.CConst | str) -> types.FRESULT:
|
||||
return default_fs.file_rename(old_path, new_path)
|
||||
|
||||
def stat(path: t.CConst | str, info: types.fileinfo | t.CPtr) -> types.FRESULT:
|
||||
return default_fs.file_stat(path, info)
|
||||
|
||||
def mkdir(path: t.CConst | str) -> types.FRESULT:
|
||||
return default_fs.dir_make(path)
|
||||
|
||||
def rmdir(path: t.CConst | str) -> types.FRESULT:
|
||||
return default_fs.dir_remove(path)
|
||||
|
||||
def opendir(path: t.CConst | str, dp: types.dirobj | t.CPtr) -> types.FRESULT:
|
||||
return default_fs.dir_open_path(path, dp)
|
||||
|
||||
def readdir(dp: types.dirobj | t.CPtr, info: types.fileinfo | t.CPtr) -> types.FRESULT:
|
||||
return default_fs.dir_read(dp, info)
|
||||
|
||||
def closedir(dp: types.dirobj | t.CPtr):
|
||||
dp.is_open = 0
|
||||
|
||||
def chmod(path: t.CConst | str, attr: t.CUInt8T, mask: t.CUInt8T) -> types.FRESULT:
|
||||
return default_fs.chmod(path, attr, mask)
|
||||
|
||||
def utime(path: t.CConst | str, mtime: t.CUInt16T, mdate: t.CUInt16T) -> types.FRESULT:
|
||||
return default_fs.utime(path, mtime, mdate)
|
||||
|
||||
def get_free() -> t.CUInt32T:
|
||||
if not default_fs.mounted: return 0
|
||||
if default_fs.free_clusters == 0xFFFFFFFF:
|
||||
return default_fs.count_free_clusters()
|
||||
return default_fs.free_clusters
|
||||
|
||||
def get_total() -> t.CUInt32T:
|
||||
if not default_fs.mounted: return 0
|
||||
return default_fs.total_clusters
|
||||
|
||||
def get_cluster_size() -> t.CUInt32T:
|
||||
if not default_fs.mounted: return 0
|
||||
return default_fs.cluster_size
|
||||
|
||||
def is_mounted() -> t.CInt:
|
||||
return default_fs.mounted
|
||||
|
||||
def last_error() -> t.CUInt32T:
|
||||
return default_fs.last_error
|
||||
|
||||
def get_fattime() -> t.CUInt32T:
|
||||
return ftime.get_fattime()
|
||||
|
||||
def get_metadata() -> t.CUInt32T:
|
||||
return default_fs.metadata
|
||||
|
||||
def set_metadata(val: t.CUInt32T):
|
||||
default_fs.metadata = val
|
||||
|
||||
def scan_drives() -> types.FRESULT:
|
||||
return part.scan_drives()
|
||||
|
||||
def get_drive_count() -> t.CInt:
|
||||
return part.get_drive_count()
|
||||
|
||||
def get_drive_letter(idx: t.CInt) -> t.CChar:
|
||||
return part.get_drive_letter(idx)
|
||||
|
||||
def set_drive_letter(idx: t.CInt, letter: t.CChar) -> types.FRESULT:
|
||||
return part.set_drive_letter(idx, letter)
|
||||
|
||||
def get_partition_count(letter: t.CChar) -> t.CInt:
|
||||
return part.get_partition_count(letter)
|
||||
|
||||
def is_partition_fat32(letter: t.CChar, part_idx: t.CInt) -> t.CInt:
|
||||
return part.is_partition_fat32(letter, part_idx)
|
||||
|
||||
from stdint import *
|
||||
import string
|
||||
import fat32_types as types
|
||||
import fat32_time as ftime
|
||||
import fat32_mkfs as mkfs_mod
|
||||
import fat32_part as part
|
||||
import fat32_diskio as diskio
|
||||
import sched.sched as sched
|
||||
import viperlib
|
||||
import drivers.serial.uart.serial as serial
|
||||
import t, c
|
||||
|
||||
|
||||
default_fs: types.volinfo = types.volinfo()
|
||||
_fs_lock: int = 0
|
||||
|
||||
def lock():
|
||||
global _fs_lock
|
||||
while True:
|
||||
c.Asm("cli")
|
||||
if _fs_lock == 0:
|
||||
_fs_lock = 1
|
||||
c.Asm("sti")
|
||||
return
|
||||
c.Asm("sti")
|
||||
sched.Scheduler._yield()
|
||||
|
||||
def unlock():
|
||||
global _fs_lock
|
||||
_fs_lock = 0
|
||||
|
||||
def mount() -> types.FRESULT:
|
||||
default_fs.pdrv = 0
|
||||
default_fs.hidden_sectors = 0
|
||||
buf: t.CArray[uint8, 512]
|
||||
dres: types.DRESULT = diskio.read(0, c.Addr(buf[0]), 0, 1)
|
||||
if dres == types.DRESULT.RES_OK:
|
||||
if buf[0] == 0xEB or buf[0] == 0xE9:
|
||||
default_fs.hidden_sectors = 0
|
||||
else:
|
||||
sig: uint16 = uint16(buf[510]) | (uint16(buf[511]) << 8)
|
||||
if sig == 0xAA55:
|
||||
ptype: uint8 = buf[450]
|
||||
if ptype != 0:
|
||||
slba: uint32 = uint32(buf[454]) | (uint32(buf[455]) << 8) | (uint32(buf[456]) << 16) | (uint32(buf[457]) << 24)
|
||||
default_fs.hidden_sectors = slba
|
||||
if default_fs.mounted: return types.FRESULT.FR_OK
|
||||
dsk_res: types.DRESULT = diskio.status(default_fs.pdrv)
|
||||
if dsk_res != types.DRESULT.RES_OK:
|
||||
dsk_res = diskio.init(default_fs.pdrv)
|
||||
if dsk_res != types.DRESULT.RES_OK: return types.FRESULT.FR_NOT_READY
|
||||
default_fs.winsect = 0xFFFFFFFFFFFFFFFF
|
||||
default_fs.fat_winsect = 0xFFFFFFFFFFFFFFFF
|
||||
wres: types.FRESULT = default_fs.win_read(0)
|
||||
if wres != types.FRESULT.FR_OK: return types.FRESULT.FR_DISK_ERR
|
||||
bps: uint16 = default_fs.win[11] | (uint16(default_fs.win[12]) << 8)
|
||||
spc: uint8 = default_fs.win[13]
|
||||
rsc: uint16 = default_fs.win[14] | (uint16(default_fs.win[15]) << 8)
|
||||
nf: uint8 = default_fs.win[16]
|
||||
if bps != 512: return types.FRESULT.FR_NO_FILESYSTEM
|
||||
if spc == 0 or (spc & (spc - 1)) != 0: return types.FRESULT.FR_NO_FILESYSTEM
|
||||
if rsc == 0: return types.FRESULT.FR_NO_FILESYSTEM
|
||||
if nf == 0: return types.FRESULT.FR_NO_FILESYSTEM
|
||||
root_ent: uint16 = default_fs.win[17] | (uint16(default_fs.win[18]) << 8)
|
||||
fat16sz: uint16 = default_fs.win[22] | (uint16(default_fs.win[23]) << 8)
|
||||
tot32: uint32 = uint32(default_fs.win[32]) | (uint32(default_fs.win[33]) << 8) | (uint32(default_fs.win[34]) << 16) | (uint32(default_fs.win[35]) << 24)
|
||||
fat32sz: uint32 = uint32(default_fs.win[36]) | (uint32(default_fs.win[37]) << 8) | (uint32(default_fs.win[38]) << 16) | (uint32(default_fs.win[39]) << 24)
|
||||
root_clus: uint32 = uint32(default_fs.win[44]) | (uint32(default_fs.win[45]) << 8) | (uint32(default_fs.win[46]) << 16) | (uint32(default_fs.win[47]) << 24)
|
||||
if root_ent != 0 or fat16sz != 0: return types.FRESULT.FR_NO_FILESYSTEM
|
||||
if fat32sz == 0: return types.FRESULT.FR_NO_FILESYSTEM
|
||||
if tot32 == 0: return types.FRESULT.FR_NO_FILESYSTEM
|
||||
if default_fs.win[510] != 0x55 or default_fs.win[511] != 0xAA: return types.FRESULT.FR_NO_FILESYSTEM
|
||||
fsinfo_sec: uint16 = default_fs.win[48] | (uint16(default_fs.win[49]) << 8)
|
||||
bkboot_sec: uint16 = default_fs.win[50] | (uint16(default_fs.win[51]) << 8)
|
||||
default_fs.sector_size = 512
|
||||
default_fs.cluster_sectors = spc
|
||||
default_fs.cluster_size = uint32(spc) * 512
|
||||
default_fs.num_fats = nf
|
||||
default_fs.reserved_sectors = rsc
|
||||
default_fs.fat_size = fat32sz
|
||||
default_fs.fat_start = uint64(rsc)
|
||||
default_fs.total_sectors = uint64(tot32)
|
||||
default_fs.root_cluster = root_clus
|
||||
default_fs.fsinfo_sector = fsinfo_sec
|
||||
default_fs.backup_sector = bkboot_sec
|
||||
default_fs.vol_id = uint32(default_fs.win[67]) | (uint32(default_fs.win[68]) << 8) | (uint32(default_fs.win[69]) << 16) | (uint32(default_fs.win[70]) << 24)
|
||||
data_sectors: uint64 = default_fs.total_sectors - uint64(rsc) - uint64(uint64(nf) * uint64(fat32sz))
|
||||
default_fs.total_clusters = uint32(data_sectors / uint64(spc))
|
||||
default_fs.data_start = default_fs.fat_start + uint64(uint64(nf) * uint64(fat32sz))
|
||||
default_fs.last_alloc = 2
|
||||
default_fs.free_clusters = 0xFFFFFFFF
|
||||
if fsinfo_sec != 0:
|
||||
default_fs.fsinfo_read()
|
||||
default_fs.mounted = 1
|
||||
return types.FRESULT.FR_OK
|
||||
|
||||
def unmount() -> types.FRESULT:
|
||||
return default_fs.unmount()
|
||||
|
||||
def format(sec_per_clus: uint8 = 0, vol_id: uint32 = 0) -> types.FRESULT:
|
||||
return mkfs_mod.mkfs(default_fs.pdrv, sec_per_clus, vol_id)
|
||||
|
||||
def open(path: t.CConst | str, mode: uint8) -> types.fileobj | t.CPtr:
|
||||
return default_fs.file_open(path, mode)
|
||||
|
||||
def close(fp: types.fileobj | t.CPtr) -> types.FRESULT:
|
||||
return fp.close()
|
||||
|
||||
def read(fp: types.fileobj | t.CPtr, buff: t.CPtr, btr: uint32) -> uint32:
|
||||
br: uint32 = 0
|
||||
fp.read(buff, btr, c.Addr(br))
|
||||
# [RD2-DIAG] 确认 br 是否被 c.Set 写入(types 内 total_read=64 但外部可能收不到)
|
||||
_rd2: t.CArray[t.CChar, 96]
|
||||
viperlib.snprintf(c.Addr(_rd2), 96, "[fat32.vp] read br=%lu\n", br)
|
||||
serial.puts(c.Addr(_rd2))
|
||||
return br
|
||||
|
||||
def write(fp: types.fileobj | t.CPtr, buff: t.CConst | t.CPtr, btw: uint32) -> uint32:
|
||||
bw: uint32 = 0
|
||||
fp.write(buff, btw, c.Addr(bw))
|
||||
return bw
|
||||
|
||||
def seek(fp: types.fileobj | t.CPtr, offset: uint32) -> types.FRESULT:
|
||||
return fp.seek(offset)
|
||||
|
||||
def tell(fp: types.fileobj | t.CPtr) -> uint32:
|
||||
return fp.tell()
|
||||
|
||||
def size(fp: types.fileobj | t.CPtr) -> uint32:
|
||||
return fp.size()
|
||||
|
||||
def truncate(fp: types.fileobj | t.CPtr) -> types.FRESULT:
|
||||
return fp.truncate()
|
||||
|
||||
def remove(path: t.CConst | str) -> types.FRESULT:
|
||||
return default_fs.file_delete(path)
|
||||
|
||||
def rename(old_path: t.CConst | str, new_path: t.CConst | str) -> types.FRESULT:
|
||||
return default_fs.file_rename(old_path, new_path)
|
||||
|
||||
def move(old_path: t.CConst | str, new_path: t.CConst | str) -> types.FRESULT:
|
||||
return default_fs.file_rename(old_path, new_path)
|
||||
|
||||
def stat(path: t.CConst | str, info: types.fileinfo | t.CPtr) -> types.FRESULT:
|
||||
return default_fs.file_stat(path, info)
|
||||
|
||||
def mkdir(path: t.CConst | str) -> types.FRESULT:
|
||||
return default_fs.dir_make(path)
|
||||
|
||||
def rmdir(path: t.CConst | str) -> types.FRESULT:
|
||||
return default_fs.dir_remove(path)
|
||||
|
||||
def opendir(path: t.CConst | str, dp: types.dirobj | t.CPtr) -> types.FRESULT:
|
||||
return default_fs.dir_open_path(path, dp)
|
||||
|
||||
def readdir(dp: types.dirobj | t.CPtr, info: types.fileinfo | t.CPtr) -> types.FRESULT:
|
||||
return default_fs.dir_read(dp, info)
|
||||
|
||||
def closedir(dp: types.dirobj | t.CPtr):
|
||||
dp.is_open = 0
|
||||
|
||||
def chmod(path: t.CConst | str, attr: uint8, mask: uint8) -> types.FRESULT:
|
||||
return default_fs.chmod(path, attr, mask)
|
||||
|
||||
def utime(path: t.CConst | str, mtime: uint16, mdate: uint16) -> types.FRESULT:
|
||||
return default_fs.utime(path, mtime, mdate)
|
||||
|
||||
def get_free() -> uint32:
|
||||
if not default_fs.mounted: return 0
|
||||
if default_fs.free_clusters == 0xFFFFFFFF:
|
||||
return default_fs.count_free_clusters()
|
||||
return default_fs.free_clusters
|
||||
|
||||
def get_total() -> uint32:
|
||||
if not default_fs.mounted: return 0
|
||||
return default_fs.total_clusters
|
||||
|
||||
def get_cluster_size() -> uint32:
|
||||
if not default_fs.mounted: return 0
|
||||
return default_fs.cluster_size
|
||||
|
||||
def is_mounted() -> int:
|
||||
return default_fs.mounted
|
||||
|
||||
def last_error() -> uint32:
|
||||
return default_fs.last_error
|
||||
|
||||
def get_fattime() -> uint32:
|
||||
return ftime.get_fattime()
|
||||
|
||||
def get_metadata() -> uint32:
|
||||
return default_fs.metadata
|
||||
|
||||
def set_metadata(val: uint32):
|
||||
default_fs.metadata = val
|
||||
|
||||
def scan_drives() -> types.FRESULT:
|
||||
return part.scan_drives()
|
||||
|
||||
def get_drive_count() -> int:
|
||||
return part.get_drive_count()
|
||||
|
||||
def get_drive_letter(idx: int) -> t.CChar:
|
||||
return part.get_drive_letter(idx)
|
||||
|
||||
def set_drive_letter(idx: int, letter: t.CChar) -> types.FRESULT:
|
||||
return part.set_drive_letter(idx, letter)
|
||||
|
||||
def get_partition_count(letter: t.CChar) -> int:
|
||||
return part.get_partition_count(letter)
|
||||
|
||||
def is_partition_fat32(letter: t.CChar, part_idx: int) -> int:
|
||||
return part.is_partition_fat32(letter, part_idx)
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
from stdint import *
|
||||
import fat32_types as types
|
||||
import t, c
|
||||
|
||||
|
||||
_read32 = types._read32
|
||||
_read16 = types._read16
|
||||
_write32 = types._write32
|
||||
_write16 = types._write16
|
||||
|
||||
|
||||
def is_eoc(cluster: t.CUInt32T) -> t.CInt:
|
||||
return 1 if (cluster >= types.CLUSTER_EOC_MIN and cluster <= types.CLUSTER_EOC_MAX) else 0
|
||||
|
||||
def is_free(cluster: t.CUInt32T) -> t.CInt:
|
||||
return 1 if cluster == types.CLUSTER_FREE else 0
|
||||
from stdint import *
|
||||
import fat32_types as types
|
||||
import t, c
|
||||
|
||||
|
||||
_read32 = types._read32
|
||||
_read16 = types._read16
|
||||
_write32 = types._write32
|
||||
_write16 = types._write16
|
||||
|
||||
|
||||
def is_eoc(cluster: uint32) -> int:
|
||||
return 1 if (cluster >= types.CLUSTER_EOC_MIN and cluster <= types.CLUSTER_EOC_MAX) else 0
|
||||
|
||||
def is_free(cluster: uint32) -> int:
|
||||
return 1 if cluster == types.CLUSTER_FREE else 0
|
||||
@@ -1,81 +1,81 @@
|
||||
import drivers.storage.ide.ide as ide
|
||||
import fat32_types as types
|
||||
import spinlock
|
||||
import string
|
||||
import t, c
|
||||
|
||||
|
||||
MAX_DRIVES: t.CDefine = 4
|
||||
|
||||
drive_initialized: t.CArray[t.CInt, MAX_DRIVES]
|
||||
drive_lock: spinlock._spinlock = spinlock._spinlock()
|
||||
|
||||
def status(pdrv: t.CUInt8T) -> types.DRESULT:
|
||||
global drive_initialized
|
||||
if pdrv >= MAX_DRIVES: return types.DRESULT.RES_PARERR
|
||||
if not drive_initialized[pdrv]: return types.DRESULT.RES_NOTRDY
|
||||
return types.DRESULT.RES_OK
|
||||
|
||||
def init(pdrv: t.CUInt8T) -> types.DRESULT:
|
||||
global drive_lock, drive_initialized
|
||||
if pdrv >= MAX_DRIVES: return types.DRESULT.RES_PARERR
|
||||
drive_lock.lock()
|
||||
err: t.CInt = ide.init()
|
||||
if err != 0:
|
||||
drive_lock.unlock()
|
||||
return types.DRESULT.RES_NOTRDY
|
||||
drive_initialized[pdrv] = 1
|
||||
drive_lock.unlock()
|
||||
return types.DRESULT.RES_OK
|
||||
|
||||
def read(pdrv: t.CUInt8T, buff: t.CUInt8T | t.CPtr, sector: t.CUInt32T, count: t.CUInt32T) -> types.DRESULT:
|
||||
global drive_initialized, drive_lock
|
||||
if pdrv >= MAX_DRIVES: return types.DRESULT.RES_PARERR
|
||||
if not drive_initialized[pdrv]: return types.DRESULT.RES_NOTRDY
|
||||
drive_lock.lock()
|
||||
i: t.CUInt32T
|
||||
for i in range(count):
|
||||
rd_res: t.CInt = ide.readSector(sector + i, buff + (i * 512))
|
||||
if rd_res != 0:
|
||||
drive_lock.unlock()
|
||||
return types.DRESULT.RES_ERROR
|
||||
drive_lock.unlock()
|
||||
return types.DRESULT.RES_OK
|
||||
|
||||
def write(pdrv: t.CUInt8T, buff: t.CConst | t.CUInt8T | t.CPtr, sector: t.CUInt32T, count: t.CUInt32T) -> types.DRESULT:
|
||||
global drive_initialized, drive_lock
|
||||
if pdrv >= MAX_DRIVES: return types.DRESULT.RES_PARERR
|
||||
if not drive_initialized[pdrv]: return types.DRESULT.RES_NOTRDY
|
||||
drive_lock.lock()
|
||||
i: t.CUInt32T
|
||||
for i in range(count):
|
||||
if ide.writeSector(sector + i, buff + (i * 512)) != 0:
|
||||
drive_lock.unlock()
|
||||
return types.DRESULT.RES_ERROR
|
||||
drive_lock.unlock()
|
||||
return types.DRESULT.RES_OK
|
||||
|
||||
def ioctl(pdrv: t.CUInt8T, cmd: t.CUInt8T, buff: t.CVoid | t.CPtr) -> types.DRESULT:
|
||||
global drive_initialized
|
||||
if pdrv >= MAX_DRIVES: return types.DRESULT.RES_PARERR
|
||||
if not drive_initialized[pdrv]: return types.DRESULT.RES_NOTRDY
|
||||
match cmd:
|
||||
case types.GET_SECTOR_COUNT:
|
||||
disk_size: t.CUInt64T = ide.getDiskSize()
|
||||
if disk_size == 0:
|
||||
c.Set(c.Deref(t.CUInt32T(buff, t.CPtr)), 131072)
|
||||
elif disk_size > 0xFFFFFFFF:
|
||||
c.Set(c.Deref(t.CUInt32T(buff, t.CPtr)), 0xFFFFFFFF)
|
||||
else:
|
||||
c.Set(c.Deref(t.CUInt32T(buff, t.CPtr)), t.CUInt32T(disk_size))
|
||||
return types.DRESULT.RES_OK
|
||||
case types.GET_SECTOR_SIZE:
|
||||
c.Set(c.Deref(t.CUInt16T(buff, t.CPtr)), 512)
|
||||
return types.DRESULT.RES_OK
|
||||
case types.GET_BLOCK_SIZE:
|
||||
c.Set(c.Deref(t.CUInt32T(buff, t.CPtr)), 1)
|
||||
return types.DRESULT.RES_OK
|
||||
case types.CTRL_SYNC:
|
||||
return types.DRESULT.RES_OK
|
||||
case _:
|
||||
return types.DRESULT.RES_PARERR
|
||||
import drivers.storage.ide.ide as ide
|
||||
import fat32_types as types
|
||||
import spinlock
|
||||
import string
|
||||
import t, c
|
||||
|
||||
|
||||
MAX_DRIVES: t.CDefine = 4
|
||||
|
||||
drive_initialized: t.CArray[int, MAX_DRIVES]
|
||||
drive_lock: spinlock._spinlock = spinlock._spinlock()
|
||||
|
||||
def status(pdrv: uint8) -> types.DRESULT:
|
||||
global drive_initialized
|
||||
if pdrv >= MAX_DRIVES: return types.DRESULT.RES_PARERR
|
||||
if not drive_initialized[pdrv]: return types.DRESULT.RES_NOTRDY
|
||||
return types.DRESULT.RES_OK
|
||||
|
||||
def init(pdrv: uint8) -> types.DRESULT:
|
||||
global drive_lock, drive_initialized
|
||||
if pdrv >= MAX_DRIVES: return types.DRESULT.RES_PARERR
|
||||
drive_lock.lock()
|
||||
err: int = ide.init()
|
||||
if err != 0:
|
||||
drive_lock.unlock()
|
||||
return types.DRESULT.RES_NOTRDY
|
||||
drive_initialized[pdrv] = 1
|
||||
drive_lock.unlock()
|
||||
return types.DRESULT.RES_OK
|
||||
|
||||
def read(pdrv: uint8, buff: uint8 | t.CPtr, sector: uint32, count: uint32) -> types.DRESULT:
|
||||
global drive_initialized, drive_lock
|
||||
if pdrv >= MAX_DRIVES: return types.DRESULT.RES_PARERR
|
||||
if not drive_initialized[pdrv]: return types.DRESULT.RES_NOTRDY
|
||||
drive_lock.lock()
|
||||
i: uint32
|
||||
for i in range(count):
|
||||
rd_res: int = ide.readSector(sector + i, buff + (i * 512))
|
||||
if rd_res != 0:
|
||||
drive_lock.unlock()
|
||||
return types.DRESULT.RES_ERROR
|
||||
drive_lock.unlock()
|
||||
return types.DRESULT.RES_OK
|
||||
|
||||
def write(pdrv: uint8, buff: t.CConst | uint8 | t.CPtr, sector: uint32, count: uint32) -> types.DRESULT:
|
||||
global drive_initialized, drive_lock
|
||||
if pdrv >= MAX_DRIVES: return types.DRESULT.RES_PARERR
|
||||
if not drive_initialized[pdrv]: return types.DRESULT.RES_NOTRDY
|
||||
drive_lock.lock()
|
||||
i: uint32
|
||||
for i in range(count):
|
||||
if ide.writeSector(sector + i, buff + (i * 512)) != 0:
|
||||
drive_lock.unlock()
|
||||
return types.DRESULT.RES_ERROR
|
||||
drive_lock.unlock()
|
||||
return types.DRESULT.RES_OK
|
||||
|
||||
def ioctl(pdrv: uint8, cmd: uint8, buff: t.CPtr) -> types.DRESULT:
|
||||
global drive_initialized
|
||||
if pdrv >= MAX_DRIVES: return types.DRESULT.RES_PARERR
|
||||
if not drive_initialized[pdrv]: return types.DRESULT.RES_NOTRDY
|
||||
match cmd:
|
||||
case types.GET_SECTOR_COUNT:
|
||||
disk_size: uint64 = ide.getDiskSize()
|
||||
if disk_size == 0:
|
||||
c.Set(c.Deref(uint32(buff, t.CPtr)), 131072)
|
||||
elif disk_size > 0xFFFFFFFF:
|
||||
c.Set(c.Deref(uint32(buff, t.CPtr)), 0xFFFFFFFF)
|
||||
else:
|
||||
c.Set(c.Deref(uint32(buff, t.CPtr)), uint32(disk_size))
|
||||
return types.DRESULT.RES_OK
|
||||
case types.GET_SECTOR_SIZE:
|
||||
c.Set(c.Deref(uint16(buff, t.CPtr)), 512)
|
||||
return types.DRESULT.RES_OK
|
||||
case types.GET_BLOCK_SIZE:
|
||||
c.Set(c.Deref(uint32(buff, t.CPtr)), 1)
|
||||
return types.DRESULT.RES_OK
|
||||
case types.CTRL_SYNC:
|
||||
return types.DRESULT.RES_OK
|
||||
case _:
|
||||
return types.DRESULT.RES_PARERR
|
||||
@@ -1,143 +1,143 @@
|
||||
from stdint import *
|
||||
import fat32_types as types
|
||||
import fat32_diskio as diskio
|
||||
import fat32_time as ftime
|
||||
import string
|
||||
import t, c
|
||||
|
||||
|
||||
def _div_round_up(a: t.CUInt64T, b: t.CUInt64T) -> t.CUInt64T:
|
||||
return (a + b - 1) / b
|
||||
|
||||
def _calc_fat_size(total_sectors: t.CUInt64T, reserved: t.CUInt32T, sec_per_clus: t.CUInt8T, num_fats: t.CUInt8T) -> t.CUInt32T:
|
||||
tmp: t.CUInt64T = total_sectors - t.CUInt64T(reserved)
|
||||
fat_sz: t.CUInt32T = 1
|
||||
while True:
|
||||
data_sectors: t.CUInt64T = tmp - t.CUInt64T(fat_sz) * t.CUInt64T(num_fats)
|
||||
total_clusters: t.CUInt32T = t.CUInt32T(data_sectors / t.CUInt64T(sec_per_clus))
|
||||
needed: t.CUInt64T = _div_round_up(t.CUInt64T(total_clusters) * 4, 512)
|
||||
if needed <= t.CUInt64T(fat_sz): break
|
||||
fat_sz = t.CUInt32T(needed)
|
||||
return fat_sz
|
||||
|
||||
def _write_boot_sector(pdrv: t.CUInt8T, total_sectors: t.CUInt64T, sec_per_clus: t.CUInt8T, vol_id: t.CUInt32T, fat_sz: t.CUInt32T) -> types.DRESULT:
|
||||
buf: t.CArray[t.CUInt8T, 512]
|
||||
string.memset(c.Addr(buf[0]), 0, 512)
|
||||
buf[0] = 0xEB; buf[1] = 0x58; buf[2] = 0x90
|
||||
buf[3] = 'M'; buf[4] = 'S'; buf[5] = 'W'; buf[6] = 'I'; buf[7] = 'N'
|
||||
buf[8] = '4'; buf[9] = '.'; buf[10] = '1'
|
||||
types._write16(c.Addr(buf[0]), 11, 512)
|
||||
buf[13] = sec_per_clus
|
||||
types._write16(c.Addr(buf[0]), 14, 32)
|
||||
buf[16] = 2
|
||||
types._write16(c.Addr(buf[0]), 17, 0)
|
||||
buf[21] = 0xF8
|
||||
types._write16(c.Addr(buf[0]), 22, 0)
|
||||
types._write16(c.Addr(buf[0]), 24, 63)
|
||||
types._write16(c.Addr(buf[0]), 26, 255)
|
||||
types._write32(c.Addr(buf[0]), 28, 0)
|
||||
types._write32(c.Addr(buf[0]), 32, t.CUInt32T(total_sectors))
|
||||
types._write32(c.Addr(buf[0]), 36, fat_sz)
|
||||
types._write16(c.Addr(buf[0]), 40, 0)
|
||||
types._write16(c.Addr(buf[0]), 42, 0)
|
||||
types._write32(c.Addr(buf[0]), 44, 2)
|
||||
types._write16(c.Addr(buf[0]), 48, 1)
|
||||
types._write16(c.Addr(buf[0]), 50, 6)
|
||||
buf[64] = 0x80
|
||||
buf[66] = 0x29
|
||||
types._write32(c.Addr(buf[0]), 67, vol_id)
|
||||
vol_label: t.CArray[t.CChar, 11]
|
||||
vol_label[0] = 'N'; vol_label[1] = 'O'; vol_label[2] = ' '; vol_label[3] = ' '
|
||||
vol_label[4] = ' '; vol_label[5] = ' '; vol_label[6] = ' '; vol_label[7] = ' '
|
||||
vol_label[8] = ' '; vol_label[9] = ' '; vol_label[10] = ' '
|
||||
i: t.CInt
|
||||
for i in range(11): buf[71 + i] = t.CUInt8T(vol_label[i])
|
||||
buf[82] = 'F'; buf[83] = 'A'; buf[84] = 'T'; buf[85] = '3'
|
||||
buf[86] = '2'; buf[87] = ' '; buf[88] = ' '; buf[89] = ' '
|
||||
buf[510] = 0x55; buf[511] = 0xAA
|
||||
return diskio.write(pdrv, c.Addr(buf[0]), 0, 1)
|
||||
|
||||
def _write_fsinfo(pdrv: t.CUInt8T, free_count: t.CUInt32T, next_free: t.CUInt32T) -> types.DRESULT:
|
||||
buf: t.CArray[t.CUInt8T, 512]
|
||||
string.memset(c.Addr(buf[0]), 0, 512)
|
||||
types._write32(c.Addr(buf[0]), 0, 0x41615252)
|
||||
types._write32(c.Addr(buf[0]), 484, 0x61417272)
|
||||
types._write32(c.Addr(buf[0]), 488, free_count)
|
||||
types._write32(c.Addr(buf[0]), 492, next_free)
|
||||
types._write32(c.Addr(buf[0]), 508, 0xAA550000)
|
||||
return diskio.write(pdrv, c.Addr(buf[0]), 1, 1)
|
||||
|
||||
def _init_fat(pdrv: t.CUInt8T, fat_start: t.CUInt64T, fat_sz: t.CUInt32T, root_cluster: t.CUInt32T) -> types.DRESULT:
|
||||
buf: t.CArray[t.CUInt8T, 512]
|
||||
string.memset(c.Addr(buf[0]), 0, 512)
|
||||
types._write32(c.Addr(buf[0]), 0, 0x0FFFFFF8)
|
||||
types._write32(c.Addr(buf[0]), 4, 0x0FFFFFFF)
|
||||
types._write32(c.Addr(buf[0]), 8, 0x0FFFFFFF)
|
||||
if root_cluster >= 2:
|
||||
cluster_off: t.CUInt32T = root_cluster * 4
|
||||
sector_off: t.CUInt32T = cluster_off / 512
|
||||
byte_off: t.CUInt32T = cluster_off % 512
|
||||
if sector_off == 0:
|
||||
types._write32(c.Addr(buf[0]), byte_off, 0x0FFFFFFF)
|
||||
res: types.DRESULT = diskio.write(pdrv, c.Addr(buf[0]), t.CUInt32T(fat_start), 1)
|
||||
if res != types.DRESULT.RES_OK: return res
|
||||
string.memset(c.Addr(buf[0]), 0, 512)
|
||||
s: t.CUInt32T
|
||||
for s in range(1, fat_sz):
|
||||
res2: types.DRESULT = diskio.write(pdrv, c.Addr(buf[0]), t.CUInt32T(fat_start) + s, 1)
|
||||
if res2 != types.DRESULT.RES_OK: return res2
|
||||
return types.DRESULT.RES_OK
|
||||
|
||||
def _init_root_dir(pdrv: t.CUInt8T, root_sector: t.CUInt64T, sec_per_clus: t.CUInt8T) -> types.DRESULT:
|
||||
buf: t.CArray[t.CUInt8T, 512]
|
||||
string.memset(c.Addr(buf[0]), 0, 512)
|
||||
s: t.CUInt8T
|
||||
for s in range(sec_per_clus):
|
||||
res: types.DRESULT = diskio.write(pdrv, c.Addr(buf[0]), t.CUInt32T(root_sector + t.CUInt64T(s)), 1)
|
||||
if res != types.DRESULT.RES_OK: return res
|
||||
return types.DRESULT.RES_OK
|
||||
|
||||
def _calc_sec_per_clus(total_sectors: t.CUInt64T) -> t.CUInt8T:
|
||||
ts: t.CUInt64T = total_sectors
|
||||
if ts < 532480: return 1
|
||||
elif ts < 16777216: return 8
|
||||
elif ts < 33554432: return 16
|
||||
elif ts < 67108864: return 32
|
||||
else: return 64
|
||||
|
||||
def mkfs(pdrv: t.CUInt8T, sec_per_clus: t.CUInt8T, vol_id: t.CUInt32T) -> types.FRESULT:
|
||||
if pdrv != types.DEV_DISK: return types.FRESULT.FR_INVALID_DRIVE
|
||||
total_sectors_buf: t.CUInt32T = 0
|
||||
diskio.ioctl(pdrv, types.GET_SECTOR_COUNT, c.Addr(total_sectors_buf))
|
||||
total_sectors: t.CUInt64T = t.CUInt64T(total_sectors_buf)
|
||||
if total_sectors < 65536: return types.FRESULT.FR_MKFS_ABORTED
|
||||
if sec_per_clus == 0: sec_per_clus = _calc_sec_per_clus(total_sectors)
|
||||
if sec_per_clus != 1 and sec_per_clus != 2 and sec_per_clus != 4 and sec_per_clus != 8 and sec_per_clus != 16 and sec_per_clus != 32 and sec_per_clus != 64 and sec_per_clus != 128:
|
||||
return types.FRESULT.FR_INVALID_PARAMETER
|
||||
if vol_id == 0: vol_id = ftime.get_fattime()
|
||||
reserved: t.CUInt32T = 32
|
||||
num_fats: t.CUInt8T = 2
|
||||
fat_sz: t.CUInt32T = _calc_fat_size(total_sectors, reserved, sec_per_clus, num_fats)
|
||||
data_sectors: t.CUInt64T = total_sectors - t.CUInt64T(reserved) - t.CUInt64T(fat_sz) * t.CUInt64T(num_fats)
|
||||
total_clusters: t.CUInt32T = t.CUInt32T(data_sectors / t.CUInt64T(sec_per_clus))
|
||||
free_count: t.CUInt32T = total_clusters - 1
|
||||
res: types.DRESULT = _write_boot_sector(pdrv, total_sectors, sec_per_clus, vol_id, fat_sz)
|
||||
if res != types.DRESULT.RES_OK: return types.FRESULT.FR_DISK_ERR
|
||||
res2: types.DRESULT = _write_fsinfo(pdrv, free_count, 3)
|
||||
if res2 != types.DRESULT.RES_OK: return types.FRESULT.FR_DISK_ERR
|
||||
boot_backup: t.CArray[t.CUInt8T, 512]
|
||||
diskio.read(pdrv, c.Addr(boot_backup[0]), 0, 1)
|
||||
diskio.write(pdrv, c.Addr(boot_backup[0]), 6, 1)
|
||||
fsinfo_backup: t.CArray[t.CUInt8T, 512]
|
||||
diskio.read(pdrv, c.Addr(fsinfo_backup[0]), 1, 1)
|
||||
diskio.write(pdrv, c.Addr(fsinfo_backup[0]), 7, 1)
|
||||
fat_start: t.CUInt64T = t.CUInt64T(reserved)
|
||||
res3: types.DRESULT = _init_fat(pdrv, fat_start, fat_sz, 2)
|
||||
if res3 != types.DRESULT.RES_OK: return types.FRESULT.FR_DISK_ERR
|
||||
fat2_start: t.CUInt64T = fat_start + t.CUInt64T(fat_sz)
|
||||
res4: types.DRESULT = _init_fat(pdrv, fat2_start, fat_sz, 2)
|
||||
if res4 != types.DRESULT.RES_OK: return types.FRESULT.FR_DISK_ERR
|
||||
root_sector: t.CUInt64T = fat2_start + t.CUInt64T(fat_sz)
|
||||
res5: types.DRESULT = _init_root_dir(pdrv, root_sector, sec_per_clus)
|
||||
if res5 != types.DRESULT.RES_OK: return types.FRESULT.FR_DISK_ERR
|
||||
return types.FRESULT.FR_OK
|
||||
from stdint import *
|
||||
import fat32_types as types
|
||||
import fat32_diskio as diskio
|
||||
import fat32_time as ftime
|
||||
import string
|
||||
import t, c
|
||||
|
||||
|
||||
def _div_round_up(a: uint64, b: uint64) -> uint64:
|
||||
return (a + b - 1) / b
|
||||
|
||||
def _calc_fat_size(total_sectors: uint64, reserved: uint32, sec_per_clus: uint8, num_fats: uint8) -> uint32:
|
||||
tmp: uint64 = total_sectors - uint64(reserved)
|
||||
fat_sz: uint32 = 1
|
||||
while True:
|
||||
data_sectors: uint64 = tmp - uint64(fat_sz) * uint64(num_fats)
|
||||
total_clusters: uint32 = uint32(data_sectors / uint64(sec_per_clus))
|
||||
needed: uint64 = _div_round_up(uint64(total_clusters) * 4, 512)
|
||||
if needed <= uint64(fat_sz): break
|
||||
fat_sz = uint32(needed)
|
||||
return fat_sz
|
||||
|
||||
def _write_boot_sector(pdrv: uint8, total_sectors: uint64, sec_per_clus: uint8, vol_id: uint32, fat_sz: uint32) -> types.DRESULT:
|
||||
buf: t.CArray[uint8, 512]
|
||||
string.memset(c.Addr(buf[0]), 0, 512)
|
||||
buf[0] = 0xEB; buf[1] = 0x58; buf[2] = 0x90
|
||||
buf[3] = 'M'; buf[4] = 'S'; buf[5] = 'W'; buf[6] = 'I'; buf[7] = 'N'
|
||||
buf[8] = '4'; buf[9] = '.'; buf[10] = '1'
|
||||
types._write16(c.Addr(buf[0]), 11, 512)
|
||||
buf[13] = sec_per_clus
|
||||
types._write16(c.Addr(buf[0]), 14, 32)
|
||||
buf[16] = 2
|
||||
types._write16(c.Addr(buf[0]), 17, 0)
|
||||
buf[21] = 0xF8
|
||||
types._write16(c.Addr(buf[0]), 22, 0)
|
||||
types._write16(c.Addr(buf[0]), 24, 63)
|
||||
types._write16(c.Addr(buf[0]), 26, 255)
|
||||
types._write32(c.Addr(buf[0]), 28, 0)
|
||||
types._write32(c.Addr(buf[0]), 32, uint32(total_sectors))
|
||||
types._write32(c.Addr(buf[0]), 36, fat_sz)
|
||||
types._write16(c.Addr(buf[0]), 40, 0)
|
||||
types._write16(c.Addr(buf[0]), 42, 0)
|
||||
types._write32(c.Addr(buf[0]), 44, 2)
|
||||
types._write16(c.Addr(buf[0]), 48, 1)
|
||||
types._write16(c.Addr(buf[0]), 50, 6)
|
||||
buf[64] = 0x80
|
||||
buf[66] = 0x29
|
||||
types._write32(c.Addr(buf[0]), 67, vol_id)
|
||||
vol_label: t.CArray[t.CChar, 11]
|
||||
vol_label[0] = 'N'; vol_label[1] = 'O'; vol_label[2] = ' '; vol_label[3] = ' '
|
||||
vol_label[4] = ' '; vol_label[5] = ' '; vol_label[6] = ' '; vol_label[7] = ' '
|
||||
vol_label[8] = ' '; vol_label[9] = ' '; vol_label[10] = ' '
|
||||
i: int
|
||||
for i in range(11): buf[71 + i] = uint8(vol_label[i])
|
||||
buf[82] = 'F'; buf[83] = 'A'; buf[84] = 'T'; buf[85] = '3'
|
||||
buf[86] = '2'; buf[87] = ' '; buf[88] = ' '; buf[89] = ' '
|
||||
buf[510] = 0x55; buf[511] = 0xAA
|
||||
return diskio.write(pdrv, c.Addr(buf[0]), 0, 1)
|
||||
|
||||
def _write_fsinfo(pdrv: uint8, free_count: uint32, next_free: uint32) -> types.DRESULT:
|
||||
buf: t.CArray[uint8, 512]
|
||||
string.memset(c.Addr(buf[0]), 0, 512)
|
||||
types._write32(c.Addr(buf[0]), 0, 0x41615252)
|
||||
types._write32(c.Addr(buf[0]), 484, 0x61417272)
|
||||
types._write32(c.Addr(buf[0]), 488, free_count)
|
||||
types._write32(c.Addr(buf[0]), 492, next_free)
|
||||
types._write32(c.Addr(buf[0]), 508, 0xAA550000)
|
||||
return diskio.write(pdrv, c.Addr(buf[0]), 1, 1)
|
||||
|
||||
def _init_fat(pdrv: uint8, fat_start: uint64, fat_sz: uint32, root_cluster: uint32) -> types.DRESULT:
|
||||
buf: t.CArray[uint8, 512]
|
||||
string.memset(c.Addr(buf[0]), 0, 512)
|
||||
types._write32(c.Addr(buf[0]), 0, 0x0FFFFFF8)
|
||||
types._write32(c.Addr(buf[0]), 4, 0x0FFFFFFF)
|
||||
types._write32(c.Addr(buf[0]), 8, 0x0FFFFFFF)
|
||||
if root_cluster >= 2:
|
||||
cluster_off: uint32 = root_cluster * 4
|
||||
sector_off: uint32 = cluster_off / 512
|
||||
byte_off: uint32 = cluster_off % 512
|
||||
if sector_off == 0:
|
||||
types._write32(c.Addr(buf[0]), byte_off, 0x0FFFFFFF)
|
||||
res: types.DRESULT = diskio.write(pdrv, c.Addr(buf[0]), uint32(fat_start), 1)
|
||||
if res != types.DRESULT.RES_OK: return res
|
||||
string.memset(c.Addr(buf[0]), 0, 512)
|
||||
s: uint32
|
||||
for s in range(1, fat_sz):
|
||||
res2: types.DRESULT = diskio.write(pdrv, c.Addr(buf[0]), uint32(fat_start) + s, 1)
|
||||
if res2 != types.DRESULT.RES_OK: return res2
|
||||
return types.DRESULT.RES_OK
|
||||
|
||||
def _init_root_dir(pdrv: uint8, root_sector: uint64, sec_per_clus: uint8) -> types.DRESULT:
|
||||
buf: t.CArray[uint8, 512]
|
||||
string.memset(c.Addr(buf[0]), 0, 512)
|
||||
s: uint8
|
||||
for s in range(sec_per_clus):
|
||||
res: types.DRESULT = diskio.write(pdrv, c.Addr(buf[0]), uint32(root_sector + uint64(s)), 1)
|
||||
if res != types.DRESULT.RES_OK: return res
|
||||
return types.DRESULT.RES_OK
|
||||
|
||||
def _calc_sec_per_clus(total_sectors: uint64) -> uint8:
|
||||
ts: uint64 = total_sectors
|
||||
if ts < 532480: return 1
|
||||
elif ts < 16777216: return 8
|
||||
elif ts < 33554432: return 16
|
||||
elif ts < 67108864: return 32
|
||||
else: return 64
|
||||
|
||||
def mkfs(pdrv: uint8, sec_per_clus: uint8, vol_id: uint32) -> types.FRESULT:
|
||||
if pdrv != types.DEV_DISK: return types.FRESULT.FR_INVALID_DRIVE
|
||||
total_sectors_buf: uint32 = 0
|
||||
diskio.ioctl(pdrv, types.GET_SECTOR_COUNT, c.Addr(total_sectors_buf))
|
||||
total_sectors: uint64 = uint64(total_sectors_buf)
|
||||
if total_sectors < 65536: return types.FRESULT.FR_MKFS_ABORTED
|
||||
if sec_per_clus == 0: sec_per_clus = _calc_sec_per_clus(total_sectors)
|
||||
if sec_per_clus != 1 and sec_per_clus != 2 and sec_per_clus != 4 and sec_per_clus != 8 and sec_per_clus != 16 and sec_per_clus != 32 and sec_per_clus != 64 and sec_per_clus != 128:
|
||||
return types.FRESULT.FR_INVALID_PARAMETER
|
||||
if vol_id == 0: vol_id = ftime.get_fattime()
|
||||
reserved: uint32 = 32
|
||||
num_fats: uint8 = 2
|
||||
fat_sz: uint32 = _calc_fat_size(total_sectors, reserved, sec_per_clus, num_fats)
|
||||
data_sectors: uint64 = total_sectors - uint64(reserved) - uint64(fat_sz) * uint64(num_fats)
|
||||
total_clusters: uint32 = uint32(data_sectors / uint64(sec_per_clus))
|
||||
free_count: uint32 = total_clusters - 1
|
||||
res: types.DRESULT = _write_boot_sector(pdrv, total_sectors, sec_per_clus, vol_id, fat_sz)
|
||||
if res != types.DRESULT.RES_OK: return types.FRESULT.FR_DISK_ERR
|
||||
res2: types.DRESULT = _write_fsinfo(pdrv, free_count, 3)
|
||||
if res2 != types.DRESULT.RES_OK: return types.FRESULT.FR_DISK_ERR
|
||||
boot_backup: t.CArray[uint8, 512]
|
||||
diskio.read(pdrv, c.Addr(boot_backup[0]), 0, 1)
|
||||
diskio.write(pdrv, c.Addr(boot_backup[0]), 6, 1)
|
||||
fsinfo_backup: t.CArray[uint8, 512]
|
||||
diskio.read(pdrv, c.Addr(fsinfo_backup[0]), 1, 1)
|
||||
diskio.write(pdrv, c.Addr(fsinfo_backup[0]), 7, 1)
|
||||
fat_start: uint64 = uint64(reserved)
|
||||
res3: types.DRESULT = _init_fat(pdrv, fat_start, fat_sz, 2)
|
||||
if res3 != types.DRESULT.RES_OK: return types.FRESULT.FR_DISK_ERR
|
||||
fat2_start: uint64 = fat_start + uint64(fat_sz)
|
||||
res4: types.DRESULT = _init_fat(pdrv, fat2_start, fat_sz, 2)
|
||||
if res4 != types.DRESULT.RES_OK: return types.FRESULT.FR_DISK_ERR
|
||||
root_sector: uint64 = fat2_start + uint64(fat_sz)
|
||||
res5: types.DRESULT = _init_root_dir(pdrv, root_sector, sec_per_clus)
|
||||
if res5 != types.DRESULT.RES_OK: return types.FRESULT.FR_DISK_ERR
|
||||
return types.FRESULT.FR_OK
|
||||
@@ -1,153 +1,153 @@
|
||||
from stdint import *
|
||||
import fat32_types as types
|
||||
import fat32_diskio as diskio
|
||||
import string
|
||||
import t, c
|
||||
|
||||
|
||||
MAX_VOLUMES: t.CDefine = 4
|
||||
MAX_PARTITIONS: t.CDefine = 4
|
||||
|
||||
MBR_SIGNATURE: t.CDefine = 0xAA55
|
||||
PART_TYPE_FAT32: t.CDefine = 0x0C
|
||||
PART_TYPE_FAT32_LBA: t.CDefine = 0x0B
|
||||
PART_TYPE_FAT16: t.CDefine = 0x06
|
||||
PART_TYPE_FAT16_LBA: t.CDefine = 0x0E
|
||||
|
||||
class partition_entry:
|
||||
boot_flag: t.CUInt8T
|
||||
start_chs: t.CArray[t.CUInt8T, 3]
|
||||
part_type: t.CUInt8T
|
||||
end_chs: t.CArray[t.CUInt8T, 3]
|
||||
start_lba: t.CUInt32T
|
||||
total_sectors: t.CUInt32T
|
||||
|
||||
drive_pdrv: t.CArray[t.CUInt8T, MAX_VOLUMES]
|
||||
drive_num_parts: t.CArray[t.CInt, MAX_VOLUMES]
|
||||
drive_letter_map: t.CArray[t.CChar, MAX_VOLUMES]
|
||||
volume_mounted: t.CArray[t.CInt, MAX_VOLUMES]
|
||||
part_types: t.CArray[t.CUInt8T, MAX_VOLUMES * MAX_PARTITIONS]
|
||||
part_start_lbas: t.CArray[t.CUInt64T, MAX_VOLUMES * MAX_PARTITIONS]
|
||||
part_totals: t.CArray[t.CUInt64T, MAX_VOLUMES * MAX_PARTITIONS]
|
||||
part_is_fat32: t.CArray[t.CInt, MAX_VOLUMES * MAX_PARTITIONS]
|
||||
|
||||
num_drives: t.CInt = 0
|
||||
|
||||
def _init():
|
||||
global num_drives, drive_letter_map, volume_mounted, drive_pdrv, drive_num_parts
|
||||
global part_types, part_start_lbas, part_totals, part_is_fat32
|
||||
if num_drives > 0: return
|
||||
i: t.CInt
|
||||
for i in range(MAX_VOLUMES):
|
||||
drive_letter_map[i] = 0
|
||||
volume_mounted[i] = 0
|
||||
drive_pdrv[i] = 0
|
||||
drive_num_parts[i] = 0
|
||||
j: t.CInt
|
||||
for j in range(MAX_VOLUMES * MAX_PARTITIONS):
|
||||
part_types[j] = 0
|
||||
part_start_lbas[j] = 0
|
||||
part_totals[j] = 0
|
||||
part_is_fat32[j] = 0
|
||||
|
||||
def _part_idx(drive: t.CInt, part: t.CInt) -> t.CInt:
|
||||
return drive * MAX_PARTITIONS + part
|
||||
|
||||
def parse_mbr(pdrv: t.CUInt8T, drive_idx: t.CInt) -> types.FRESULT:
|
||||
global num_drives, drive_letter_map, volume_mounted, drive_pdrv, drive_num_parts
|
||||
global part_types, part_start_lbas, part_totals, part_is_fat32
|
||||
buf: t.CArray[t.CUInt8T, 512]
|
||||
res: types.DRESULT = diskio.read(pdrv, c.Addr(buf[0]), 0, 1)
|
||||
if res != types.DRESULT.RES_OK: return types.FRESULT.FR_DISK_ERR
|
||||
if buf[0] == 0xEB or buf[0] == 0xE9:
|
||||
return types.FRESULT.FR_NO_FILESYSTEM
|
||||
sig: t.CUInt16T = t.CUInt16T(buf[510]) | (t.CUInt16T(buf[511]) << 8)
|
||||
if sig != MBR_SIGNATURE: return types.FRESULT.FR_NO_FILESYSTEM
|
||||
drive_pdrv[drive_idx] = pdrv
|
||||
drive_num_parts[drive_idx] = 0
|
||||
i: t.CInt
|
||||
for i in range(4):
|
||||
base: t.CUInt32T = 446 + t.CUInt32T(i * 16)
|
||||
ptype: t.CUInt8T = buf[base + 4]
|
||||
slba: t.CUInt32T = t.CUInt32T(buf[base + 8]) | (t.CUInt32T(buf[base + 9]) << 8) | (t.CUInt32T(buf[base + 10]) << 16) | (t.CUInt32T(buf[base + 11]) << 24)
|
||||
tsec: t.CUInt32T = t.CUInt32T(buf[base + 12]) | (t.CUInt32T(buf[base + 13]) << 8) | (t.CUInt32T(buf[base + 14]) << 16) | (t.CUInt32T(buf[base + 15]) << 24)
|
||||
if ptype != 0 and tsec > 0:
|
||||
pi: t.CInt = drive_num_parts[drive_idx]
|
||||
if pi < MAX_PARTITIONS:
|
||||
pidx: t.CInt = _part_idx(drive_idx, pi)
|
||||
part_types[pidx] = ptype
|
||||
part_start_lbas[pidx] = t.CUInt64T(slba)
|
||||
part_totals[pidx] = t.CUInt64T(tsec)
|
||||
part_is_fat32[pidx] = 1 if (ptype == PART_TYPE_FAT32 or ptype == PART_TYPE_FAT32_LBA) else 0
|
||||
drive_num_parts[drive_idx] = pi + 1
|
||||
return types.FRESULT.FR_OK
|
||||
|
||||
def scan_drives() -> types.FRESULT:
|
||||
global num_drives, drive_letter_map, volume_mounted, drive_pdrv, drive_num_parts
|
||||
global part_types, part_start_lbas, part_totals, part_is_fat32
|
||||
_init()
|
||||
global num_drives
|
||||
num_drives = 0
|
||||
pdrv: t.CUInt8T
|
||||
for pdrv in range(MAX_VOLUMES):
|
||||
res: types.DRESULT = diskio.init(pdrv)
|
||||
if res != types.DRESULT.RES_OK: continue
|
||||
res2: types.FRESULT = parse_mbr(pdrv, num_drives)
|
||||
if res2 == types.FRESULT.FR_OK and drive_num_parts[num_drives] > 0:
|
||||
drive_letter_map[num_drives] = t.CChar(ord('C') + num_drives)
|
||||
else:
|
||||
drive_pdrv[num_drives] = pdrv
|
||||
drive_num_parts[num_drives] = 1
|
||||
pidx: t.CInt = _part_idx(num_drives, 0)
|
||||
part_types[pidx] = PART_TYPE_FAT32_LBA
|
||||
part_start_lbas[pidx] = 0
|
||||
part_totals[pidx] = 0
|
||||
part_is_fat32[pidx] = 1
|
||||
drive_letter_map[num_drives] = t.CChar(ord('C') + num_drives)
|
||||
num_drives = num_drives + 1
|
||||
if num_drives >= MAX_VOLUMES: break
|
||||
return types.FRESULT.FR_OK
|
||||
|
||||
def get_drive(letter: t.CChar) -> t.CInt:
|
||||
_init()
|
||||
i: t.CInt
|
||||
for i in range(num_drives):
|
||||
if drive_letter_map[i] == letter or drive_letter_map[i] == (letter - 32) or drive_letter_map[i] == (letter + 32):
|
||||
return i
|
||||
return -1
|
||||
|
||||
def get_pdrv(letter: t.CChar) -> t.CUInt8T:
|
||||
idx: t.CInt = get_drive(letter)
|
||||
if idx < 0: return 0
|
||||
return drive_pdrv[idx]
|
||||
|
||||
def get_partition_start(letter: t.CChar, part_idx: t.CInt) -> t.CUInt64T:
|
||||
idx: t.CInt = get_drive(letter)
|
||||
if idx < 0: return 0
|
||||
if part_idx >= drive_num_parts[idx]: return 0
|
||||
pidx: t.CInt = _part_idx(idx, part_idx)
|
||||
return part_start_lbas[pidx]
|
||||
|
||||
def get_partition_count(letter: t.CChar) -> t.CInt:
|
||||
idx: t.CInt = get_drive(letter)
|
||||
if idx < 0: return 0
|
||||
return drive_num_parts[idx]
|
||||
|
||||
def is_partition_fat32(letter: t.CChar, part_idx: t.CInt) -> t.CInt:
|
||||
idx: t.CInt = get_drive(letter)
|
||||
if idx < 0: return 0
|
||||
if part_idx >= drive_num_parts[idx]: return 0
|
||||
pidx: t.CInt = _part_idx(idx, part_idx)
|
||||
return part_is_fat32[pidx]
|
||||
|
||||
def get_drive_count() -> t.CInt:
|
||||
return num_drives
|
||||
|
||||
def get_drive_letter(idx: t.CInt) -> t.CChar:
|
||||
if idx < 0 or idx >= num_drives: return 0
|
||||
return drive_letter_map[idx]
|
||||
|
||||
def set_drive_letter(idx: t.CInt, letter: t.CChar) -> types.FRESULT:
|
||||
if idx < 0 or idx >= num_drives: return types.FRESULT.FR_INVALID_PARAMETER
|
||||
drive_letter_map[idx] = letter
|
||||
return types.FRESULT.FR_OK
|
||||
from stdint import *
|
||||
import fat32_types as types
|
||||
import fat32_diskio as diskio
|
||||
import string
|
||||
import t, c
|
||||
|
||||
|
||||
MAX_VOLUMES: t.CDefine = 4
|
||||
MAX_PARTITIONS: t.CDefine = 4
|
||||
|
||||
MBR_SIGNATURE: t.CDefine = 0xAA55
|
||||
PART_TYPE_FAT32: t.CDefine = 0x0C
|
||||
PART_TYPE_FAT32_LBA: t.CDefine = 0x0B
|
||||
PART_TYPE_FAT16: t.CDefine = 0x06
|
||||
PART_TYPE_FAT16_LBA: t.CDefine = 0x0E
|
||||
|
||||
class partition_entry:
|
||||
boot_flag: uint8
|
||||
start_chs: t.CArray[uint8, 3]
|
||||
part_type: uint8
|
||||
end_chs: t.CArray[uint8, 3]
|
||||
start_lba: uint32
|
||||
total_sectors: uint32
|
||||
|
||||
drive_pdrv: t.CArray[uint8, MAX_VOLUMES]
|
||||
drive_num_parts: t.CArray[int, MAX_VOLUMES]
|
||||
drive_letter_map: t.CArray[t.CChar, MAX_VOLUMES]
|
||||
volume_mounted: t.CArray[int, MAX_VOLUMES]
|
||||
part_types: t.CArray[uint8, MAX_VOLUMES * MAX_PARTITIONS]
|
||||
part_start_lbas: t.CArray[uint64, MAX_VOLUMES * MAX_PARTITIONS]
|
||||
part_totals: t.CArray[uint64, MAX_VOLUMES * MAX_PARTITIONS]
|
||||
part_is_fat32: t.CArray[int, MAX_VOLUMES * MAX_PARTITIONS]
|
||||
|
||||
num_drives: int = 0
|
||||
|
||||
def _init():
|
||||
global num_drives, drive_letter_map, volume_mounted, drive_pdrv, drive_num_parts
|
||||
global part_types, part_start_lbas, part_totals, part_is_fat32
|
||||
if num_drives > 0: return
|
||||
i: int
|
||||
for i in range(MAX_VOLUMES):
|
||||
drive_letter_map[i] = 0
|
||||
volume_mounted[i] = 0
|
||||
drive_pdrv[i] = 0
|
||||
drive_num_parts[i] = 0
|
||||
j: int
|
||||
for j in range(MAX_VOLUMES * MAX_PARTITIONS):
|
||||
part_types[j] = 0
|
||||
part_start_lbas[j] = 0
|
||||
part_totals[j] = 0
|
||||
part_is_fat32[j] = 0
|
||||
|
||||
def _part_idx(drive: int, part: int) -> int:
|
||||
return drive * MAX_PARTITIONS + part
|
||||
|
||||
def parse_mbr(pdrv: uint8, drive_idx: int) -> types.FRESULT:
|
||||
global num_drives, drive_letter_map, volume_mounted, drive_pdrv, drive_num_parts
|
||||
global part_types, part_start_lbas, part_totals, part_is_fat32
|
||||
buf: t.CArray[uint8, 512]
|
||||
res: types.DRESULT = diskio.read(pdrv, c.Addr(buf[0]), 0, 1)
|
||||
if res != types.DRESULT.RES_OK: return types.FRESULT.FR_DISK_ERR
|
||||
if buf[0] == 0xEB or buf[0] == 0xE9:
|
||||
return types.FRESULT.FR_NO_FILESYSTEM
|
||||
sig: uint16 = uint16(buf[510]) | (uint16(buf[511]) << 8)
|
||||
if sig != MBR_SIGNATURE: return types.FRESULT.FR_NO_FILESYSTEM
|
||||
drive_pdrv[drive_idx] = pdrv
|
||||
drive_num_parts[drive_idx] = 0
|
||||
i: int
|
||||
for i in range(4):
|
||||
base: uint32 = 446 + uint32(i * 16)
|
||||
ptype: uint8 = buf[base + 4]
|
||||
slba: uint32 = uint32(buf[base + 8]) | (uint32(buf[base + 9]) << 8) | (uint32(buf[base + 10]) << 16) | (uint32(buf[base + 11]) << 24)
|
||||
tsec: uint32 = uint32(buf[base + 12]) | (uint32(buf[base + 13]) << 8) | (uint32(buf[base + 14]) << 16) | (uint32(buf[base + 15]) << 24)
|
||||
if ptype != 0 and tsec > 0:
|
||||
pi: int = drive_num_parts[drive_idx]
|
||||
if pi < MAX_PARTITIONS:
|
||||
pidx: int = _part_idx(drive_idx, pi)
|
||||
part_types[pidx] = ptype
|
||||
part_start_lbas[pidx] = uint64(slba)
|
||||
part_totals[pidx] = uint64(tsec)
|
||||
part_is_fat32[pidx] = 1 if (ptype == PART_TYPE_FAT32 or ptype == PART_TYPE_FAT32_LBA) else 0
|
||||
drive_num_parts[drive_idx] = pi + 1
|
||||
return types.FRESULT.FR_OK
|
||||
|
||||
def scan_drives() -> types.FRESULT:
|
||||
global num_drives, drive_letter_map, volume_mounted, drive_pdrv, drive_num_parts
|
||||
global part_types, part_start_lbas, part_totals, part_is_fat32
|
||||
_init()
|
||||
global num_drives
|
||||
num_drives = 0
|
||||
pdrv: uint8
|
||||
for pdrv in range(MAX_VOLUMES):
|
||||
res: types.DRESULT = diskio.init(pdrv)
|
||||
if res != types.DRESULT.RES_OK: continue
|
||||
res2: types.FRESULT = parse_mbr(pdrv, num_drives)
|
||||
if res2 == types.FRESULT.FR_OK and drive_num_parts[num_drives] > 0:
|
||||
drive_letter_map[num_drives] = t.CChar(ord('C') + num_drives)
|
||||
else:
|
||||
drive_pdrv[num_drives] = pdrv
|
||||
drive_num_parts[num_drives] = 1
|
||||
pidx: int = _part_idx(num_drives, 0)
|
||||
part_types[pidx] = PART_TYPE_FAT32_LBA
|
||||
part_start_lbas[pidx] = 0
|
||||
part_totals[pidx] = 0
|
||||
part_is_fat32[pidx] = 1
|
||||
drive_letter_map[num_drives] = t.CChar(ord('C') + num_drives)
|
||||
num_drives = num_drives + 1
|
||||
if num_drives >= MAX_VOLUMES: break
|
||||
return types.FRESULT.FR_OK
|
||||
|
||||
def get_drive(letter: t.CChar) -> int:
|
||||
_init()
|
||||
i: int
|
||||
for i in range(num_drives):
|
||||
if drive_letter_map[i] == letter or drive_letter_map[i] == (letter - 32) or drive_letter_map[i] == (letter + 32):
|
||||
return i
|
||||
return -1
|
||||
|
||||
def get_pdrv(letter: t.CChar) -> uint8:
|
||||
idx: int = get_drive(letter)
|
||||
if idx < 0: return 0
|
||||
return drive_pdrv[idx]
|
||||
|
||||
def get_partition_start(letter: t.CChar, part_idx: int) -> uint64:
|
||||
idx: int = get_drive(letter)
|
||||
if idx < 0: return 0
|
||||
if part_idx >= drive_num_parts[idx]: return 0
|
||||
pidx: int = _part_idx(idx, part_idx)
|
||||
return part_start_lbas[pidx]
|
||||
|
||||
def get_partition_count(letter: t.CChar) -> int:
|
||||
idx: int = get_drive(letter)
|
||||
if idx < 0: return 0
|
||||
return drive_num_parts[idx]
|
||||
|
||||
def is_partition_fat32(letter: t.CChar, part_idx: int) -> int:
|
||||
idx: int = get_drive(letter)
|
||||
if idx < 0: return 0
|
||||
if part_idx >= drive_num_parts[idx]: return 0
|
||||
pidx: int = _part_idx(idx, part_idx)
|
||||
return part_is_fat32[pidx]
|
||||
|
||||
def get_drive_count() -> int:
|
||||
return num_drives
|
||||
|
||||
def get_drive_letter(idx: int) -> t.CChar:
|
||||
if idx < 0 or idx >= num_drives: return 0
|
||||
return drive_letter_map[idx]
|
||||
|
||||
def set_drive_letter(idx: int, letter: t.CChar) -> types.FRESULT:
|
||||
if idx < 0 or idx >= num_drives: return types.FRESULT.FR_INVALID_PARAMETER
|
||||
drive_letter_map[idx] = letter
|
||||
return types.FRESULT.FR_OK
|
||||
@@ -1,64 +1,64 @@
|
||||
from stdint import *
|
||||
import t, c
|
||||
import asm
|
||||
|
||||
|
||||
rtc_cmos_addr: t.CUInt16T = 0x70
|
||||
rtc_cmos_data: t.CUInt16T = 0x71
|
||||
|
||||
def cmos_read(reg: t.CUInt8T) -> t.CUInt8T:
|
||||
asm.outb(rtc_cmos_addr, reg)
|
||||
return asm.inb(rtc_cmos_data)
|
||||
|
||||
def bcd_to_bin(bcd: t.CUInt8T) -> t.CUInt8T:
|
||||
return (bcd >> 4) * 10 + (bcd & 0x0F)
|
||||
|
||||
def get_rtc_time() -> t.CUInt32T:
|
||||
while cmos_read(0x0A) & 0x80: pass
|
||||
sec: t.CUInt8T = cmos_read(0x00)
|
||||
min_: t.CUInt8T = cmos_read(0x02)
|
||||
hour: t.CUInt8T = cmos_read(0x04)
|
||||
day: t.CUInt8T = cmos_read(0x07)
|
||||
mon: t.CUInt8T = cmos_read(0x08)
|
||||
year: t.CUInt8T = cmos_read(0x09)
|
||||
reg_b: t.CUInt8T = cmos_read(0x0B)
|
||||
if not (reg_b & 0x04):
|
||||
sec = bcd_to_bin(sec)
|
||||
min_ = bcd_to_bin(min_)
|
||||
hour = bcd_to_bin(hour)
|
||||
day = bcd_to_bin(day)
|
||||
mon = bcd_to_bin(mon)
|
||||
year = bcd_to_bin(year)
|
||||
fat_year: t.CUInt16T = t.CUInt16T(year) + 2000 - 1980
|
||||
if fat_year > 127: fat_year = 127
|
||||
fat_date: t.CUInt16T = (fat_year << 9) | (t.CUInt16T(mon) << 5) | t.CUInt16T(day)
|
||||
fat_time: t.CUInt16T = (t.CUInt16T(hour) << 11) | (t.CUInt16T(min_) << 5) | (t.CUInt16T(sec) / 2)
|
||||
return (t.CUInt32T(fat_date) << 16) | t.CUInt32T(fat_time)
|
||||
|
||||
def get_fattime() -> t.CUInt32T:
|
||||
return get_rtc_time()
|
||||
|
||||
def to_year(ft: t.CUInt32T) -> t.CUInt16T:
|
||||
return t.CUInt16T((ft >> 25) & 0x7F) + 1980
|
||||
|
||||
def to_month(ft: t.CUInt32T) -> t.CUInt8T:
|
||||
return t.CUInt8T((ft >> 21) & 0x0F)
|
||||
|
||||
def to_day(ft: t.CUInt32T) -> t.CUInt8T:
|
||||
return t.CUInt8T((ft >> 16) & 0x1F)
|
||||
|
||||
def to_hour(ft: t.CUInt32T) -> t.CUInt8T:
|
||||
return t.CUInt8T((ft >> 11) & 0x1F)
|
||||
|
||||
def to_minute(ft: t.CUInt32T) -> t.CUInt8T:
|
||||
return t.CUInt8T((ft >> 5) & 0x3F)
|
||||
|
||||
def to_second(ft: t.CUInt32T) -> t.CUInt8T:
|
||||
return t.CUInt8T((ft & 0x1F) * 2)
|
||||
|
||||
def make(year: t.CUInt16T, month: t.CUInt8T, day: t.CUInt8T, hour: t.CUInt8T, minute: t.CUInt8T, second: t.CUInt8T) -> t.CUInt32T:
|
||||
fat_year: t.CUInt16T = year - 1980
|
||||
if fat_year > 127: fat_year = 127
|
||||
fat_date: t.CUInt16T = (fat_year << 9) | (t.CUInt16T(month) << 5) | t.CUInt16T(day)
|
||||
fat_time: t.CUInt16T = (t.CUInt16T(hour) << 11) | (t.CUInt16T(minute) << 5) | (t.CUInt16T(second) / 2)
|
||||
return (t.CUInt32T(fat_date) << 16) | t.CUInt32T(fat_time)
|
||||
from stdint import *
|
||||
import t, c
|
||||
import asm
|
||||
|
||||
|
||||
rtc_cmos_addr: uint16 = 0x70
|
||||
rtc_cmos_data: uint16 = 0x71
|
||||
|
||||
def cmos_read(reg: uint8) -> uint8:
|
||||
asm.outb(rtc_cmos_addr, reg)
|
||||
return asm.inb(rtc_cmos_data)
|
||||
|
||||
def bcd_to_bin(bcd: uint8) -> uint8:
|
||||
return (bcd >> 4) * 10 + (bcd & 0x0F)
|
||||
|
||||
def get_rtc_time() -> uint32:
|
||||
while cmos_read(0x0A) & 0x80: pass
|
||||
sec: uint8 = cmos_read(0x00)
|
||||
min_: uint8 = cmos_read(0x02)
|
||||
hour: uint8 = cmos_read(0x04)
|
||||
day: uint8 = cmos_read(0x07)
|
||||
mon: uint8 = cmos_read(0x08)
|
||||
year: uint8 = cmos_read(0x09)
|
||||
reg_b: uint8 = cmos_read(0x0B)
|
||||
if not (reg_b & 0x04):
|
||||
sec = bcd_to_bin(sec)
|
||||
min_ = bcd_to_bin(min_)
|
||||
hour = bcd_to_bin(hour)
|
||||
day = bcd_to_bin(day)
|
||||
mon = bcd_to_bin(mon)
|
||||
year = bcd_to_bin(year)
|
||||
fat_year: uint16 = uint16(year) + 2000 - 1980
|
||||
if fat_year > 127: fat_year = 127
|
||||
fat_date: uint16 = (fat_year << 9) | (uint16(mon) << 5) | uint16(day)
|
||||
fat_time: uint16 = (uint16(hour) << 11) | (uint16(min_) << 5) | (uint16(sec) / 2)
|
||||
return (uint32(fat_date) << 16) | uint32(fat_time)
|
||||
|
||||
def get_fattime() -> uint32:
|
||||
return get_rtc_time()
|
||||
|
||||
def to_year(ft: uint32) -> uint16:
|
||||
return uint16((ft >> 25) & 0x7F) + 1980
|
||||
|
||||
def to_month(ft: uint32) -> uint8:
|
||||
return uint8((ft >> 21) & 0x0F)
|
||||
|
||||
def to_day(ft: uint32) -> uint8:
|
||||
return uint8((ft >> 16) & 0x1F)
|
||||
|
||||
def to_hour(ft: uint32) -> uint8:
|
||||
return uint8((ft >> 11) & 0x1F)
|
||||
|
||||
def to_minute(ft: uint32) -> uint8:
|
||||
return uint8((ft >> 5) & 0x3F)
|
||||
|
||||
def to_second(ft: uint32) -> uint8:
|
||||
return uint8((ft & 0x1F) * 2)
|
||||
|
||||
def make(year: uint16, month: uint8, day: uint8, hour: uint8, minute: uint8, second: uint8) -> uint32:
|
||||
fat_year: uint16 = year - 1980
|
||||
if fat_year > 127: fat_year = 127
|
||||
fat_date: uint16 = (fat_year << 9) | (uint16(month) << 5) | uint16(day)
|
||||
fat_time: uint16 = (uint16(hour) << 11) | (uint16(minute) << 5) | (uint16(second) / 2)
|
||||
return (uint32(fat_date) << 16) | uint32(fat_time)
|
||||
File diff suppressed because it is too large.
Load diff
@@ -1,148 +1,148 @@
|
||||
import asm
|
||||
import intr.idt as idt
|
||||
import drivers.serial.uart.serial as serial
|
||||
import viperstring as string
|
||||
import t, c
|
||||
|
||||
|
||||
KBD_DATA: t.CDefine = 0x60
|
||||
KBD_STATUS: t.CDefine = 0x64
|
||||
KBD_COMMAND: t.CDefine = 0x64
|
||||
|
||||
KBD_BUF_SIZE: t.CDefine = 1024
|
||||
|
||||
KEY_RELEASED: t.CDefine = 0x80
|
||||
|
||||
buffer: t.CArray[t.CUInt8T, KBD_BUF_SIZE]
|
||||
buf_head: t.CStatic | t.CUInt32T = 0
|
||||
buf_tail: t.CStatic | t.CUInt32T = 0
|
||||
buf_count: t.CStatic | t.CUInt32T = 0
|
||||
kbd_irq_cnt: t.CStatic | t.CUInt64T = 0
|
||||
|
||||
shift_l: t.CStatic | t.CUInt8T = 0
|
||||
shift_r: t.CStatic | t.CUInt8T = 0
|
||||
ctrl_l: t.CStatic | t.CUInt8T = 0
|
||||
alt_l: t.CStatic | t.CUInt8T = 0
|
||||
caps_lock: t.CStatic | t.CUInt8T = 0
|
||||
|
||||
scancode_set1: t.CArray[t.CChar, 128] = [
|
||||
'\0', '\x1b', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '-', '=', '\b',
|
||||
'\t', 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p', '[', ']', '\n',
|
||||
'\0', 'a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';', "'", '`', '\0',
|
||||
'\\', 'z', 'x', 'c', 'v', 'b', 'n', 'm', ',', '.', '/', '\0', '\0', '\0', ' ',
|
||||
'\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '-', '8', '6', '2', '\0',
|
||||
'1', '+', '4', '5', '3', '0', '.', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0',
|
||||
'\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0',
|
||||
'\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0',
|
||||
'\0'
|
||||
]
|
||||
|
||||
scancode_set1_shift: t.CArray[t.CChar, 128] = [
|
||||
'\0', '\x1b', '!', '@', '#', '$', '%', '^', '&', '*', '(', ')', '_', '+', '\b',
|
||||
'\t', 'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I', 'O', 'P', '{', '}', '\n',
|
||||
'\0', 'A', 'S', 'D', 'F', 'G', 'H', 'J', 'K', 'L', ':', '"', '~', '\0',
|
||||
'|', 'Z', 'X', 'C', 'V', 'B', 'N', 'M', '<', '>', '?', '\0', '\0', '\0', ' ',
|
||||
'\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '-', '8', '6', '2', '\0',
|
||||
'1', '+', '4', '5', '3', '0', '.', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0',
|
||||
'\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0',
|
||||
'\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0',
|
||||
'\0'
|
||||
]
|
||||
|
||||
def _wait_read():
|
||||
timeout: t.CUInt32T = 100000
|
||||
while timeout > 0:
|
||||
if (asm.inb(KBD_STATUS) & 0x01) != 0: return
|
||||
timeout -= 1
|
||||
|
||||
def _wait_write():
|
||||
timeout: t.CUInt32T = 100000
|
||||
while timeout > 0:
|
||||
if (asm.inb(KBD_STATUS) & 0x02) == 0: return
|
||||
timeout -= 1
|
||||
|
||||
def irq_handler() -> t.CInt:
|
||||
global buf_head, buf_tail, buf_count, kbd_irq_cnt
|
||||
kbd_irq_cnt += 1
|
||||
scancode: t.CUInt8T = asm.inb(KBD_DATA)
|
||||
if buf_count < KBD_BUF_SIZE:
|
||||
buffer[buf_tail] = scancode
|
||||
buf_tail = buf_tail + 1
|
||||
if buf_tail >= KBD_BUF_SIZE:
|
||||
buf_tail = 0
|
||||
buf_count += 1
|
||||
return 0
|
||||
|
||||
def read_scancode() -> t.CUInt8T:
|
||||
global buf_head, buf_count
|
||||
asm.cli()
|
||||
if buf_count == 0:
|
||||
asm.sti()
|
||||
return 0
|
||||
code: t.CUInt8T = buffer[buf_head]
|
||||
buf_head = buf_head + 1
|
||||
if buf_head >= KBD_BUF_SIZE:
|
||||
buf_head = 0
|
||||
buf_count -= 1
|
||||
asm.sti()
|
||||
return code
|
||||
|
||||
def scancode_to_ascii(scancode: t.CUInt8T) -> t.CChar:
|
||||
code: t.CUInt8T = scancode & ~t.CUInt8T(KEY_RELEASED)
|
||||
if code >= 128: return '\0'
|
||||
shifted: bool = (shift_l or shift_r) != 0
|
||||
if caps_lock and code >= 0x10 and code <= 0x32:
|
||||
shifted = not shifted
|
||||
if shifted:
|
||||
return scancode_set1_shift[code]
|
||||
return scancode_set1[code]
|
||||
|
||||
def has_data() -> t.CInt:
|
||||
return buf_count
|
||||
|
||||
def init():
|
||||
drain: t.CUInt32T
|
||||
drain = 0
|
||||
while (asm.inb(KBD_STATUS) & 0x01) != 0:
|
||||
asm.inb(KBD_DATA)
|
||||
drain += 1
|
||||
if drain > 1000: break
|
||||
|
||||
_wait_write()
|
||||
asm.outb(KBD_COMMAND, 0xAD)
|
||||
|
||||
drain = 0
|
||||
while (asm.inb(KBD_STATUS) & 0x01) != 0:
|
||||
asm.inb(KBD_DATA)
|
||||
drain += 1
|
||||
if drain > 1000: break
|
||||
|
||||
_wait_write()
|
||||
asm.outb(KBD_COMMAND, 0x20)
|
||||
_wait_read()
|
||||
ccb: t.CUInt8T = asm.inb(KBD_DATA)
|
||||
|
||||
ccb = ccb | 0x01
|
||||
ccb = ccb | 0x40
|
||||
ccb = ccb & 0xEF
|
||||
|
||||
_wait_write()
|
||||
asm.outb(KBD_COMMAND, 0x60)
|
||||
_wait_write()
|
||||
asm.outb(KBD_DATA, ccb)
|
||||
|
||||
_wait_write()
|
||||
asm.outb(KBD_COMMAND, 0xAE)
|
||||
|
||||
drain = 0
|
||||
while (asm.inb(KBD_STATUS) & 0x01) != 0:
|
||||
asm.inb(KBD_DATA)
|
||||
drain += 1
|
||||
if drain > 1000: break
|
||||
|
||||
_wait_write()
|
||||
asm.outb(KBD_DATA, 0xF4)
|
||||
_wait_read()
|
||||
asm.inb(KBD_DATA)
|
||||
|
||||
idt.irqInstallHandler(1, irq_handler, "keyboard")
|
||||
import asm
|
||||
import intr.idt as idt
|
||||
import drivers.serial.uart.serial as serial
|
||||
import viperstring as string
|
||||
import t, c
|
||||
|
||||
|
||||
KBD_DATA: t.CDefine = 0x60
|
||||
KBD_STATUS: t.CDefine = 0x64
|
||||
KBD_COMMAND: t.CDefine = 0x64
|
||||
|
||||
KBD_BUF_SIZE: t.CDefine = 1024
|
||||
|
||||
KEY_RELEASED: t.CDefine = 0x80
|
||||
|
||||
buffer: t.CArray[uint8, KBD_BUF_SIZE]
|
||||
buf_head: t.CStatic | uint32 = 0
|
||||
buf_tail: t.CStatic | uint32 = 0
|
||||
buf_count: t.CStatic | uint32 = 0
|
||||
kbd_irq_cnt: t.CStatic | uint64 = 0
|
||||
|
||||
shift_l: t.CStatic | uint8 = 0
|
||||
shift_r: t.CStatic | uint8 = 0
|
||||
ctrl_l: t.CStatic | uint8 = 0
|
||||
alt_l: t.CStatic | uint8 = 0
|
||||
caps_lock: t.CStatic | uint8 = 0
|
||||
|
||||
scancode_set1: t.CArray[t.CChar, 128] = [
|
||||
'\0', '\x1b', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '-', '=', '\b',
|
||||
'\t', 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p', '[', ']', '\n',
|
||||
'\0', 'a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';', "'", '`', '\0',
|
||||
'\\', 'z', 'x', 'c', 'v', 'b', 'n', 'm', ',', '.', '/', '\0', '\0', '\0', ' ',
|
||||
'\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '-', '8', '6', '2', '\0',
|
||||
'1', '+', '4', '5', '3', '0', '.', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0',
|
||||
'\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0',
|
||||
'\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0',
|
||||
'\0'
|
||||
]
|
||||
|
||||
scancode_set1_shift: t.CArray[t.CChar, 128] = [
|
||||
'\0', '\x1b', '!', '@', '#', '$', '%', '^', '&', '*', '(', ')', '_', '+', '\b',
|
||||
'\t', 'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I', 'O', 'P', '{', '}', '\n',
|
||||
'\0', 'A', 'S', 'D', 'F', 'G', 'H', 'J', 'K', 'L', ':', '"', '~', '\0',
|
||||
'|', 'Z', 'X', 'C', 'V', 'B', 'N', 'M', '<', '>', '?', '\0', '\0', '\0', ' ',
|
||||
'\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '-', '8', '6', '2', '\0',
|
||||
'1', '+', '4', '5', '3', '0', '.', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0',
|
||||
'\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0',
|
||||
'\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0',
|
||||
'\0'
|
||||
]
|
||||
|
||||
def _wait_read():
|
||||
timeout: uint32 = 100000
|
||||
while timeout > 0:
|
||||
if (asm.inb(KBD_STATUS) & 0x01) != 0: return
|
||||
timeout -= 1
|
||||
|
||||
def _wait_write():
|
||||
timeout: uint32 = 100000
|
||||
while timeout > 0:
|
||||
if (asm.inb(KBD_STATUS) & 0x02) == 0: return
|
||||
timeout -= 1
|
||||
|
||||
def irq_handler() -> int:
|
||||
global buf_head, buf_tail, buf_count, kbd_irq_cnt
|
||||
kbd_irq_cnt += 1
|
||||
scancode: uint8 = asm.inb(KBD_DATA)
|
||||
if buf_count < KBD_BUF_SIZE:
|
||||
buffer[buf_tail] = scancode
|
||||
buf_tail = buf_tail + 1
|
||||
if buf_tail >= KBD_BUF_SIZE:
|
||||
buf_tail = 0
|
||||
buf_count += 1
|
||||
return 0
|
||||
|
||||
def read_scancode() -> uint8:
|
||||
global buf_head, buf_count
|
||||
asm.cli()
|
||||
if buf_count == 0:
|
||||
asm.sti()
|
||||
return 0
|
||||
code: uint8 = buffer[buf_head]
|
||||
buf_head = buf_head + 1
|
||||
if buf_head >= KBD_BUF_SIZE:
|
||||
buf_head = 0
|
||||
buf_count -= 1
|
||||
asm.sti()
|
||||
return code
|
||||
|
||||
def scancode_to_ascii(scancode: uint8) -> t.CChar:
|
||||
code: uint8 = scancode & ~uint8(KEY_RELEASED)
|
||||
if code >= 128: return '\0'
|
||||
shifted: bool = (shift_l or shift_r) != 0
|
||||
if caps_lock and code >= 0x10 and code <= 0x32:
|
||||
shifted = not shifted
|
||||
if shifted:
|
||||
return scancode_set1_shift[code]
|
||||
return scancode_set1[code]
|
||||
|
||||
def has_data() -> int:
|
||||
return buf_count
|
||||
|
||||
def init():
|
||||
drain: uint32
|
||||
drain = 0
|
||||
while (asm.inb(KBD_STATUS) & 0x01) != 0:
|
||||
asm.inb(KBD_DATA)
|
||||
drain += 1
|
||||
if drain > 1000: break
|
||||
|
||||
_wait_write()
|
||||
asm.outb(KBD_COMMAND, 0xAD)
|
||||
|
||||
drain = 0
|
||||
while (asm.inb(KBD_STATUS) & 0x01) != 0:
|
||||
asm.inb(KBD_DATA)
|
||||
drain += 1
|
||||
if drain > 1000: break
|
||||
|
||||
_wait_write()
|
||||
asm.outb(KBD_COMMAND, 0x20)
|
||||
_wait_read()
|
||||
ccb: uint8 = asm.inb(KBD_DATA)
|
||||
|
||||
ccb = ccb | 0x01
|
||||
ccb = ccb | 0x40
|
||||
ccb = ccb & 0xEF
|
||||
|
||||
_wait_write()
|
||||
asm.outb(KBD_COMMAND, 0x60)
|
||||
_wait_write()
|
||||
asm.outb(KBD_DATA, ccb)
|
||||
|
||||
_wait_write()
|
||||
asm.outb(KBD_COMMAND, 0xAE)
|
||||
|
||||
drain = 0
|
||||
while (asm.inb(KBD_STATUS) & 0x01) != 0:
|
||||
asm.inb(KBD_DATA)
|
||||
drain += 1
|
||||
if drain > 1000: break
|
||||
|
||||
_wait_write()
|
||||
asm.outb(KBD_DATA, 0xF4)
|
||||
_wait_read()
|
||||
asm.inb(KBD_DATA)
|
||||
|
||||
idt.irqInstallHandler(1, irq_handler, "keyboard")
|
||||
@@ -1,136 +1,136 @@
|
||||
import asm
|
||||
import intr.idt as idt
|
||||
import platform.pch.pic as pic
|
||||
import drivers.serial.uart.serial as serial
|
||||
import t, c
|
||||
|
||||
|
||||
MOUSE_DATA: t.CDefine = 0x60
|
||||
MOUSE_STATUS: t.CDefine = 0x64
|
||||
MOUSE_COMMAND: t.CDefine = 0x64
|
||||
|
||||
MOUSE_BUF_SIZE: t.CDefine = 1024
|
||||
|
||||
MOUSE_LEFT: t.CDefine = 0x01
|
||||
MOUSE_RIGHT: t.CDefine = 0x02
|
||||
MOUSE_MIDDLE: t.CDefine = 0x04
|
||||
|
||||
class mouse_packet:
|
||||
flags: t.CUInt8T
|
||||
dx: t.CInt8T
|
||||
dy: t.CInt8T
|
||||
buttons: t.CUInt8T
|
||||
|
||||
packets: t.CArray[mouse_packet, MOUSE_BUF_SIZE]
|
||||
pack_head: t.CStatic | t.CUInt32T = 0
|
||||
pack_tail: t.CStatic | t.CUInt32T = 0
|
||||
pack_count: t.CStatic | t.CUInt32T = 0
|
||||
mse_irq_cnt: t.CStatic | t.CUInt64T = 0
|
||||
|
||||
cycle: t.CStatic | t.CUInt8T = 0
|
||||
byte1: t.CStatic | t.CUInt8T = 0
|
||||
byte2: t.CStatic | t.CInt8T = 0
|
||||
byte3: t.CStatic | t.CInt8T = 0
|
||||
|
||||
mouse_x: t.CStatic | t.CInt32T = 0
|
||||
mouse_y: t.CStatic | t.CInt32T = 0
|
||||
mouse_buttons: t.CStatic | t.CUInt8T = 0
|
||||
|
||||
def _wait_read():
|
||||
timeout: t.CUInt32T = 100000
|
||||
while timeout > 0:
|
||||
if (asm.inb(MOUSE_STATUS) & 0x01) != 0: return
|
||||
timeout -= 1
|
||||
|
||||
def _wait_write():
|
||||
timeout: t.CUInt32T = 100000
|
||||
while timeout > 0:
|
||||
if (asm.inb(MOUSE_STATUS) & 0x02) == 0: return
|
||||
timeout -= 1
|
||||
|
||||
def _write_cmd(cmd: t.CUInt8T):
|
||||
_wait_write()
|
||||
asm.outb(MOUSE_COMMAND, 0xD4)
|
||||
_wait_write()
|
||||
asm.outb(MOUSE_DATA, cmd)
|
||||
_wait_read()
|
||||
asm.inb(MOUSE_DATA)
|
||||
|
||||
def irq_handler() -> t.CInt:
|
||||
global cycle, byte1, byte2, byte3, pack_tail, pack_count, mse_irq_cnt
|
||||
mse_irq_cnt += 1
|
||||
status: t.CUInt8T = asm.inb(MOUSE_STATUS)
|
||||
if (status & 0x20) == 0: return 0
|
||||
data: t.CUInt8T = asm.inb(MOUSE_DATA)
|
||||
if cycle == 0:
|
||||
if (data & 0x08) != 0:
|
||||
byte1 = data
|
||||
cycle = 1
|
||||
return 0
|
||||
if cycle == 1:
|
||||
byte2 = data
|
||||
cycle = 2
|
||||
return 0
|
||||
byte3 = data
|
||||
cycle = 0
|
||||
if pack_count < MOUSE_BUF_SIZE:
|
||||
packets[pack_tail].flags = byte1
|
||||
packets[pack_tail].dx = byte2
|
||||
packets[pack_tail].dy = byte3
|
||||
packets[pack_tail].buttons = byte1 & t.CUInt8T(0x07)
|
||||
pack_tail = pack_tail + 1
|
||||
if pack_tail >= MOUSE_BUF_SIZE:
|
||||
pack_tail = 0
|
||||
pack_count += 1
|
||||
return 0
|
||||
|
||||
def read_packet(out: mouse_packet | t.CPtr) -> t.CInt:
|
||||
global pack_head, pack_count
|
||||
asm.cli()
|
||||
if pack_count == 0:
|
||||
asm.sti()
|
||||
out.flags = 0
|
||||
out.dx = 0
|
||||
out.dy = 0
|
||||
out.buttons = 0
|
||||
return -1
|
||||
out.flags = packets[pack_head].flags
|
||||
out.dx = packets[pack_head].dx
|
||||
out.dy = packets[pack_head].dy
|
||||
out.buttons = packets[pack_head].buttons
|
||||
pack_head = pack_head + 1
|
||||
if pack_head >= MOUSE_BUF_SIZE:
|
||||
pack_head = 0
|
||||
pack_count -= 1
|
||||
asm.sti()
|
||||
return 0
|
||||
|
||||
def has_data() -> t.CInt:
|
||||
return pack_count
|
||||
|
||||
def get_x() -> t.CInt32T:
|
||||
return mouse_x
|
||||
|
||||
def get_y() -> t.CInt32T:
|
||||
return mouse_y
|
||||
|
||||
def get_buttons() -> t.CUInt8T:
|
||||
return mouse_buttons
|
||||
|
||||
def init():
|
||||
_wait_write()
|
||||
asm.outb(MOUSE_COMMAND, 0xA8)
|
||||
_wait_write()
|
||||
asm.outb(MOUSE_COMMAND, 0x20)
|
||||
_wait_read()
|
||||
status: t.CUInt8T = asm.inb(MOUSE_DATA)
|
||||
status = status | 0x02
|
||||
status = status & 0xDF
|
||||
_wait_write()
|
||||
asm.outb(MOUSE_COMMAND, 0x60)
|
||||
_wait_write()
|
||||
asm.outb(MOUSE_DATA, status)
|
||||
_write_cmd(0xF6)
|
||||
_write_cmd(0xF4)
|
||||
pic.clearMask(12)
|
||||
idt.irqInstallHandler(12, irq_handler, "mouse")
|
||||
import asm
|
||||
import intr.idt as idt
|
||||
import platform.pch.pic as pic
|
||||
import drivers.serial.uart.serial as serial
|
||||
import t, c
|
||||
|
||||
|
||||
MOUSE_DATA: t.CDefine = 0x60
|
||||
MOUSE_STATUS: t.CDefine = 0x64
|
||||
MOUSE_COMMAND: t.CDefine = 0x64
|
||||
|
||||
MOUSE_BUF_SIZE: t.CDefine = 1024
|
||||
|
||||
MOUSE_LEFT: t.CDefine = 0x01
|
||||
MOUSE_RIGHT: t.CDefine = 0x02
|
||||
MOUSE_MIDDLE: t.CDefine = 0x04
|
||||
|
||||
class mouse_packet:
|
||||
flags: uint8
|
||||
dx: int8
|
||||
dy: int8
|
||||
buttons: uint8
|
||||
|
||||
packets: t.CArray[mouse_packet, MOUSE_BUF_SIZE]
|
||||
pack_head: t.CStatic | uint32 = 0
|
||||
pack_tail: t.CStatic | uint32 = 0
|
||||
pack_count: t.CStatic | uint32 = 0
|
||||
mse_irq_cnt: t.CStatic | uint64 = 0
|
||||
|
||||
cycle: t.CStatic | uint8 = 0
|
||||
byte1: t.CStatic | uint8 = 0
|
||||
byte2: t.CStatic | int8 = 0
|
||||
byte3: t.CStatic | int8 = 0
|
||||
|
||||
mouse_x: t.CStatic | int32 = 0
|
||||
mouse_y: t.CStatic | int32 = 0
|
||||
mouse_buttons: t.CStatic | uint8 = 0
|
||||
|
||||
def _wait_read():
|
||||
timeout: uint32 = 100000
|
||||
while timeout > 0:
|
||||
if (asm.inb(MOUSE_STATUS) & 0x01) != 0: return
|
||||
timeout -= 1
|
||||
|
||||
def _wait_write():
|
||||
timeout: uint32 = 100000
|
||||
while timeout > 0:
|
||||
if (asm.inb(MOUSE_STATUS) & 0x02) == 0: return
|
||||
timeout -= 1
|
||||
|
||||
def _write_cmd(cmd: uint8):
|
||||
_wait_write()
|
||||
asm.outb(MOUSE_COMMAND, 0xD4)
|
||||
_wait_write()
|
||||
asm.outb(MOUSE_DATA, cmd)
|
||||
_wait_read()
|
||||
asm.inb(MOUSE_DATA)
|
||||
|
||||
def irq_handler() -> int:
|
||||
global cycle, byte1, byte2, byte3, pack_tail, pack_count, mse_irq_cnt
|
||||
mse_irq_cnt += 1
|
||||
status: uint8 = asm.inb(MOUSE_STATUS)
|
||||
if (status & 0x20) == 0: return 0
|
||||
data: uint8 = asm.inb(MOUSE_DATA)
|
||||
if cycle == 0:
|
||||
if (data & 0x08) != 0:
|
||||
byte1 = data
|
||||
cycle = 1
|
||||
return 0
|
||||
if cycle == 1:
|
||||
byte2 = data
|
||||
cycle = 2
|
||||
return 0
|
||||
byte3 = data
|
||||
cycle = 0
|
||||
if pack_count < MOUSE_BUF_SIZE:
|
||||
packets[pack_tail].flags = byte1
|
||||
packets[pack_tail].dx = byte2
|
||||
packets[pack_tail].dy = byte3
|
||||
packets[pack_tail].buttons = byte1 & uint8(0x07)
|
||||
pack_tail = pack_tail + 1
|
||||
if pack_tail >= MOUSE_BUF_SIZE:
|
||||
pack_tail = 0
|
||||
pack_count += 1
|
||||
return 0
|
||||
|
||||
def read_packet(out: mouse_packet | t.CPtr) -> int:
|
||||
global pack_head, pack_count
|
||||
asm.cli()
|
||||
if pack_count == 0:
|
||||
asm.sti()
|
||||
out.flags = 0
|
||||
out.dx = 0
|
||||
out.dy = 0
|
||||
out.buttons = 0
|
||||
return -1
|
||||
out.flags = packets[pack_head].flags
|
||||
out.dx = packets[pack_head].dx
|
||||
out.dy = packets[pack_head].dy
|
||||
out.buttons = packets[pack_head].buttons
|
||||
pack_head = pack_head + 1
|
||||
if pack_head >= MOUSE_BUF_SIZE:
|
||||
pack_head = 0
|
||||
pack_count -= 1
|
||||
asm.sti()
|
||||
return 0
|
||||
|
||||
def has_data() -> int:
|
||||
return pack_count
|
||||
|
||||
def get_x() -> int32:
|
||||
return mouse_x
|
||||
|
||||
def get_y() -> int32:
|
||||
return mouse_y
|
||||
|
||||
def get_buttons() -> uint8:
|
||||
return mouse_buttons
|
||||
|
||||
def init():
|
||||
_wait_write()
|
||||
asm.outb(MOUSE_COMMAND, 0xA8)
|
||||
_wait_write()
|
||||
asm.outb(MOUSE_COMMAND, 0x20)
|
||||
_wait_read()
|
||||
status: uint8 = asm.inb(MOUSE_DATA)
|
||||
status = status | 0x02
|
||||
status = status & 0xDF
|
||||
_wait_write()
|
||||
asm.outb(MOUSE_COMMAND, 0x60)
|
||||
_wait_write()
|
||||
asm.outb(MOUSE_DATA, status)
|
||||
_write_cmd(0xF6)
|
||||
_write_cmd(0xF4)
|
||||
pic.clearMask(12)
|
||||
idt.irqInstallHandler(12, irq_handler, "mouse")
|
||||
@@ -30,15 +30,15 @@ def puts(s: str):
|
||||
putchar(i)
|
||||
|
||||
# 检查COM1是否有数据可读
|
||||
def isDataAvailable() -> t.CInt:
|
||||
def isDataAvailable() -> int:
|
||||
return su8250.isDataAvailable(su8250.COM1_PORT)
|
||||
|
||||
# 检查COM1发送缓冲区是否为空
|
||||
def isTransmitEmpty() -> t.CInt:
|
||||
def isTransmitEmpty() -> int:
|
||||
return su8250.isTransmitEmpty(su8250.COM1_PORT)
|
||||
|
||||
# 发送32位十六进制值到COM1
|
||||
def put_hex32(value: t.CUInt32T):
|
||||
def put_hex32(value: uint32):
|
||||
hex_digits: t.CArray[t.CChar, None] = ["0123456789ABCDEF"]
|
||||
buffer: t.CArray[t.CChar, 9]
|
||||
for i in range(7, -1, -1):
|
||||
@@ -51,24 +51,24 @@ def put_hex32(value: t.CUInt32T):
|
||||
# 格式化输出到串口(printf 实现,覆盖 libc printf 的裸机缺失)
|
||||
# 内部复用 viperlib.vsnprintf 格式化到栈缓冲,再逐字符送串口。
|
||||
# print(...) 内建映射到 @printf(stdio extern),此定义提供裸机实现。
|
||||
def printf(fmt: t.CConst | str, *args) -> t.CInt | t.CExport:
|
||||
def printf(fmt: t.CConst | str, *args) -> int | t.CExport:
|
||||
if fmt is None:
|
||||
return 0
|
||||
buf: t.CArray[t.CChar, 1024]
|
||||
n: t.CInt = viperlib.vsnprintf(c.Addr(buf), 1024, fmt, args)
|
||||
n: int = viperlib.vsnprintf(c.Addr(buf), 1024, fmt, args)
|
||||
puts(buf)
|
||||
return n
|
||||
|
||||
|
||||
# 刷新输出流:串口是无缓冲直写(putchar 直接写 UART 端口),flush 即空操作。
|
||||
# 覆盖 libc fflush 的裸机缺失(memhub 的诊断/终止路径 call @fflush)。
|
||||
def fflush(stream: t.CConst | t.CVoid | t.CPtr) -> t.CInt | t.CExport:
|
||||
def fflush(stream: t.CConst | t.CPtr) -> int | t.CExport:
|
||||
return 0
|
||||
|
||||
|
||||
# 系统退出:触发硬件关机(QEMU ACPI/Bochs 关机端口),失败则停机兜底。
|
||||
# 覆盖 libc exit 的裸机缺失(memhub 等致命错误路径 call @exit)。
|
||||
def exit(status: int) -> t.CInt | t.CExport:
|
||||
def exit(status: int) -> int | t.CExport:
|
||||
asm.outw(0x604, 0x2000) # QEMU ACPI 关机
|
||||
asm.outw(0xB004, 0x2000) # Bochs/QEMU 备用端口
|
||||
while True:
|
||||
|
||||
@@ -40,7 +40,7 @@ BAUD_115200: t.CDefine = 1
|
||||
|
||||
|
||||
# 初始化UART 8250/16550
|
||||
def init(port: t.CUInt16T):
|
||||
def init(port: uint16):
|
||||
# 1. 禁用中断
|
||||
asm.outb(port + UART_IER, 0x00)
|
||||
delay(1000)
|
||||
@@ -69,18 +69,18 @@ def init(port: t.CUInt16T):
|
||||
delay(10000)
|
||||
|
||||
# 延迟函数
|
||||
def delay(count: t.CInt):
|
||||
def delay(count: int):
|
||||
for i in range(count): c.Asm("nop")
|
||||
|
||||
# 检查发送缓冲区是否为空
|
||||
def isTransmitEmpty(port: t.CUInt16T) -> t.CInt:
|
||||
def isTransmitEmpty(port: uint16) -> int:
|
||||
return asm.inb(port + UART_LSR) & UART_LSR_THRE
|
||||
|
||||
def putchar(port: t.CUInt16T, cr: t.CChar):
|
||||
def putchar(port: uint16, cr: t.CChar):
|
||||
# 1. 处理换行符:串口终端需要\r\n才会正确换行,只发\n会错位
|
||||
if cr == '\n':
|
||||
# 直接发送\r,避免递归调用
|
||||
timeout: t.CUInt32T = 1000000
|
||||
timeout: uint32 = 1000000
|
||||
while ((asm.inb(port + UART_LSR) & UART_LSR_THRE) == 0) and timeout:
|
||||
c.Asm("nop")
|
||||
timeout -= 1
|
||||
@@ -91,7 +91,7 @@ def putchar(port: t.CUInt16T, cr: t.CChar):
|
||||
c.Asm("nop")
|
||||
timeout -= 1
|
||||
# 2. 等待发送缓冲区为空
|
||||
timeout: t.CUInt32T = 1000000
|
||||
timeout: uint32 = 1000000
|
||||
while ((asm.inb(port + UART_LSR) & UART_LSR_THRE) == 0) and timeout:
|
||||
c.Asm("nop")
|
||||
timeout -= 1
|
||||
@@ -105,11 +105,11 @@ def putchar(port: t.CUInt16T, cr: t.CChar):
|
||||
timeout -= 1
|
||||
|
||||
# 检查是否有数据可读
|
||||
def isDataAvailable(port: t.CUInt16T) -> t.CInt:
|
||||
def isDataAvailable(port: uint16) -> int:
|
||||
return asm.inb(port + UART_LSR) & UART_LSR_DR
|
||||
|
||||
# 读取一个字符
|
||||
def getchar(port: t.CUInt16T) -> t.CChar:
|
||||
def getchar(port: uint16) -> t.CChar:
|
||||
# 等待数据可用
|
||||
while not isDataAvailable(port): pass
|
||||
# 读取字符
|
||||
|
||||
@@ -29,12 +29,12 @@ IDE_STATUS_ERR: t.CDefine = 0x01
|
||||
|
||||
SECTOR_SIZE: t.CDefine = 512
|
||||
|
||||
_ide_initialized: t.CInt = 0
|
||||
_ide_initialized: int = 0
|
||||
|
||||
def waitReady(baseport: t.CUInt16T) -> t.CStatic | IDError:
|
||||
timeout: t.CInt = 100000
|
||||
def waitReady(baseport: uint16) -> t.CStatic | IDError:
|
||||
timeout: int = 100000
|
||||
while timeout > 0:
|
||||
status: t.CUInt8T = asm.inb(baseport + 7)
|
||||
status: uint8 = asm.inb(baseport + 7)
|
||||
if status & IDE_STATUS_DF:
|
||||
return IDError.IDE_ERR_DEVICE_FAILURE
|
||||
if not status & IDE_STATUS_BSY and status & IDE_STATUS_DRDY:
|
||||
@@ -42,10 +42,10 @@ def waitReady(baseport: t.CUInt16T) -> t.CStatic | IDError:
|
||||
timeout -= 1
|
||||
return IDError.IDE_ERR_TIMEOUT
|
||||
|
||||
def waitDataReady(baseport: t.CUInt16T) -> t.CStatic | IDError:
|
||||
timeout: t.CInt = 100000
|
||||
def waitDataReady(baseport: uint16) -> t.CStatic | IDError:
|
||||
timeout: int = 100000
|
||||
while timeout > 0:
|
||||
status: t.CUInt8T = asm.inb(baseport + 7)
|
||||
status: uint8 = asm.inb(baseport + 7)
|
||||
if status & IDE_STATUS_ERR: return IDError.IDE_ERR_DEVICE_ERROR
|
||||
if status & IDE_STATUS_DF: return IDError.IDE_ERR_DEVICE_FAILURE
|
||||
if not status & IDE_STATUS_BSY and (status & IDE_STATUS_DRQ or status & IDE_STATUS_DRDY):
|
||||
@@ -53,110 +53,112 @@ def waitDataReady(baseport: t.CUInt16T) -> t.CStatic | IDError:
|
||||
timeout -= 1
|
||||
return IDError.IDE_ERR_TIMEOUT
|
||||
|
||||
def init() -> t.CInt:
|
||||
def init() -> int:
|
||||
global _ide_initialized
|
||||
if _ide_initialized: return IDError.IDE_ERR_NONE
|
||||
dbg: t.CArray[t.CChar, 120]
|
||||
bus: t.CUInt8T
|
||||
dev_n: t.CUInt8T
|
||||
func: t.CUInt8T
|
||||
bus: uint8
|
||||
dev_n: uint8
|
||||
func: uint8
|
||||
for bus in range(2):
|
||||
for dev_n in range(32):
|
||||
for func in range(8):
|
||||
vendor: t.CUInt16T = pci.pci_read16(bus, dev_n, func, 0x00)
|
||||
vendor: uint16 = pci.pci_read16(bus, dev_n, func, 0x00)
|
||||
if vendor == 0xFFFF: continue
|
||||
cls: t.CUInt32T = pci.pci_get_class(bus, dev_n, func)
|
||||
cls: uint32 = pci.pci_get_class(bus, dev_n, func)
|
||||
if cls == 0x010180 or cls == 0x0101:
|
||||
cmd: t.CUInt16T = pci.pci_read16(bus, dev_n, func, 0x04)
|
||||
pci.pci_write32(bus, dev_n, func, 0x04, t.CUInt32T(cmd | 0x0007))
|
||||
viperlib.snprintf(c.Addr(dbg), 120, "[ide] found at %d:%d:%d cmd=0x%04x\n", t.CInt(bus), t.CInt(dev_n), t.CInt(func), t.CUInt32T(pci.pci_read16(bus, dev_n, func, 0x04)))
|
||||
cmd: uint16 = pci.pci_read16(bus, dev_n, func, 0x04)
|
||||
pci.pci_write32(bus, dev_n, func, 0x04, uint32(cmd | 0x0007))
|
||||
viperlib.snprintf(c.Addr(dbg), 120, "[ide] found at %d:%d:%d cmd=0x%04x\n", int(bus), int(dev_n), int(func), uint32(pci.pci_read16(bus, dev_n, func, 0x04)))
|
||||
serial.puts(dbg)
|
||||
asm.outb(0x3F6, 0x04)
|
||||
i: t.CInt
|
||||
i: int
|
||||
for i in range(10000):
|
||||
asm.nop()
|
||||
asm.outb(0x3F6, 0x00)
|
||||
for i in range(10000):
|
||||
asm.nop()
|
||||
status: t.CUInt8T = asm.inb(0x1F7)
|
||||
viperlib.snprintf(c.Addr(dbg), 120, "[ide] status=0x%02x\n", t.CUInt32T(status))
|
||||
status: uint8 = asm.inb(0x1F7)
|
||||
viperlib.snprintf(c.Addr(dbg), 120, "[ide] status=0x%02x\n", uint32(status))
|
||||
serial.puts(dbg)
|
||||
_ide_initialized = 1
|
||||
return IDError.IDE_ERR_NONE
|
||||
|
||||
def readSector(lba: t.CUInt32T, buffer: t.CVoid | t.CPtr) -> t.CInt:
|
||||
def readSector(lba: uint32, buffer: t.CPtr) -> int:
|
||||
if buffer is None: return IDError.IDE_ERR_BUFFER_NULL
|
||||
dbg: t.CArray[t.CChar, 120]
|
||||
err: IDError = waitReady(IDE_baseport_PRIMARY)
|
||||
if err != IDError.IDE_ERR_NONE:
|
||||
viperlib.snprintf(c.Addr(dbg), 120, "[readSector] waitReady err=%d\n", t.CInt(err))
|
||||
viperlib.snprintf(c.Addr(dbg), 120, "[readSector] waitReady err=%d\n", int(err))
|
||||
serial.puts(dbg)
|
||||
return err
|
||||
asm.outb(0x3F6, 0x00)
|
||||
asm.outb(0x1F2, 1)
|
||||
asm.outb(0x1F3, t.CUInt8T(lba & 0xFF))
|
||||
asm.outb(0x1F4, t.CUInt8T((lba >> 8) & 0xFF))
|
||||
asm.outb(0x1F5, t.CUInt8T((lba >> 16) & 0xFF))
|
||||
asm.outb(0x1F6, t.CUInt8T(0xE0 | ((lba >> 24) & 0x0F)))
|
||||
asm.outb(0x1F3, uint8(lba & 0xFF))
|
||||
asm.outb(0x1F4, uint8((lba >> 8) & 0xFF))
|
||||
asm.outb(0x1F5, uint8((lba >> 16) & 0xFF))
|
||||
asm.outb(0x1F6, uint8(0xE0 | ((lba >> 24) & 0x0F)))
|
||||
asm.outb(0x1F7, 0x20)
|
||||
err = waitDataReady(IDE_baseport_PRIMARY)
|
||||
if err != IDError.IDE_ERR_NONE:
|
||||
st: t.CUInt8T = asm.inb(0x1F7)
|
||||
viperlib.snprintf(c.Addr(dbg), 120, "[readSector] waitDataReady err=%d status=0x%02x\n", t.CInt(err), t.CUInt32T(st))
|
||||
st: uint8 = asm.inb(0x1F7)
|
||||
viperlib.snprintf(c.Addr(dbg), 120, "[readSector] waitDataReady err=%d status=0x%02x\n", int(err), uint32(st))
|
||||
serial.puts(dbg)
|
||||
return err
|
||||
st2: t.CUInt8T = asm.inb(0x1F7)
|
||||
buf: t.CUInt16T | t.CPtr = t.CUInt16T(buffer, t.CPtr)
|
||||
st2: uint8 = asm.inb(0x1F7)
|
||||
buf: uint16 | t.CPtr = uint16(buffer, t.CPtr)
|
||||
for j in range(256):
|
||||
c.Set(c.Deref(buf), asm.inw(0x1F0))
|
||||
buf += 1
|
||||
first_byte: t.CUInt8T = c.Deref(t.CUInt8T(buffer, t.CPtr))
|
||||
# viperlib.snprintf(c.Addr(dbg), 120, "[readSector] lba=%lu status=0x%02x first=%02x\n", lba, t.CUInt32T(st2), t.CUInt32T(first_byte))
|
||||
# buf 为字节指针(uint16|t.CPtr → i8*),每次按 u16 读写须前进 2 字节
|
||||
buf = buf + 2
|
||||
first_byte: uint8 = c.Deref(uint8(buffer, t.CPtr))
|
||||
# viperlib.snprintf(c.Addr(dbg), 120, "[readSector] lba=%lu status=0x%02x first=%02x\n", lba, uint32(st2), uint32(first_byte))
|
||||
# serial.puts(dbg)
|
||||
return IDError.IDE_ERR_NONE
|
||||
|
||||
def writeSector(lba: t.CUInt32T, buffer: t.CConst | t.CVoid | t.CPtr) -> t.CInt:
|
||||
def writeSector(lba: uint32, buffer: t.CConst | t.CPtr) -> int:
|
||||
if buffer is None: return IDError.IDE_ERR_BUFFER_NULL
|
||||
err: IDError = waitReady(IDE_baseport_PRIMARY)
|
||||
if err != IDError.IDE_ERR_NONE: return err
|
||||
asm.outb(0x3F6, 0x00)
|
||||
asm.outb(0x1F2, 1)
|
||||
asm.outb(0x1F3, t.CUInt8T(lba & 0xFF))
|
||||
asm.outb(0x1F4, t.CUInt8T((lba >> 8) & 0xFF))
|
||||
asm.outb(0x1F5, t.CUInt8T((lba >> 16) & 0xFF))
|
||||
asm.outb(0x1F6, t.CUInt8T(0xE0 | ((lba >> 24) & 0x0F)))
|
||||
asm.outb(0x1F3, uint8(lba & 0xFF))
|
||||
asm.outb(0x1F4, uint8((lba >> 8) & 0xFF))
|
||||
asm.outb(0x1F5, uint8((lba >> 16) & 0xFF))
|
||||
asm.outb(0x1F6, uint8(0xE0 | ((lba >> 24) & 0x0F)))
|
||||
asm.outb(0x1F7, 0x30)
|
||||
err = waitDataReady(IDE_baseport_PRIMARY)
|
||||
if err != IDError.IDE_ERR_NONE: return err
|
||||
buf: t.CUInt16T | t.CPtr = t.CUInt16T(buffer, t.CPtr)
|
||||
buf: uint16 | t.CPtr = uint16(buffer, t.CPtr)
|
||||
for j in range(256):
|
||||
val: t.CUInt16T = c.Deref(buf)
|
||||
val: uint16 = c.Deref(buf)
|
||||
asm.outw(0x1F0, val)
|
||||
buf += 1
|
||||
# buf 为字节指针(uint16|t.CPtr → i8*),每次按 u16 读写须前进 2 字节
|
||||
buf = buf + 2
|
||||
asm.outb(0x1F7, 0xE7)
|
||||
waitReady(IDE_baseport_PRIMARY)
|
||||
return IDError.IDE_ERR_NONE
|
||||
|
||||
def getDiskSize() -> t.CUInt64T:
|
||||
def getDiskSize() -> uint64:
|
||||
err: IDError = waitReady(IDE_baseport_PRIMARY)
|
||||
if err != IDError.IDE_ERR_NONE: return 0
|
||||
asm.outb(0x1F6, 0xE0)
|
||||
asm.outb(0x1F7, 0xEC)
|
||||
err = waitDataReady(IDE_baseport_PRIMARY)
|
||||
if err != IDError.IDE_ERR_NONE: return 0
|
||||
status: t.CUInt8T = asm.inb(0x1F7)
|
||||
status: uint8 = asm.inb(0x1F7)
|
||||
if not status & IDE_STATUS_DRDY: return 0
|
||||
if status & IDE_STATUS_ERR: return 0
|
||||
identify_data: t.CArray[t.CUInt16T, 256]
|
||||
identify_data: t.CArray[uint16, 256]
|
||||
for i in range(256):
|
||||
identify_data[i] = asm.inw(0x1F0)
|
||||
totalSectors: t.CUInt64T = identify_data[60] | t.CUInt64T(identify_data[61]) << 16
|
||||
totalSectors: uint64 = identify_data[60] | uint64(identify_data[61]) << 16
|
||||
if identify_data[83] & (1 << 10):
|
||||
lba48_sectors: t.CUInt64T = (
|
||||
t.CUInt64T(identify_data[100]) |
|
||||
t.CUInt64T(identify_data[101]) << 16 |
|
||||
t.CUInt64T(identify_data[102]) << 32 |
|
||||
t.CUInt64T(identify_data[103]) << 48)
|
||||
lba48_sectors: uint64 = (
|
||||
uint64(identify_data[100]) |
|
||||
uint64(identify_data[101]) << 16 |
|
||||
uint64(identify_data[102]) << 32 |
|
||||
uint64(identify_data[103]) << 48)
|
||||
if lba48_sectors > totalSectors:
|
||||
totalSectors = lba48_sectors
|
||||
return totalSectors
|
||||
@@ -1,37 +1,37 @@
|
||||
import t, c
|
||||
import drivers.usb.usb as usb
|
||||
|
||||
HID_BOOT_PROTOCOL: t.CDefine = 0
|
||||
HID_REPORT_PROTOCOL: t.CDefine = 1
|
||||
|
||||
HID_KBD_REPORT_SIZE: t.CDefine = 8
|
||||
HID_MOUSE_REPORT_SIZE: t.CDefine = 4
|
||||
|
||||
class hid_kbd_report(t.CStruct):
|
||||
modifier: t.CUInt8T
|
||||
reserved: t.CUInt8T
|
||||
keycode: t.CArray[t.CUInt8T, 6]
|
||||
|
||||
class hid_mouse_report(t.CStruct):
|
||||
buttons: t.CUInt8T
|
||||
dx: t.CInt8T
|
||||
dy: t.CInt8T
|
||||
wheel: t.CInt8T
|
||||
|
||||
def init_keyboard(dev: usb.usb_device | t.CPtr) -> t.CInt:
|
||||
if dev.iface_class != 0x03: return -1
|
||||
if dev.iface_protocol != 0x01: return -2
|
||||
if dev.ep_in == 0: return -3
|
||||
return 0
|
||||
|
||||
def init_mouse(dev: usb.usb_device | t.CPtr) -> t.CInt:
|
||||
if dev.iface_class != 0x03: return -1
|
||||
if dev.iface_protocol != 0x02: return -2
|
||||
if dev.ep_in == 0: return -3
|
||||
return 0
|
||||
|
||||
def read_keyboard(dev: usb.usb_device | t.CPtr, report: hid_kbd_report | t.CPtr) -> t.CInt:
|
||||
return usb.read_interrupt(dev, c.Addr(report))
|
||||
|
||||
def read_mouse(dev: usb.usb_device | t.CPtr, report: hid_mouse_report | t.CPtr) -> t.CInt:
|
||||
return usb.read_interrupt(dev, c.Addr(report))
|
||||
import t, c
|
||||
import drivers.usb.usb as usb
|
||||
|
||||
HID_BOOT_PROTOCOL: t.CDefine = 0
|
||||
HID_REPORT_PROTOCOL: t.CDefine = 1
|
||||
|
||||
HID_KBD_REPORT_SIZE: t.CDefine = 8
|
||||
HID_MOUSE_REPORT_SIZE: t.CDefine = 4
|
||||
|
||||
class hid_kbd_report(t.CStruct):
|
||||
modifier: uint8
|
||||
reserved: uint8
|
||||
keycode: t.CArray[uint8, 6]
|
||||
|
||||
class hid_mouse_report(t.CStruct):
|
||||
buttons: uint8
|
||||
dx: int8
|
||||
dy: int8
|
||||
wheel: int8
|
||||
|
||||
def init_keyboard(dev: usb.usb_device | t.CPtr) -> int:
|
||||
if dev.iface_class != 0x03: return -1
|
||||
if dev.iface_protocol != 0x01: return -2
|
||||
if dev.ep_in == 0: return -3
|
||||
return 0
|
||||
|
||||
def init_mouse(dev: usb.usb_device | t.CPtr) -> int:
|
||||
if dev.iface_class != 0x03: return -1
|
||||
if dev.iface_protocol != 0x02: return -2
|
||||
if dev.ep_in == 0: return -3
|
||||
return 0
|
||||
|
||||
def read_keyboard(dev: usb.usb_device | t.CPtr, report: hid_kbd_report | t.CPtr) -> int:
|
||||
return usb.read_interrupt(dev, c.Addr(report))
|
||||
|
||||
def read_mouse(dev: usb.usb_device | t.CPtr, report: hid_mouse_report | t.CPtr) -> int:
|
||||
return usb.read_interrupt(dev, c.Addr(report))
|
||||
@@ -1,111 +1,116 @@
|
||||
import t, c
|
||||
import drivers.usb.usb as usb
|
||||
import drivers.usb.hid.hid as hid
|
||||
import drivers.usb.uhci as uhci
|
||||
import drivers.serial.uart.serial as serial
|
||||
|
||||
KBD_BUF_SIZE: t.CDefine = 1024
|
||||
KBD_EVT_PRESS: t.CDefine = 0
|
||||
KBD_EVT_RELEASE: t.CDefine = 1
|
||||
|
||||
class usb_kbd_event(t.CStruct):
|
||||
modifier: t.CUInt8T
|
||||
keycode: t.CUInt8T
|
||||
event_type: t.CUInt8T
|
||||
|
||||
kbd_buf: t.CArray[usb_kbd_event, KBD_BUF_SIZE]
|
||||
kbd_buf_head: t.CInt = 0
|
||||
kbd_buf_tail: t.CInt = 0
|
||||
kbd_buf_count: t.CInt = 0
|
||||
kbd_dev: usb.usb_device | t.CPtr = None
|
||||
kbd_report: hid.hid_kbd_report
|
||||
kbd_prev_keycodes: t.CArray[t.CUInt8T, 6]
|
||||
kbd_initialized: t.CInt = 0
|
||||
kbd_slot_id: t.CInt = -1
|
||||
|
||||
def init() -> t.CInt:
|
||||
global kbd_dev, kbd_initialized, kbd_slot_id
|
||||
dev: usb.usb_device | t.CPtr = usb.find_hid_device(0x01)
|
||||
if dev is None:
|
||||
serial.puts("[usb_kbd] no USB keyboard found\n")
|
||||
return -1
|
||||
kbd_dev = dev
|
||||
if hid.init_keyboard(dev) != 0:
|
||||
serial.puts("[usb_kbd] init failed\n")
|
||||
return -2
|
||||
kbd_initialized = 1
|
||||
serial.puts("[usb_kbd] initialized\n")
|
||||
kbd_slot_id = uhci.register_int_callback(c.Addr(_on_int_complete))
|
||||
if kbd_slot_id < 0:
|
||||
serial.puts("[usb_kbd] register callback failed\n")
|
||||
kbd_initialized = 0
|
||||
return -3
|
||||
uhci.schedule_int_transfer(kbd_slot_id, dev.addr, dev.ep_in, dev.ls, t.CUInt8T(dev.ep_in_max), c.Addr(dev.ep_in_toggle), c.Addr(kbd_report))
|
||||
return 0
|
||||
|
||||
def _on_int_complete() -> t.CInt:
|
||||
global kbd_buf_head, kbd_buf_tail, kbd_buf_count, kbd_prev_keycodes
|
||||
if kbd_initialized == 0: return 0
|
||||
i: t.CInt
|
||||
j: t.CInt
|
||||
for i in range(6):
|
||||
code: t.CUInt8T = kbd_report.keycode[i]
|
||||
if code == 0: continue
|
||||
found: t.CInt = 0
|
||||
for j in range(6):
|
||||
if code == kbd_prev_keycodes[j]:
|
||||
found = 1
|
||||
break
|
||||
if found == 0:
|
||||
if kbd_buf_count < KBD_BUF_SIZE:
|
||||
kbd_buf[kbd_buf_tail].modifier = kbd_report.modifier
|
||||
kbd_buf[kbd_buf_tail].keycode = code
|
||||
kbd_buf[kbd_buf_tail].event_type = KBD_EVT_PRESS
|
||||
kbd_buf_tail = kbd_buf_tail + 1
|
||||
if kbd_buf_tail >= KBD_BUF_SIZE:
|
||||
kbd_buf_tail = 0
|
||||
kbd_buf_count += 1
|
||||
for i in range(6):
|
||||
prev: t.CUInt8T = kbd_prev_keycodes[i]
|
||||
if prev == 0: continue
|
||||
found2: t.CInt = 0
|
||||
for j in range(6):
|
||||
if prev == kbd_report.keycode[j]:
|
||||
found2 = 1
|
||||
break
|
||||
if found2 == 0:
|
||||
if kbd_buf_count < KBD_BUF_SIZE:
|
||||
kbd_buf[kbd_buf_tail].modifier = kbd_report.modifier
|
||||
kbd_buf[kbd_buf_tail].keycode = prev
|
||||
kbd_buf[kbd_buf_tail].event_type = KBD_EVT_RELEASE
|
||||
kbd_buf_tail = kbd_buf_tail + 1
|
||||
if kbd_buf_tail >= KBD_BUF_SIZE:
|
||||
kbd_buf_tail = 0
|
||||
kbd_buf_count += 1
|
||||
for i in range(6):
|
||||
kbd_prev_keycodes[i] = kbd_report.keycode[i]
|
||||
dev: usb.usb_device | t.CPtr = kbd_dev
|
||||
if dev is not None and kbd_slot_id >= 0:
|
||||
uhci.schedule_int_transfer(kbd_slot_id, dev.addr, dev.ep_in, dev.ls, t.CUInt8T(dev.ep_in_max), c.Addr(dev.ep_in_toggle), c.Addr(kbd_report))
|
||||
return 0
|
||||
|
||||
def has_data() -> t.CInt:
|
||||
if kbd_buf_count > 0: return 1
|
||||
return 0
|
||||
|
||||
def poll() -> t.CInt:
|
||||
if kbd_initialized == 0: return 0
|
||||
if kbd_buf_count > 0: return 1
|
||||
return 0
|
||||
|
||||
def read_event(out: usb_kbd_event | t.CPtr) -> t.CInt:
|
||||
global kbd_buf_head, kbd_buf_count
|
||||
if kbd_buf_count == 0: return -1
|
||||
out.modifier = kbd_buf[kbd_buf_head].modifier
|
||||
out.keycode = kbd_buf[kbd_buf_head].keycode
|
||||
out.event_type = kbd_buf[kbd_buf_head].event_type
|
||||
kbd_buf_head = kbd_buf_head + 1
|
||||
if kbd_buf_head >= KBD_BUF_SIZE:
|
||||
kbd_buf_head = 0
|
||||
kbd_buf_count -= 1
|
||||
return 0
|
||||
import t, c
|
||||
import drivers.usb.usb as usb
|
||||
import drivers.usb.hid.hid as hid
|
||||
import drivers.usb.uhci as uhci
|
||||
import drivers.serial.uart.serial as serial
|
||||
|
||||
KBD_BUF_SIZE: t.CDefine = 1024
|
||||
KBD_EVT_PRESS: t.CDefine = 0
|
||||
KBD_EVT_RELEASE: t.CDefine = 1
|
||||
|
||||
class usb_kbd_event(t.CStruct):
|
||||
modifier: uint8
|
||||
keycode: uint8
|
||||
event_type: uint8
|
||||
|
||||
kbd_buf: t.CArray[usb_kbd_event, KBD_BUF_SIZE]
|
||||
kbd_buf_head: int = 0
|
||||
kbd_buf_tail: int = 0
|
||||
kbd_buf_count: int = 0
|
||||
kbd_dev: usb.usb_device | t.CPtr = None
|
||||
kbd_report: hid.hid_kbd_report
|
||||
kbd_prev_keycodes: t.CArray[uint8, 6]
|
||||
kbd_initialized: int = 0
|
||||
kbd_slot_id: int = -1
|
||||
|
||||
def init() -> int:
|
||||
global kbd_dev, kbd_initialized, kbd_slot_id
|
||||
dev: usb.usb_device | t.CPtr = usb.find_hid_device(0x01)
|
||||
if dev is None:
|
||||
serial.puts("[usb_kbd] no USB keyboard found\n")
|
||||
return -1
|
||||
kbd_dev = dev
|
||||
if hid.init_keyboard(dev) != 0:
|
||||
serial.puts("[usb_kbd] init failed\n")
|
||||
return -2
|
||||
kbd_initialized = 1
|
||||
serial.puts("[usb_kbd] initialized\n")
|
||||
kbd_slot_id = uhci.register_int_callback(c.Addr(_on_int_complete))
|
||||
if kbd_slot_id < 0:
|
||||
serial.puts("[usb_kbd] register callback failed\n")
|
||||
kbd_initialized = 0
|
||||
return -3
|
||||
# 中断传输长度不得超过 kbd_report(8 字节),否则 DMA 越界写全局
|
||||
kbd_pkt_len: uint8 = 8
|
||||
if dev.ep_in_max < 8: kbd_pkt_len = uint8(dev.ep_in_max)
|
||||
uhci.schedule_int_transfer(kbd_slot_id, dev.addr, dev.ep_in, dev.ls, kbd_pkt_len, c.Addr(dev.ep_in_toggle), c.Addr(kbd_report))
|
||||
return 0
|
||||
|
||||
def _on_int_complete() -> int:
|
||||
global kbd_buf_head, kbd_buf_tail, kbd_buf_count, kbd_prev_keycodes
|
||||
if kbd_initialized == 0: return 0
|
||||
i: int
|
||||
j: int
|
||||
for i in range(6):
|
||||
code: uint8 = kbd_report.keycode[i]
|
||||
if code == 0: continue
|
||||
found: int = 0
|
||||
for j in range(6):
|
||||
if code == kbd_prev_keycodes[j]:
|
||||
found = 1
|
||||
break
|
||||
if found == 0:
|
||||
if kbd_buf_count < KBD_BUF_SIZE:
|
||||
kbd_buf[kbd_buf_tail].modifier = kbd_report.modifier
|
||||
kbd_buf[kbd_buf_tail].keycode = code
|
||||
kbd_buf[kbd_buf_tail].event_type = KBD_EVT_PRESS
|
||||
kbd_buf_tail = kbd_buf_tail + 1
|
||||
if kbd_buf_tail >= KBD_BUF_SIZE:
|
||||
kbd_buf_tail = 0
|
||||
kbd_buf_count += 1
|
||||
for i in range(6):
|
||||
prev: uint8 = kbd_prev_keycodes[i]
|
||||
if prev == 0: continue
|
||||
found2: int = 0
|
||||
for j in range(6):
|
||||
if prev == kbd_report.keycode[j]:
|
||||
found2 = 1
|
||||
break
|
||||
if found2 == 0:
|
||||
if kbd_buf_count < KBD_BUF_SIZE:
|
||||
kbd_buf[kbd_buf_tail].modifier = kbd_report.modifier
|
||||
kbd_buf[kbd_buf_tail].keycode = prev
|
||||
kbd_buf[kbd_buf_tail].event_type = KBD_EVT_RELEASE
|
||||
kbd_buf_tail = kbd_buf_tail + 1
|
||||
if kbd_buf_tail >= KBD_BUF_SIZE:
|
||||
kbd_buf_tail = 0
|
||||
kbd_buf_count += 1
|
||||
for i in range(6):
|
||||
kbd_prev_keycodes[i] = kbd_report.keycode[i]
|
||||
dev: usb.usb_device | t.CPtr = kbd_dev
|
||||
if dev is not None and kbd_slot_id >= 0:
|
||||
kbd_pkt_len2: uint8 = 8
|
||||
if dev.ep_in_max < 8: kbd_pkt_len2 = uint8(dev.ep_in_max)
|
||||
uhci.schedule_int_transfer(kbd_slot_id, dev.addr, dev.ep_in, dev.ls, kbd_pkt_len2, c.Addr(dev.ep_in_toggle), c.Addr(kbd_report))
|
||||
return 0
|
||||
|
||||
def has_data() -> int:
|
||||
if kbd_buf_count > 0: return 1
|
||||
return 0
|
||||
|
||||
def poll() -> int:
|
||||
if kbd_initialized == 0: return 0
|
||||
if kbd_buf_count > 0: return 1
|
||||
return 0
|
||||
|
||||
def read_event(out: usb_kbd_event | t.CPtr) -> int:
|
||||
global kbd_buf_head, kbd_buf_count
|
||||
if kbd_buf_count == 0: return -1
|
||||
out.modifier = kbd_buf[kbd_buf_head].modifier
|
||||
out.keycode = kbd_buf[kbd_buf_head].keycode
|
||||
out.event_type = kbd_buf[kbd_buf_head].event_type
|
||||
kbd_buf_head = kbd_buf_head + 1
|
||||
if kbd_buf_head >= KBD_BUF_SIZE:
|
||||
kbd_buf_head = 0
|
||||
kbd_buf_count -= 1
|
||||
return 0
|
||||
@@ -1,77 +1,82 @@
|
||||
import t, c
|
||||
import drivers.usb.usb as usb
|
||||
import drivers.usb.hid.hid as hid
|
||||
import drivers.usb.uhci as uhci
|
||||
import drivers.serial.uart.serial as serial
|
||||
|
||||
MOUSE_BUF_SIZE: t.CDefine = 1024
|
||||
|
||||
class usb_mouse_packet(t.CStruct):
|
||||
buttons: t.CUInt8T
|
||||
dx: t.CInt16T
|
||||
dy: t.CInt16T
|
||||
wheel: t.CInt8T
|
||||
|
||||
mse_buf: t.CArray[usb_mouse_packet, MOUSE_BUF_SIZE]
|
||||
mse_buf_head: t.CInt = 0
|
||||
mse_buf_tail: t.CInt = 0
|
||||
mse_buf_count: t.CInt = 0
|
||||
mse_dev: usb.usb_device | t.CPtr = None
|
||||
mse_report: hid.hid_mouse_report
|
||||
mse_initialized: t.CInt = 0
|
||||
mse_slot_id: t.CInt = -1
|
||||
|
||||
def init() -> t.CInt:
|
||||
global mse_dev, mse_initialized, mse_slot_id
|
||||
dev: usb.usb_device | t.CPtr = usb.find_hid_device(0x02)
|
||||
if dev is None:
|
||||
serial.puts("[usb_mse] no USB mouse found\n")
|
||||
return -1
|
||||
mse_dev = dev
|
||||
if hid.init_mouse(dev) != 0:
|
||||
serial.puts("[usb_mse] init failed\n")
|
||||
return -2
|
||||
mse_initialized = 1
|
||||
serial.puts("[usb_mse] initialized\n")
|
||||
mse_slot_id = uhci.register_int_callback(c.Addr(_on_int_complete))
|
||||
if mse_slot_id < 0:
|
||||
serial.puts("[usb_mse] register callback failed\n")
|
||||
mse_initialized = 0
|
||||
return -3
|
||||
uhci.schedule_int_transfer(mse_slot_id, dev.addr, dev.ep_in, dev.ls, t.CUInt8T(dev.ep_in_max), c.Addr(dev.ep_in_toggle), c.Addr(mse_report))
|
||||
return 0
|
||||
|
||||
def _on_int_complete() -> t.CInt:
|
||||
global mse_buf_head, mse_buf_tail, mse_buf_count
|
||||
if mse_initialized == 0: return 0
|
||||
if mse_report.dx != 0 or mse_report.dy != 0 or mse_report.buttons != 0:
|
||||
if mse_buf_count < MOUSE_BUF_SIZE:
|
||||
mse_buf[mse_buf_tail].buttons = mse_report.buttons
|
||||
mse_buf[mse_buf_tail].dx = t.CInt16T(mse_report.dx)
|
||||
mse_buf[mse_buf_tail].dy = t.CInt16T(mse_report.dy)
|
||||
mse_buf[mse_buf_tail].wheel = mse_report.wheel
|
||||
mse_buf_tail = mse_buf_tail + 1
|
||||
if mse_buf_tail >= MOUSE_BUF_SIZE:
|
||||
mse_buf_tail = 0
|
||||
mse_buf_count += 1
|
||||
dev: usb.usb_device | t.CPtr = mse_dev
|
||||
if dev is not None and mse_slot_id >= 0:
|
||||
uhci.schedule_int_transfer(mse_slot_id, dev.addr, dev.ep_in, dev.ls, t.CUInt8T(dev.ep_in_max), c.Addr(dev.ep_in_toggle), c.Addr(mse_report))
|
||||
return 0
|
||||
|
||||
def has_data() -> t.CInt:
|
||||
if mse_buf_count > 0: return 1
|
||||
return 0
|
||||
|
||||
def read_packet(out: usb_mouse_packet | t.CPtr) -> t.CInt:
|
||||
global mse_buf_head, mse_buf_count
|
||||
if mse_buf_count == 0: return -1
|
||||
out.buttons = mse_buf[mse_buf_head].buttons
|
||||
out.dx = mse_buf[mse_buf_head].dx
|
||||
out.dy = mse_buf[mse_buf_head].dy
|
||||
out.wheel = mse_buf[mse_buf_head].wheel
|
||||
mse_buf_head = mse_buf_head + 1
|
||||
if mse_buf_head >= MOUSE_BUF_SIZE:
|
||||
mse_buf_head = 0
|
||||
mse_buf_count -= 1
|
||||
return 0
|
||||
import t, c
|
||||
import drivers.usb.usb as usb
|
||||
import drivers.usb.hid.hid as hid
|
||||
import drivers.usb.uhci as uhci
|
||||
import drivers.serial.uart.serial as serial
|
||||
|
||||
MOUSE_BUF_SIZE: t.CDefine = 1024
|
||||
|
||||
class usb_mouse_packet(t.CStruct):
|
||||
buttons: uint8
|
||||
dx: int16
|
||||
dy: int16
|
||||
wheel: int8
|
||||
|
||||
mse_buf: t.CArray[usb_mouse_packet, MOUSE_BUF_SIZE]
|
||||
mse_buf_head: int = 0
|
||||
mse_buf_tail: int = 0
|
||||
mse_buf_count: int = 0
|
||||
mse_dev: usb.usb_device | t.CPtr = None
|
||||
mse_report: hid.hid_mouse_report
|
||||
mse_initialized: int = 0
|
||||
mse_slot_id: int = -1
|
||||
|
||||
def init() -> int:
|
||||
global mse_dev, mse_initialized, mse_slot_id
|
||||
dev: usb.usb_device | t.CPtr = usb.find_hid_device(0x02)
|
||||
if dev is None:
|
||||
serial.puts("[usb_mse] no USB mouse found\n")
|
||||
return -1
|
||||
mse_dev = dev
|
||||
if hid.init_mouse(dev) != 0:
|
||||
serial.puts("[usb_mse] init failed\n")
|
||||
return -2
|
||||
mse_initialized = 1
|
||||
serial.puts("[usb_mse] initialized\n")
|
||||
mse_slot_id = uhci.register_int_callback(c.Addr(_on_int_complete))
|
||||
if mse_slot_id < 0:
|
||||
serial.puts("[usb_mse] register callback failed\n")
|
||||
mse_initialized = 0
|
||||
return -3
|
||||
# 中断传输长度不得超过 mse_report(4 字节),否则 DMA 越界写全局
|
||||
mse_pkt_len: uint8 = 4
|
||||
if dev.ep_in_max < 4: mse_pkt_len = uint8(dev.ep_in_max)
|
||||
uhci.schedule_int_transfer(mse_slot_id, dev.addr, dev.ep_in, dev.ls, mse_pkt_len, c.Addr(dev.ep_in_toggle), c.Addr(mse_report))
|
||||
return 0
|
||||
|
||||
def _on_int_complete() -> int:
|
||||
global mse_buf_head, mse_buf_tail, mse_buf_count
|
||||
if mse_initialized == 0: return 0
|
||||
if mse_report.dx != 0 or mse_report.dy != 0 or mse_report.buttons != 0:
|
||||
if mse_buf_count < MOUSE_BUF_SIZE:
|
||||
mse_buf[mse_buf_tail].buttons = mse_report.buttons
|
||||
mse_buf[mse_buf_tail].dx = int16(mse_report.dx)
|
||||
mse_buf[mse_buf_tail].dy = int16(mse_report.dy)
|
||||
mse_buf[mse_buf_tail].wheel = mse_report.wheel
|
||||
mse_buf_tail = mse_buf_tail + 1
|
||||
if mse_buf_tail >= MOUSE_BUF_SIZE:
|
||||
mse_buf_tail = 0
|
||||
mse_buf_count += 1
|
||||
dev: usb.usb_device | t.CPtr = mse_dev
|
||||
if dev is not None and mse_slot_id >= 0:
|
||||
mse_pkt_len2: uint8 = 4
|
||||
if dev.ep_in_max < 4: mse_pkt_len2 = uint8(dev.ep_in_max)
|
||||
uhci.schedule_int_transfer(mse_slot_id, dev.addr, dev.ep_in, dev.ls, mse_pkt_len2, c.Addr(dev.ep_in_toggle), c.Addr(mse_report))
|
||||
return 0
|
||||
|
||||
def has_data() -> int:
|
||||
if mse_buf_count > 0: return 1
|
||||
return 0
|
||||
|
||||
def read_packet(out: usb_mouse_packet | t.CPtr) -> int:
|
||||
global mse_buf_head, mse_buf_count
|
||||
if mse_buf_count == 0: return -1
|
||||
out.buttons = mse_buf[mse_buf_head].buttons
|
||||
out.dx = mse_buf[mse_buf_head].dx
|
||||
out.dy = mse_buf[mse_buf_head].dy
|
||||
out.wheel = mse_buf[mse_buf_head].wheel
|
||||
mse_buf_head = mse_buf_head + 1
|
||||
if mse_buf_head >= MOUSE_BUF_SIZE:
|
||||
mse_buf_head = 0
|
||||
mse_buf_count -= 1
|
||||
return 0
|
||||
@@ -1,93 +1,93 @@
|
||||
import t, c
|
||||
import asm
|
||||
|
||||
PCI_CONFIG_ADDR: t.CDefine = 0xCF8
|
||||
PCI_CONFIG_DATA: t.CDefine = 0xCFC
|
||||
|
||||
PCI_CLASS_SERIAL_USB: t.CDefine = 0x0C03
|
||||
PCI_CLASS_SERIAL_UHCI: t.CDefine = 0x0C0300
|
||||
PCI_CLASS_SERIAL_OHCI: t.CDefine = 0x0C0310
|
||||
PCI_CLASS_SERIAL_EHCI: t.CDefine = 0x0C0320
|
||||
PCI_CLASS_SERIAL_XHCI: t.CDefine = 0x0C0330
|
||||
|
||||
PCI_CMD_IO_SPACE: t.CDefine = 0x0001
|
||||
PCI_CMD_BUS_MASTER: t.CDefine = 0x0004
|
||||
|
||||
class pci_device(t.CStruct):
|
||||
bus: t.CUInt8T
|
||||
dev: t.CUInt8T
|
||||
func: t.CUInt8T
|
||||
vendor_id: t.CUInt16T
|
||||
device_id: t.CUInt16T
|
||||
class_code: t.CUInt32T
|
||||
irq: t.CUInt8T
|
||||
bar: t.CArray[t.CUInt32T, 6]
|
||||
|
||||
def pci_read32(bus: t.CUInt8T, dev: t.CUInt8T, func: t.CUInt8T, offset: t.CUInt8T) -> t.CUInt32T:
|
||||
addr: t.CUInt32T = 0x80000000 | (t.CUInt32T(bus) << 16) | (t.CUInt32T(dev) << 11) | (t.CUInt32T(func) << 8) | (t.CUInt32T(offset) & 0xFC)
|
||||
asm.outl(PCI_CONFIG_ADDR, addr)
|
||||
return asm.inl(PCI_CONFIG_DATA)
|
||||
|
||||
def pci_write32(bus: t.CUInt8T, dev: t.CUInt8T, func: t.CUInt8T, offset: t.CUInt8T, value: t.CUInt32T):
|
||||
addr: t.CUInt32T = 0x80000000 | (t.CUInt32T(bus) << 16) | (t.CUInt32T(dev) << 11) | (t.CUInt32T(func) << 8) | (t.CUInt32T(offset) & 0xFC)
|
||||
asm.outl(PCI_CONFIG_ADDR, addr)
|
||||
asm.outl(PCI_CONFIG_DATA, value)
|
||||
|
||||
def pci_read16(bus: t.CUInt8T, dev: t.CUInt8T, func: t.CUInt8T, offset: t.CUInt8T) -> t.CUInt16T:
|
||||
val: t.CUInt32T = pci_read32(bus, dev, func, offset)
|
||||
shift: t.CUInt32T = (t.CUInt32T(offset) & 0x02) * 8
|
||||
return t.CUInt16T((val >> shift) & 0xFFFF)
|
||||
|
||||
def pci_read8(bus: t.CUInt8T, dev: t.CUInt8T, func: t.CUInt8T, offset: t.CUInt8T) -> t.CUInt8T:
|
||||
val: t.CUInt32T = pci_read32(bus, dev, func, offset)
|
||||
shift: t.CUInt32T = (t.CUInt32T(offset) & 0x03) * 8
|
||||
return t.CUInt8T((val >> shift) & 0xFF)
|
||||
|
||||
def pci_get_class(bus: t.CUInt8T, dev: t.CUInt8T, func: t.CUInt8T) -> t.CUInt32T:
|
||||
cls: t.CUInt8T = pci_read8(bus, dev, func, 0x0B)
|
||||
sub: t.CUInt8T = pci_read8(bus, dev, func, 0x0A)
|
||||
proto: t.CUInt8T = pci_read8(bus, dev, func, 0x09)
|
||||
return (t.CUInt32T(cls) << 16) | (t.CUInt32T(sub) << 8) | t.CUInt32T(proto)
|
||||
|
||||
def pci_get_bar(bus: t.CUInt8T, dev: t.CUInt8T, func: t.CUInt8T, bar_idx: t.CUInt8T) -> t.CUInt32T:
|
||||
return pci_read32(bus, dev, func, 0x10 + bar_idx * 4)
|
||||
|
||||
def pci_enable_device(dev: pci_device | t.CPtr):
|
||||
cmd: t.CUInt16T = pci_read16(dev.bus, dev.dev, dev.func, 0x04)
|
||||
cmd = cmd | PCI_CMD_IO_SPACE | PCI_CMD_BUS_MASTER
|
||||
pci_write32(dev.bus, dev.dev, dev.func, 0x04, t.CUInt32T(cmd))
|
||||
|
||||
def pci_fill_device(bus: t.CUInt8T, dev_n: t.CUInt8T, func: t.CUInt8T, out: pci_device | t.CPtr):
|
||||
out.bus = bus
|
||||
out.dev = dev_n
|
||||
out.func = func
|
||||
out.vendor_id = pci_read16(bus, dev_n, func, 0x00)
|
||||
out.device_id = pci_read16(bus, dev_n, func, 0x02)
|
||||
out.class_code = pci_get_class(bus, dev_n, func)
|
||||
out.irq = pci_read8(bus, dev_n, func, 0x3C)
|
||||
i: t.CInt
|
||||
for i in range(6):
|
||||
out.bar[i] = pci_get_bar(bus, dev_n, func, t.CUInt8T(i))
|
||||
|
||||
_uhci_dev: pci_device
|
||||
_uhci_found: t.CInt = 0
|
||||
|
||||
def find_uhci() -> t.CUInt16T:
|
||||
global _uhci_dev, _uhci_found
|
||||
bus: t.CUInt8T
|
||||
dev_n: t.CUInt8T
|
||||
func: t.CUInt8T
|
||||
for bus in range(1):
|
||||
for dev_n in range(32):
|
||||
for func in range(8):
|
||||
vendor: t.CUInt16T = pci_read16(bus, dev_n, func, 0x00)
|
||||
if vendor == 0xFFFF: continue
|
||||
cls: t.CUInt32T = pci_get_class(bus, dev_n, func)
|
||||
if cls == PCI_CLASS_SERIAL_UHCI:
|
||||
pci_fill_device(bus, dev_n, func, c.Addr(_uhci_dev))
|
||||
pci_enable_device(c.Addr(_uhci_dev))
|
||||
_uhci_found = 1
|
||||
bar: t.CUInt32T = _uhci_dev.bar[4]
|
||||
io_base: t.CUInt16T = t.CUInt16T(bar & 0xFFFE)
|
||||
return io_base
|
||||
return 0
|
||||
import t, c
|
||||
import asm
|
||||
|
||||
PCI_CONFIG_ADDR: t.CDefine = 0xCF8
|
||||
PCI_CONFIG_DATA: t.CDefine = 0xCFC
|
||||
|
||||
PCI_CLASS_SERIAL_USB: t.CDefine = 0x0C03
|
||||
PCI_CLASS_SERIAL_UHCI: t.CDefine = 0x0C0300
|
||||
PCI_CLASS_SERIAL_OHCI: t.CDefine = 0x0C0310
|
||||
PCI_CLASS_SERIAL_EHCI: t.CDefine = 0x0C0320
|
||||
PCI_CLASS_SERIAL_XHCI: t.CDefine = 0x0C0330
|
||||
|
||||
PCI_CMD_IO_SPACE: t.CDefine = 0x0001
|
||||
PCI_CMD_BUS_MASTER: t.CDefine = 0x0004
|
||||
|
||||
class pci_device(t.CStruct):
|
||||
bus: uint8
|
||||
dev: uint8
|
||||
func: uint8
|
||||
vendor_id: uint16
|
||||
device_id: uint16
|
||||
class_code: uint32
|
||||
irq: uint8
|
||||
bar: t.CArray[uint32, 6]
|
||||
|
||||
def pci_read32(bus: uint8, dev: uint8, func: uint8, offset: uint8) -> uint32:
|
||||
addr: uint32 = 0x80000000 | (uint32(bus) << 16) | (uint32(dev) << 11) | (uint32(func) << 8) | (uint32(offset) & 0xFC)
|
||||
asm.outl(PCI_CONFIG_ADDR, addr)
|
||||
return asm.inl(PCI_CONFIG_DATA)
|
||||
|
||||
def pci_write32(bus: uint8, dev: uint8, func: uint8, offset: uint8, value: uint32):
|
||||
addr: uint32 = 0x80000000 | (uint32(bus) << 16) | (uint32(dev) << 11) | (uint32(func) << 8) | (uint32(offset) & 0xFC)
|
||||
asm.outl(PCI_CONFIG_ADDR, addr)
|
||||
asm.outl(PCI_CONFIG_DATA, value)
|
||||
|
||||
def pci_read16(bus: uint8, dev: uint8, func: uint8, offset: uint8) -> uint16:
|
||||
val: uint32 = pci_read32(bus, dev, func, offset)
|
||||
shift: uint32 = (uint32(offset) & 0x02) * 8
|
||||
return uint16((val >> shift) & 0xFFFF)
|
||||
|
||||
def pci_read8(bus: uint8, dev: uint8, func: uint8, offset: uint8) -> uint8:
|
||||
val: uint32 = pci_read32(bus, dev, func, offset)
|
||||
shift: uint32 = (uint32(offset) & 0x03) * 8
|
||||
return uint8((val >> shift) & 0xFF)
|
||||
|
||||
def pci_get_class(bus: uint8, dev: uint8, func: uint8) -> uint32:
|
||||
cls: uint8 = pci_read8(bus, dev, func, 0x0B)
|
||||
sub: uint8 = pci_read8(bus, dev, func, 0x0A)
|
||||
proto: uint8 = pci_read8(bus, dev, func, 0x09)
|
||||
return (uint32(cls) << 16) | (uint32(sub) << 8) | uint32(proto)
|
||||
|
||||
def pci_get_bar(bus: uint8, dev: uint8, func: uint8, bar_idx: uint8) -> uint32:
|
||||
return pci_read32(bus, dev, func, 0x10 + bar_idx * 4)
|
||||
|
||||
def pci_enable_device(dev: pci_device | t.CPtr):
|
||||
cmd: uint16 = pci_read16(dev.bus, dev.dev, dev.func, 0x04)
|
||||
cmd = cmd | PCI_CMD_IO_SPACE | PCI_CMD_BUS_MASTER
|
||||
pci_write32(dev.bus, dev.dev, dev.func, 0x04, uint32(cmd))
|
||||
|
||||
def pci_fill_device(bus: uint8, dev_n: uint8, func: uint8, out: pci_device | t.CPtr):
|
||||
out.bus = bus
|
||||
out.dev = dev_n
|
||||
out.func = func
|
||||
out.vendor_id = pci_read16(bus, dev_n, func, 0x00)
|
||||
out.device_id = pci_read16(bus, dev_n, func, 0x02)
|
||||
out.class_code = pci_get_class(bus, dev_n, func)
|
||||
out.irq = pci_read8(bus, dev_n, func, 0x3C)
|
||||
i: int
|
||||
for i in range(6):
|
||||
out.bar[i] = pci_get_bar(bus, dev_n, func, uint8(i))
|
||||
|
||||
_uhci_dev: pci_device
|
||||
_uhci_found: int = 0
|
||||
|
||||
def find_uhci() -> uint16:
|
||||
global _uhci_dev, _uhci_found
|
||||
bus: uint8
|
||||
dev_n: uint8
|
||||
func: uint8
|
||||
for bus in range(1):
|
||||
for dev_n in range(32):
|
||||
for func in range(8):
|
||||
vendor: uint16 = pci_read16(bus, dev_n, func, 0x00)
|
||||
if vendor == 0xFFFF: continue
|
||||
cls: uint32 = pci_get_class(bus, dev_n, func)
|
||||
if cls == PCI_CLASS_SERIAL_UHCI:
|
||||
pci_fill_device(bus, dev_n, func, c.Addr(_uhci_dev))
|
||||
pci_enable_device(c.Addr(_uhci_dev))
|
||||
_uhci_found = 1
|
||||
bar: uint32 = _uhci_dev.bar[4]
|
||||
io_base: uint16 = uint16(bar & 0xFFFE)
|
||||
return io_base
|
||||
return 0
|
||||
+419
-419
@@ -1,419 +1,419 @@
|
||||
import t, c
|
||||
import asm
|
||||
import mm.mm as mm
|
||||
import viperstring as string
|
||||
import drivers.serial.uart.serial as serial
|
||||
import platform.pch.timer as timer
|
||||
import intr.idt as idt
|
||||
import platform.pch.pic as pic
|
||||
import drivers.usb.pci as pci
|
||||
import viperlib
|
||||
|
||||
UHCI_USBCMD: t.CDefine = 0x00
|
||||
UHCI_USBSTS: t.CDefine = 0x02
|
||||
UHCI_USBINTR: t.CDefine = 0x04
|
||||
UHCI_FRNUM: t.CDefine = 0x06
|
||||
UHCI_FLBASEADD: t.CDefine = 0x08
|
||||
UHCI_SOFMOD: t.CDefine = 0x0C
|
||||
UHCI_PORTSC1: t.CDefine = 0x10
|
||||
UHCI_PORTSC2: t.CDefine = 0x12
|
||||
|
||||
UHCI_CMD_RUN: t.CDefine = 0x0001
|
||||
UHCI_CMD_HCRESET: t.CDefine = 0x0002
|
||||
UHCI_CMD_GRESET: t.CDefine = 0x0004
|
||||
UHCI_CMD_MAXPKT: t.CDefine = 0x0080
|
||||
UHCI_CMD_CF: t.CDefine = 0x0040
|
||||
|
||||
UHCI_STS_HCHALTED: t.CDefine = 0x0020
|
||||
UHCI_STS_USBINT: t.CDefine = 0x0001
|
||||
UHCI_STS_USBERRINT: t.CDefine = 0x0002
|
||||
UHCI_STS_RESUME: t.CDefine = 0x0004
|
||||
UHCI_INTR_TIMEOUT: t.CDefine = 0x0001
|
||||
UHCI_INTR_RESUME: t.CDefine = 0x0002
|
||||
UHCI_INTR_IOC: t.CDefine = 0x0004
|
||||
UHCI_INTR_SHORT: t.CDefine = 0x0008
|
||||
|
||||
UHCI_PORT_CONNECT: t.CDefine = 0x0001
|
||||
UHCI_PORT_CONNECT_CHANGE: t.CDefine = 0x0002
|
||||
UHCI_PORT_ENABLE: t.CDefine = 0x0004
|
||||
UHCI_PORT_ENABLE_CHANGE: t.CDefine = 0x0008
|
||||
UHCI_PORT_RESET: t.CDefine = 0x0200
|
||||
UHCI_PORT_LOW_SPEED: t.CDefine = 0x0100
|
||||
|
||||
TD_CTRL_ACTIVE: t.CDefine = 0x00800000
|
||||
TD_CTRL_IOC: t.CDefine = 0x01000000
|
||||
TD_CTRL_LS: t.CDefine = 0x04000000
|
||||
TD_CTRL_SPD: t.CDefine = 0x20000000
|
||||
TD_CTRL_CERR_SHIFT: t.CDefine = 27
|
||||
TD_CTRL_CERR_MASK: t.CDefine = 0x18000000
|
||||
|
||||
TD_TOKEN_SETUP: t.CDefine = 0x2D
|
||||
TD_TOKEN_IN: t.CDefine = 0x69
|
||||
TD_TOKEN_OUT: t.CDefine = 0xE1
|
||||
|
||||
TD_TOKEN_DATA0: t.CDefine = 0
|
||||
TD_TOKEN_DATA1: t.CDefine = 1
|
||||
|
||||
TD_LINK_TERMINATE: t.CDefine = 0x00000001
|
||||
TD_LINK_QH: t.CDefine = 0x00000002
|
||||
TD_LINK_DEPTH_FIRST: t.CDefine = 0x00000004
|
||||
|
||||
UHCI_NUM_FRAMES: t.CDefine = 1024
|
||||
UHCI_INT_SLOTS: t.CDefine = 4
|
||||
|
||||
class uhci_td(t.CStruct):
|
||||
link: t.CUInt32T
|
||||
ctrl_status: t.CUInt32T
|
||||
token: t.CUInt32T
|
||||
buffer: t.CUInt32T
|
||||
|
||||
class uhci_qh(t.CStruct):
|
||||
link: t.CUInt32T
|
||||
element: t.CUInt32T
|
||||
|
||||
class int_slot(t.CStruct):
|
||||
td: uhci_td | t.CPtr
|
||||
callback: t.CInt | t.CPtr
|
||||
active: t.CInt
|
||||
qh: uhci_qh | t.CPtr
|
||||
|
||||
_io_base: t.CUInt16T = 0
|
||||
_frame_list: t.CUInt32T | t.CPtr = None
|
||||
_ctrl_qh: uhci_qh | t.CPtr = None
|
||||
_bulk_qh: uhci_qh | t.CPtr = None
|
||||
_irq: t.CInt = -1
|
||||
_int_slots: t.CArray[int_slot, UHCI_INT_SLOTS]
|
||||
_int_slot_count: t.CInt = 0
|
||||
|
||||
def _reg_read16(offset: t.CUInt16T) -> t.CUInt16T:
|
||||
return asm.inw(_io_base + offset)
|
||||
|
||||
def _reg_write16(offset: t.CUInt16T, value: t.CUInt16T):
|
||||
asm.outw(_io_base + offset, value)
|
||||
|
||||
def _reg_read32(offset: t.CUInt16T) -> t.CUInt32T:
|
||||
return asm.inl(_io_base + offset)
|
||||
|
||||
def _reg_write32(offset: t.CUInt16T, value: t.CUInt32T):
|
||||
asm.outl(_io_base + offset, value)
|
||||
|
||||
def _uhci_irq_handler() -> t.CInt:
|
||||
sts: t.CUInt16T = _reg_read16(UHCI_USBSTS)
|
||||
_reg_write16(UHCI_USBSTS, sts)
|
||||
if (sts & (UHCI_STS_USBINT | UHCI_STS_USBERRINT)) == 0:
|
||||
return 0
|
||||
for si in range(_int_slot_count):
|
||||
slot: int_slot | t.CPtr = c.Addr(_int_slots[si])
|
||||
if slot.active and slot.td is not None and slot.callback is not None:
|
||||
status: t.CUInt32T = slot.td.ctrl_status
|
||||
if (status & TD_CTRL_ACTIVE) == 0:
|
||||
slot.active = 0
|
||||
c.Asm(f"""mov rbp, rsp
|
||||
and rsp, -16
|
||||
call {c.AsmInp(slot.callback, t.ASM_DESCR.REG_ANY)}
|
||||
mov rsp, rbp""",
|
||||
op=[t.ASM_DESCR.CLOBBER_MEMORY, t.ASM_DESCR.CLOBBER_RAX,
|
||||
t.ASM_DESCR.CLOBBER_RBX,
|
||||
t.ASM_DESCR.CLOBBER_RCX, t.ASM_DESCR.CLOBBER_RDX,
|
||||
t.ASM_DESCR.CLOBBER_RSI, t.ASM_DESCR.CLOBBER_RDI,
|
||||
t.ASM_DESCR.CLOBBER_R8, t.ASM_DESCR.CLOBBER_R9,
|
||||
t.ASM_DESCR.CLOBBER_R10, t.ASM_DESCR.CLOBBER_R11,
|
||||
t.ASM_DESCR.CLOBBER_RBP])
|
||||
return 0
|
||||
|
||||
def register_int_callback(cb: t.CInt | t.CPtr) -> t.CInt:
|
||||
global _int_slot_count
|
||||
if _int_slot_count >= UHCI_INT_SLOTS:
|
||||
return -1
|
||||
si: t.CInt = _int_slot_count
|
||||
qh: uhci_qh | t.CPtr = mm.malloc_direct(uhci_qh.__sizeof__())
|
||||
if qh is None:
|
||||
return -2
|
||||
string.memset(c.Addr(qh), 0, uhci_qh.__sizeof__())
|
||||
_qh_set_link(qh, 0, 0, 1)
|
||||
_qh_set_element(qh, 0, 1)
|
||||
td: uhci_td | t.CPtr = mm.malloc_direct(uhci_td.__sizeof__())
|
||||
if td is None:
|
||||
return -3
|
||||
string.memset(c.Addr(td), 0, uhci_td.__sizeof__())
|
||||
slot: int_slot | t.CPtr = c.Addr(_int_slots[si])
|
||||
slot.td = td
|
||||
slot.callback = cb
|
||||
slot.active = 0
|
||||
slot.qh = qh
|
||||
_int_slot_count = si + 1
|
||||
_rebuild_int_chain()
|
||||
return si
|
||||
|
||||
def schedule_int_transfer(slot_id: t.CInt, dev_addr: t.CUInt8T, endpoint: t.CUInt8T, ls: t.CInt, max_pkt: t.CUInt8T, toggle_ptr: t.CUInt8T | t.CPtr, buf: t.CVoid | t.CPtr):
|
||||
if slot_id < 0 or slot_id >= _int_slot_count:
|
||||
return
|
||||
slot: int_slot | t.CPtr = c.Addr(_int_slots[slot_id])
|
||||
td: uhci_td | t.CPtr = slot.td
|
||||
qh: uhci_qh | t.CPtr = slot.qh
|
||||
if td is None or qh is None:
|
||||
return
|
||||
string.memset(c.Addr(td), 0, uhci_td.__sizeof__())
|
||||
_td_set_link(td, 0, 0, 1)
|
||||
_td_set_ctrl(td, ls, max_pkt)
|
||||
_td_set_token(td, TD_TOKEN_IN, dev_addr, endpoint, toggle_ptr, max_pkt)
|
||||
td.ctrl_status = td.ctrl_status | TD_CTRL_IOC
|
||||
td.buffer = t.CUInt32T(t.CUInt64T(buf))
|
||||
_qh_set_element(qh, t.CUInt32T(t.CUInt64T(td)), 0)
|
||||
slot.active = 1
|
||||
|
||||
def _rebuild_int_chain():
|
||||
if _int_slot_count == 0:
|
||||
return
|
||||
first_qh: uhci_qh | t.CPtr = None
|
||||
prev_qh: uhci_qh | t.CPtr = None
|
||||
for si in range(_int_slot_count):
|
||||
cur_qh: uhci_qh | t.CPtr = _int_slots[si].qh
|
||||
if cur_qh is not None:
|
||||
if first_qh is None:
|
||||
first_qh = cur_qh
|
||||
if prev_qh is not None:
|
||||
_qh_set_link(prev_qh, t.CUInt32T(t.CUInt64T(cur_qh)) | TD_LINK_QH, 1, 0)
|
||||
prev_qh = cur_qh
|
||||
if prev_qh is not None:
|
||||
_qh_set_link(prev_qh, t.CUInt32T(t.CUInt64T(_ctrl_qh)) | TD_LINK_QH, 1, 0)
|
||||
if first_qh is not None:
|
||||
qh_addr: t.CUInt32T = t.CUInt32T(t.CUInt64T(first_qh)) | TD_LINK_QH
|
||||
i: t.CInt
|
||||
for i in range(UHCI_NUM_FRAMES):
|
||||
entry_ptr: t.CUInt32T | t.CPtr = _frame_list + t.CUInt64T(i) * 4
|
||||
c.Set(c.Deref(entry_ptr), qh_addr)
|
||||
|
||||
def _td_set_link(td: uhci_td | t.CPtr, addr: t.CUInt32T, is_qh: t.CInt, terminate: t.CInt):
|
||||
val: t.CUInt32T = (addr & 0xFFFFFFF0)
|
||||
if is_qh: val = val | TD_LINK_QH
|
||||
if terminate: val = val | TD_LINK_TERMINATE
|
||||
td.link = val
|
||||
|
||||
def _td_set_token(td: uhci_td | t.CPtr, pid: t.CUInt8T, dev_addr: t.CUInt8T, endpoint: t.CUInt8T, toggle: t.CUInt8T, max_len: t.CUInt16T):
|
||||
len_bits: t.CUInt32T
|
||||
if max_len == 0:
|
||||
len_bits = 0x7FF
|
||||
else:
|
||||
len_bits = t.CUInt32T(max_len) - 1
|
||||
td.token = (t.CUInt32T(pid) << 0) | (t.CUInt32T(dev_addr) << 8) | (t.CUInt32T(endpoint & 0x0F) << 15) | (t.CUInt32T(toggle & 1) << 19) | (len_bits << 21)
|
||||
|
||||
def _td_set_ctrl(td: uhci_td | t.CPtr, ls: t.CInt, maxlen: t.CUInt16T):
|
||||
td.ctrl_status = TD_CTRL_ACTIVE | (3 << TD_CTRL_CERR_SHIFT)
|
||||
if ls: td.ctrl_status = td.ctrl_status | TD_CTRL_LS
|
||||
|
||||
def _qh_set_link(qh: uhci_qh | t.CPtr, addr: t.CUInt32T, is_qh: t.CInt, terminate: t.CInt):
|
||||
val: t.CUInt32T = (addr & 0xFFFFFFF0)
|
||||
if is_qh: val = val | TD_LINK_QH
|
||||
if terminate: val = val | TD_LINK_TERMINATE
|
||||
qh.link = val
|
||||
|
||||
def _qh_set_element(qh: uhci_qh | t.CPtr, addr: t.CUInt32T, terminate: t.CInt):
|
||||
val: t.CUInt32T = (addr & 0xFFFFFFF0)
|
||||
if terminate: val = val | TD_LINK_TERMINATE
|
||||
qh.element = val
|
||||
|
||||
def _wait_for_complete(td: uhci_td | t.CPtr, timeout_ms: t.CInt) -> t.CInt:
|
||||
start: t.CUInt64T = timer.timer_get_ticks()
|
||||
deadline: t.CUInt64T = start + t.CUInt64T(timeout_ms)
|
||||
poll_cnt: t.CInt = 0
|
||||
while timer.timer_get_ticks() < deadline:
|
||||
status: t.CUInt32T = td.ctrl_status
|
||||
if (status & TD_CTRL_ACTIVE) == 0:
|
||||
if (status & 0x00600000) != 0:
|
||||
return -1
|
||||
return 0
|
||||
poll_cnt += 1
|
||||
if poll_cnt >= 100:
|
||||
poll_cnt = 0
|
||||
asm.sti()
|
||||
asm.hlt()
|
||||
return -2
|
||||
|
||||
def reset(io_base: t.CUInt16T) -> t.CInt:
|
||||
global _io_base
|
||||
_io_base = io_base
|
||||
_reg_write16(UHCI_USBCMD, UHCI_CMD_HCRESET)
|
||||
i: t.CInt
|
||||
for i in range(1000):
|
||||
if (_reg_read16(UHCI_USBCMD) & UHCI_CMD_HCRESET) == 0:
|
||||
break
|
||||
_reg_write16(UHCI_USBSTS, 0xFFFF)
|
||||
_reg_write16(UHCI_USBINTR, 0x0000)
|
||||
return 0
|
||||
|
||||
def init(io_base: t.CUInt16T) -> t.CInt:
|
||||
global _irq, _io_base, _frame_list, _ctrl_qh, _bulk_qh, _int_slot_count
|
||||
_io_base = io_base
|
||||
_int_slot_count = 0
|
||||
|
||||
serial.puts("[uhci] resetting...\n")
|
||||
if reset(io_base) != 0:
|
||||
serial.puts("[uhci] reset failed\n")
|
||||
return -1
|
||||
|
||||
serial.puts("[uhci] allocating frame list...\n")
|
||||
_frame_list = mm.malloc(UHCI_NUM_FRAMES * 4)
|
||||
_dbg_fl: t.CArray[t.CChar, 96]
|
||||
viperlib.snprintf(c.Addr(_dbg_fl), 96, "[dbg] frame_list ret=0x%lx\n", t.CUInt64T(_frame_list))
|
||||
serial.puts(c.Addr(_dbg_fl))
|
||||
if _frame_list is None:
|
||||
serial.puts("[uhci] frame list alloc failed\n")
|
||||
return -2
|
||||
string.memset(_frame_list, 0, UHCI_NUM_FRAMES * 4)
|
||||
|
||||
_ctrl_qh = mm.malloc_direct(uhci_qh.__sizeof__())
|
||||
if _ctrl_qh is None:
|
||||
serial.puts("[uhci] ctrl_qh alloc failed\n")
|
||||
return -3
|
||||
string.memset(c.Addr(_ctrl_qh), 0, uhci_qh.__sizeof__())
|
||||
_qh_set_link(_ctrl_qh, 0, 0, 1)
|
||||
_qh_set_element(_ctrl_qh, 0, 1)
|
||||
|
||||
_bulk_qh = mm.malloc_direct(uhci_qh.__sizeof__())
|
||||
if _bulk_qh is None:
|
||||
serial.puts("[uhci] bulk_qh alloc failed\n")
|
||||
return -4
|
||||
string.memset(c.Addr(_bulk_qh), 0, uhci_qh.__sizeof__())
|
||||
_qh_set_link(_bulk_qh, 0, 0, 1)
|
||||
_qh_set_element(_bulk_qh, 0, 1)
|
||||
|
||||
serial.puts("[uhci] setting up frame list...\n")
|
||||
qh_addr: t.CUInt32T = t.CUInt32T(c.Addr(_ctrl_qh)) | TD_LINK_QH
|
||||
i: t.CInt
|
||||
for i in range(UHCI_NUM_FRAMES):
|
||||
entry_ptr: t.CUInt32T | t.CPtr = _frame_list + t.CUInt64T(i) * 4
|
||||
c.Set(c.Deref(entry_ptr), qh_addr)
|
||||
|
||||
_reg_write32(UHCI_FLBASEADD, t.CUInt32T(t.CUInt64T(_frame_list)))
|
||||
_reg_write16(UHCI_FRNUM, 0)
|
||||
_reg_write16(UHCI_SOFMOD, 64)
|
||||
|
||||
_reg_write16(UHCI_USBCMD, UHCI_CMD_CF | UHCI_CMD_MAXPKT | UHCI_CMD_RUN)
|
||||
|
||||
timer.timer_msleep(10)
|
||||
|
||||
_reg_write16(UHCI_USBSTS, 0xFFFF)
|
||||
_reg_write16(UHCI_USBINTR, UHCI_INTR_IOC | UHCI_INTR_SHORT)
|
||||
|
||||
_irq = t.CInt(pci._uhci_dev.irq)
|
||||
if _irq > 0 and _irq < 16:
|
||||
idt.irqInstallHandler(_irq, _uhci_irq_handler, "uhci")
|
||||
pic.clearMask(t.CUInt8T(_irq))
|
||||
|
||||
serial.puts("[uhci] started\n")
|
||||
return 0
|
||||
|
||||
def port_reset(port: t.CInt) -> t.CInt:
|
||||
sc: t.CUInt16T
|
||||
if port == 0:
|
||||
sc = _reg_read16(UHCI_PORTSC1)
|
||||
else:
|
||||
sc = _reg_read16(UHCI_PORTSC2)
|
||||
|
||||
if (sc & UHCI_PORT_CONNECT) == 0:
|
||||
return -1
|
||||
|
||||
if port == 0:
|
||||
_reg_write16(UHCI_PORTSC1, sc | UHCI_PORT_CONNECT_CHANGE | UHCI_PORT_ENABLE_CHANGE)
|
||||
else:
|
||||
_reg_write16(UHCI_PORTSC2, sc | UHCI_PORT_CONNECT_CHANGE | UHCI_PORT_ENABLE_CHANGE)
|
||||
|
||||
if port == 0:
|
||||
_reg_write16(UHCI_PORTSC1, UHCI_PORT_RESET)
|
||||
else:
|
||||
_reg_write16(UHCI_PORTSC2, UHCI_PORT_RESET)
|
||||
|
||||
timer.timer_msleep(50)
|
||||
|
||||
if port == 0:
|
||||
_reg_write16(UHCI_PORTSC1, 0x0000)
|
||||
else:
|
||||
_reg_write16(UHCI_PORTSC2, 0x0000)
|
||||
|
||||
timer.timer_msleep(10)
|
||||
|
||||
if port == 0:
|
||||
sc = _reg_read16(UHCI_PORTSC1)
|
||||
_reg_write16(UHCI_PORTSC1, sc | UHCI_PORT_ENABLE | UHCI_PORT_CONNECT_CHANGE | UHCI_PORT_ENABLE_CHANGE)
|
||||
else:
|
||||
sc = _reg_read16(UHCI_PORTSC2)
|
||||
_reg_write16(UHCI_PORTSC2, sc | UHCI_PORT_ENABLE | UHCI_PORT_CONNECT_CHANGE | UHCI_PORT_ENABLE_CHANGE)
|
||||
|
||||
timer.timer_msleep(10)
|
||||
|
||||
if port == 0:
|
||||
sc = _reg_read16(UHCI_PORTSC1)
|
||||
else:
|
||||
sc = _reg_read16(UHCI_PORTSC2)
|
||||
|
||||
if (sc & UHCI_PORT_ENABLE) == 0:
|
||||
return -2
|
||||
|
||||
return 0
|
||||
|
||||
def port_is_connected(port: t.CInt) -> t.CInt:
|
||||
sc: t.CUInt16T
|
||||
if port == 0:
|
||||
sc = _reg_read16(UHCI_PORTSC1)
|
||||
else:
|
||||
sc = _reg_read16(UHCI_PORTSC2)
|
||||
if sc & UHCI_PORT_CONNECT: return 1
|
||||
return 0
|
||||
|
||||
def port_is_low_speed(port: t.CInt) -> t.CInt:
|
||||
sc: t.CUInt16T
|
||||
if port == 0:
|
||||
sc = _reg_read16(UHCI_PORTSC1)
|
||||
else:
|
||||
sc = _reg_read16(UHCI_PORTSC2)
|
||||
if sc & UHCI_PORT_LOW_SPEED: return 1
|
||||
return 0
|
||||
|
||||
def control_transfer(dev_addr: t.CUInt8T, endpoint: t.CUInt8T, ls: t.CInt, max_pkt: t.CUInt8T, setup_buf: t.CVoid | t.CPtr, data_buf: t.CVoid | t.CPtr, data_len: t.CUInt16T, data_in: t.CInt) -> t.CInt:
|
||||
td_count: t.CInt = 2
|
||||
if data_len > 0:
|
||||
td_count = td_count + 1
|
||||
total: t.CUInt64T = t.CUInt64T(td_count) * uhci_td.__sizeof__()
|
||||
tds: uhci_td | t.CPtr = mm.malloc_direct(total)
|
||||
if tds is None: return -1
|
||||
string.memset(c.Addr(tds), 0, total)
|
||||
|
||||
setup_td: uhci_td | t.CPtr = tds
|
||||
_td_set_link(setup_td, t.CUInt32T(t.CUInt64T(tds) + uhci_td.__sizeof__()), 0, 0)
|
||||
_td_set_ctrl(setup_td, ls, 8)
|
||||
_td_set_token(setup_td, TD_TOKEN_SETUP, dev_addr, endpoint, TD_TOKEN_DATA0, 8)
|
||||
setup_td.buffer = t.CUInt32T(t.CUInt64T(setup_buf))
|
||||
|
||||
if data_len > 0:
|
||||
data_td: uhci_td | t.CPtr = t.CPtr(t.CUInt64T(tds) + uhci_td.__sizeof__())
|
||||
_td_set_link(data_td, t.CUInt32T(t.CUInt64T(data_td) + uhci_td.__sizeof__()), 0, 0)
|
||||
_td_set_ctrl(data_td, ls, max_pkt)
|
||||
if data_in:
|
||||
_td_set_token(data_td, TD_TOKEN_IN, dev_addr, endpoint, TD_TOKEN_DATA1, data_len)
|
||||
else:
|
||||
_td_set_token(data_td, TD_TOKEN_OUT, dev_addr, endpoint, TD_TOKEN_DATA1, data_len)
|
||||
data_td.buffer = t.CUInt32T(t.CUInt64T(data_buf))
|
||||
|
||||
status_td: uhci_td | t.CPtr = t.CPtr(t.CUInt64T(data_td) + uhci_td.__sizeof__())
|
||||
_td_set_link(status_td, 0, 0, 1)
|
||||
_td_set_ctrl(status_td, ls, max_pkt)
|
||||
if data_in:
|
||||
_td_set_token(status_td, TD_TOKEN_OUT, dev_addr, endpoint, TD_TOKEN_DATA1, 0)
|
||||
else:
|
||||
_td_set_token(status_td, TD_TOKEN_IN, dev_addr, endpoint, TD_TOKEN_DATA1, 0)
|
||||
status_td.buffer = 0
|
||||
else:
|
||||
status_td: uhci_td | t.CPtr = t.CPtr(t.CUInt64T(tds) + uhci_td.__sizeof__())
|
||||
_td_set_link(status_td, 0, 0, 1)
|
||||
_td_set_ctrl(status_td, ls, max_pkt)
|
||||
_td_set_token(status_td, TD_TOKEN_IN, dev_addr, endpoint, TD_TOKEN_DATA1, 0)
|
||||
status_td.buffer = 0
|
||||
|
||||
_qh_set_element(_ctrl_qh, t.CUInt32T(t.CUInt64T(setup_td)), 0)
|
||||
|
||||
result: t.CInt = _wait_for_complete(status_td, 500)
|
||||
|
||||
_qh_set_element(_ctrl_qh, 0, 1)
|
||||
mm.free(tds)
|
||||
return result
|
||||
import t, c
|
||||
import asm
|
||||
import mm.mm as mm
|
||||
import viperstring as string
|
||||
import drivers.serial.uart.serial as serial
|
||||
import platform.pch.timer as timer
|
||||
import intr.idt as idt
|
||||
import platform.pch.pic as pic
|
||||
import drivers.usb.pci as pci
|
||||
import viperlib
|
||||
|
||||
UHCI_USBCMD: t.CDefine = 0x00
|
||||
UHCI_USBSTS: t.CDefine = 0x02
|
||||
UHCI_USBINTR: t.CDefine = 0x04
|
||||
UHCI_FRNUM: t.CDefine = 0x06
|
||||
UHCI_FLBASEADD: t.CDefine = 0x08
|
||||
UHCI_SOFMOD: t.CDefine = 0x0C
|
||||
UHCI_PORTSC1: t.CDefine = 0x10
|
||||
UHCI_PORTSC2: t.CDefine = 0x12
|
||||
|
||||
UHCI_CMD_RUN: t.CDefine = 0x0001
|
||||
UHCI_CMD_HCRESET: t.CDefine = 0x0002
|
||||
UHCI_CMD_GRESET: t.CDefine = 0x0004
|
||||
UHCI_CMD_MAXPKT: t.CDefine = 0x0080
|
||||
UHCI_CMD_CF: t.CDefine = 0x0040
|
||||
|
||||
UHCI_STS_HCHALTED: t.CDefine = 0x0020
|
||||
UHCI_STS_USBINT: t.CDefine = 0x0001
|
||||
UHCI_STS_USBERRINT: t.CDefine = 0x0002
|
||||
UHCI_STS_RESUME: t.CDefine = 0x0004
|
||||
UHCI_INTR_TIMEOUT: t.CDefine = 0x0001
|
||||
UHCI_INTR_RESUME: t.CDefine = 0x0002
|
||||
UHCI_INTR_IOC: t.CDefine = 0x0004
|
||||
UHCI_INTR_SHORT: t.CDefine = 0x0008
|
||||
|
||||
UHCI_PORT_CONNECT: t.CDefine = 0x0001
|
||||
UHCI_PORT_CONNECT_CHANGE: t.CDefine = 0x0002
|
||||
UHCI_PORT_ENABLE: t.CDefine = 0x0004
|
||||
UHCI_PORT_ENABLE_CHANGE: t.CDefine = 0x0008
|
||||
UHCI_PORT_RESET: t.CDefine = 0x0200
|
||||
UHCI_PORT_LOW_SPEED: t.CDefine = 0x0100
|
||||
|
||||
TD_CTRL_ACTIVE: t.CDefine = 0x00800000
|
||||
TD_CTRL_IOC: t.CDefine = 0x01000000
|
||||
TD_CTRL_LS: t.CDefine = 0x04000000
|
||||
TD_CTRL_SPD: t.CDefine = 0x20000000
|
||||
TD_CTRL_CERR_SHIFT: t.CDefine = 27
|
||||
TD_CTRL_CERR_MASK: t.CDefine = 0x18000000
|
||||
|
||||
TD_TOKEN_SETUP: t.CDefine = 0x2D
|
||||
TD_TOKEN_IN: t.CDefine = 0x69
|
||||
TD_TOKEN_OUT: t.CDefine = 0xE1
|
||||
|
||||
TD_TOKEN_DATA0: t.CDefine = 0
|
||||
TD_TOKEN_DATA1: t.CDefine = 1
|
||||
|
||||
TD_LINK_TERMINATE: t.CDefine = 0x00000001
|
||||
TD_LINK_QH: t.CDefine = 0x00000002
|
||||
TD_LINK_DEPTH_FIRST: t.CDefine = 0x00000004
|
||||
|
||||
UHCI_NUM_FRAMES: t.CDefine = 1024
|
||||
UHCI_INT_SLOTS: t.CDefine = 4
|
||||
|
||||
class uhci_td(t.CStruct):
|
||||
link: uint32
|
||||
ctrl_status: uint32
|
||||
token: uint32
|
||||
buffer: uint32
|
||||
|
||||
class uhci_qh(t.CStruct):
|
||||
link: uint32
|
||||
element: uint32
|
||||
|
||||
class int_slot(t.CStruct):
|
||||
td: uhci_td | t.CPtr
|
||||
callback: int | t.CPtr
|
||||
active: int
|
||||
qh: uhci_qh | t.CPtr
|
||||
|
||||
_io_base: uint16 = 0
|
||||
_frame_list: uint32 | t.CPtr = None
|
||||
_ctrl_qh: uhci_qh | t.CPtr = None
|
||||
_bulk_qh: uhci_qh | t.CPtr = None
|
||||
_irq: int = -1
|
||||
_int_slots: t.CArray[int_slot, UHCI_INT_SLOTS]
|
||||
_int_slot_count: int = 0
|
||||
|
||||
def _reg_read16(offset: uint16) -> uint16:
|
||||
return asm.inw(_io_base + offset)
|
||||
|
||||
def _reg_write16(offset: uint16, value: uint16):
|
||||
asm.outw(_io_base + offset, value)
|
||||
|
||||
def _reg_read32(offset: uint16) -> uint32:
|
||||
return asm.inl(_io_base + offset)
|
||||
|
||||
def _reg_write32(offset: uint16, value: uint32):
|
||||
asm.outl(_io_base + offset, value)
|
||||
|
||||
def _uhci_irq_handler() -> int:
|
||||
sts: uint16 = _reg_read16(UHCI_USBSTS)
|
||||
_reg_write16(UHCI_USBSTS, sts)
|
||||
if (sts & (UHCI_STS_USBINT | UHCI_STS_USBERRINT)) == 0:
|
||||
return 0
|
||||
for si in range(_int_slot_count):
|
||||
slot: int_slot | t.CPtr = c.Addr(_int_slots[si])
|
||||
if slot.active and slot.td is not None and slot.callback is not None:
|
||||
status: uint32 = slot.td.ctrl_status
|
||||
if (status & TD_CTRL_ACTIVE) == 0:
|
||||
slot.active = 0
|
||||
c.Asm(f"""mov rbp, rsp
|
||||
and rsp, -16
|
||||
call {c.AsmInp(slot.callback, t.ASM_DESCR.REG_ANY)}
|
||||
mov rsp, rbp""",
|
||||
op=[t.ASM_DESCR.CLOBBER_MEMORY, t.ASM_DESCR.CLOBBER_RAX,
|
||||
t.ASM_DESCR.CLOBBER_RBX,
|
||||
t.ASM_DESCR.CLOBBER_RCX, t.ASM_DESCR.CLOBBER_RDX,
|
||||
t.ASM_DESCR.CLOBBER_RSI, t.ASM_DESCR.CLOBBER_RDI,
|
||||
t.ASM_DESCR.CLOBBER_R8, t.ASM_DESCR.CLOBBER_R9,
|
||||
t.ASM_DESCR.CLOBBER_R10, t.ASM_DESCR.CLOBBER_R11,
|
||||
t.ASM_DESCR.CLOBBER_RBP])
|
||||
return 0
|
||||
|
||||
def register_int_callback(cb: int | t.CPtr) -> int:
|
||||
global _int_slot_count
|
||||
if _int_slot_count >= UHCI_INT_SLOTS:
|
||||
return -1
|
||||
si: int = _int_slot_count
|
||||
qh: uhci_qh | t.CPtr = mm.malloc_direct(uhci_qh.__sizeof__())
|
||||
if qh is None:
|
||||
return -2
|
||||
string.memset(c.Addr(qh), 0, uhci_qh.__sizeof__())
|
||||
_qh_set_link(qh, 0, 0, 1)
|
||||
_qh_set_element(qh, 0, 1)
|
||||
td: uhci_td | t.CPtr = mm.malloc_direct(uhci_td.__sizeof__())
|
||||
if td is None:
|
||||
return -3
|
||||
string.memset(c.Addr(td), 0, uhci_td.__sizeof__())
|
||||
slot: int_slot | t.CPtr = c.Addr(_int_slots[si])
|
||||
slot.td = td
|
||||
slot.callback = cb
|
||||
slot.active = 0
|
||||
slot.qh = qh
|
||||
_int_slot_count = si + 1
|
||||
_rebuild_int_chain()
|
||||
return si
|
||||
|
||||
def schedule_int_transfer(slot_id: int, dev_addr: uint8, endpoint: uint8, ls: int, max_pkt: uint8, toggle_ptr: uint8 | t.CPtr, buf: t.CPtr):
|
||||
if slot_id < 0 or slot_id >= _int_slot_count:
|
||||
return
|
||||
slot: int_slot | t.CPtr = c.Addr(_int_slots[slot_id])
|
||||
td: uhci_td | t.CPtr = slot.td
|
||||
qh: uhci_qh | t.CPtr = slot.qh
|
||||
if td is None or qh is None:
|
||||
return
|
||||
string.memset(c.Addr(td), 0, uhci_td.__sizeof__())
|
||||
_td_set_link(td, 0, 0, 1)
|
||||
_td_set_ctrl(td, ls, max_pkt)
|
||||
_td_set_token(td, TD_TOKEN_IN, dev_addr, endpoint, toggle_ptr, max_pkt)
|
||||
td.ctrl_status = td.ctrl_status | TD_CTRL_IOC
|
||||
td.buffer = uint32(uint64(buf))
|
||||
_qh_set_element(qh, uint32(uint64(td)), 0)
|
||||
slot.active = 1
|
||||
|
||||
def _rebuild_int_chain():
|
||||
if _int_slot_count == 0:
|
||||
return
|
||||
first_qh: uhci_qh | t.CPtr = None
|
||||
prev_qh: uhci_qh | t.CPtr = None
|
||||
for si in range(_int_slot_count):
|
||||
cur_qh: uhci_qh | t.CPtr = _int_slots[si].qh
|
||||
if cur_qh is not None:
|
||||
if first_qh is None:
|
||||
first_qh = cur_qh
|
||||
if prev_qh is not None:
|
||||
_qh_set_link(prev_qh, uint32(uint64(cur_qh)) | TD_LINK_QH, 1, 0)
|
||||
prev_qh = cur_qh
|
||||
if prev_qh is not None:
|
||||
_qh_set_link(prev_qh, uint32(uint64(_ctrl_qh)) | TD_LINK_QH, 1, 0)
|
||||
if first_qh is not None:
|
||||
qh_addr: uint32 = uint32(uint64(first_qh)) | TD_LINK_QH
|
||||
i: int
|
||||
for i in range(UHCI_NUM_FRAMES):
|
||||
entry_ptr: uint32 | t.CPtr = _frame_list + uint64(i) * 4
|
||||
c.Set(c.Deref(entry_ptr), qh_addr)
|
||||
|
||||
def _td_set_link(td: uhci_td | t.CPtr, addr: uint32, is_qh: int, terminate: int):
|
||||
val: uint32 = (addr & 0xFFFFFFF0)
|
||||
if is_qh: val = val | TD_LINK_QH
|
||||
if terminate: val = val | TD_LINK_TERMINATE
|
||||
td.link = val
|
||||
|
||||
def _td_set_token(td: uhci_td | t.CPtr, pid: uint8, dev_addr: uint8, endpoint: uint8, toggle: uint8, max_len: uint16):
|
||||
len_bits: uint32
|
||||
if max_len == 0:
|
||||
len_bits = 0x7FF
|
||||
else:
|
||||
len_bits = uint32(max_len) - 1
|
||||
td.token = (uint32(pid) << 0) | (uint32(dev_addr) << 8) | (uint32(endpoint & 0x0F) << 15) | (uint32(toggle & 1) << 19) | (len_bits << 21)
|
||||
|
||||
def _td_set_ctrl(td: uhci_td | t.CPtr, ls: int, maxlen: uint16):
|
||||
td.ctrl_status = TD_CTRL_ACTIVE | (3 << TD_CTRL_CERR_SHIFT)
|
||||
if ls: td.ctrl_status = td.ctrl_status | TD_CTRL_LS
|
||||
|
||||
def _qh_set_link(qh: uhci_qh | t.CPtr, addr: uint32, is_qh: int, terminate: int):
|
||||
val: uint32 = (addr & 0xFFFFFFF0)
|
||||
if is_qh: val = val | TD_LINK_QH
|
||||
if terminate: val = val | TD_LINK_TERMINATE
|
||||
qh.link = val
|
||||
|
||||
def _qh_set_element(qh: uhci_qh | t.CPtr, addr: uint32, terminate: int):
|
||||
val: uint32 = (addr & 0xFFFFFFF0)
|
||||
if terminate: val = val | TD_LINK_TERMINATE
|
||||
qh.element = val
|
||||
|
||||
def _wait_for_complete(td: uhci_td | t.CPtr, timeout_ms: int) -> int:
|
||||
start: uint64 = timer.timer_get_ticks()
|
||||
deadline: uint64 = start + uint64(timeout_ms)
|
||||
poll_cnt: int = 0
|
||||
while timer.timer_get_ticks() < deadline:
|
||||
status: uint32 = td.ctrl_status
|
||||
if (status & TD_CTRL_ACTIVE) == 0:
|
||||
if (status & 0x00600000) != 0:
|
||||
return -1
|
||||
return 0
|
||||
poll_cnt += 1
|
||||
if poll_cnt >= 100:
|
||||
poll_cnt = 0
|
||||
asm.sti()
|
||||
asm.hlt()
|
||||
return -2
|
||||
|
||||
def reset(io_base: uint16) -> int:
|
||||
global _io_base
|
||||
_io_base = io_base
|
||||
_reg_write16(UHCI_USBCMD, UHCI_CMD_HCRESET)
|
||||
i: int
|
||||
for i in range(1000):
|
||||
if (_reg_read16(UHCI_USBCMD) & UHCI_CMD_HCRESET) == 0:
|
||||
break
|
||||
_reg_write16(UHCI_USBSTS, 0xFFFF)
|
||||
_reg_write16(UHCI_USBINTR, 0x0000)
|
||||
return 0
|
||||
|
||||
def init(io_base: uint16) -> int:
|
||||
global _irq, _io_base, _frame_list, _ctrl_qh, _bulk_qh, _int_slot_count
|
||||
_io_base = io_base
|
||||
_int_slot_count = 0
|
||||
|
||||
serial.puts("[uhci] resetting...\n")
|
||||
if reset(io_base) != 0:
|
||||
serial.puts("[uhci] reset failed\n")
|
||||
return -1
|
||||
|
||||
serial.puts("[uhci] allocating frame list...\n")
|
||||
_frame_list = mm.malloc(UHCI_NUM_FRAMES * 4)
|
||||
_dbg_fl: t.CArray[t.CChar, 96]
|
||||
viperlib.snprintf(c.Addr(_dbg_fl), 96, "[dbg] frame_list ret=0x%lx\n", uint64(_frame_list))
|
||||
serial.puts(c.Addr(_dbg_fl))
|
||||
if _frame_list is None:
|
||||
serial.puts("[uhci] frame list alloc failed\n")
|
||||
return -2
|
||||
string.memset(_frame_list, 0, UHCI_NUM_FRAMES * 4)
|
||||
|
||||
_ctrl_qh = mm.malloc_direct(uhci_qh.__sizeof__())
|
||||
if _ctrl_qh is None:
|
||||
serial.puts("[uhci] ctrl_qh alloc failed\n")
|
||||
return -3
|
||||
string.memset(c.Addr(_ctrl_qh), 0, uhci_qh.__sizeof__())
|
||||
_qh_set_link(_ctrl_qh, 0, 0, 1)
|
||||
_qh_set_element(_ctrl_qh, 0, 1)
|
||||
|
||||
_bulk_qh = mm.malloc_direct(uhci_qh.__sizeof__())
|
||||
if _bulk_qh is None:
|
||||
serial.puts("[uhci] bulk_qh alloc failed\n")
|
||||
return -4
|
||||
string.memset(c.Addr(_bulk_qh), 0, uhci_qh.__sizeof__())
|
||||
_qh_set_link(_bulk_qh, 0, 0, 1)
|
||||
_qh_set_element(_bulk_qh, 0, 1)
|
||||
|
||||
serial.puts("[uhci] setting up frame list...\n")
|
||||
qh_addr: uint32 = uint32(c.Addr(_ctrl_qh)) | TD_LINK_QH
|
||||
i: int
|
||||
for i in range(UHCI_NUM_FRAMES):
|
||||
entry_ptr: uint32 | t.CPtr = _frame_list + uint64(i) * 4
|
||||
c.Set(c.Deref(entry_ptr), qh_addr)
|
||||
|
||||
_reg_write32(UHCI_FLBASEADD, uint32(uint64(_frame_list)))
|
||||
_reg_write16(UHCI_FRNUM, 0)
|
||||
_reg_write16(UHCI_SOFMOD, 64)
|
||||
|
||||
_reg_write16(UHCI_USBCMD, UHCI_CMD_CF | UHCI_CMD_MAXPKT | UHCI_CMD_RUN)
|
||||
|
||||
timer.timer_msleep(10)
|
||||
|
||||
_reg_write16(UHCI_USBSTS, 0xFFFF)
|
||||
_reg_write16(UHCI_USBINTR, UHCI_INTR_IOC | UHCI_INTR_SHORT)
|
||||
|
||||
_irq = int(pci._uhci_dev.irq)
|
||||
if _irq > 0 and _irq < 16:
|
||||
idt.irqInstallHandler(_irq, _uhci_irq_handler, "uhci")
|
||||
pic.clearMask(uint8(_irq))
|
||||
|
||||
serial.puts("[uhci] started\n")
|
||||
return 0
|
||||
|
||||
def port_reset(port: int) -> int:
|
||||
sc: uint16
|
||||
if port == 0:
|
||||
sc = _reg_read16(UHCI_PORTSC1)
|
||||
else:
|
||||
sc = _reg_read16(UHCI_PORTSC2)
|
||||
|
||||
if (sc & UHCI_PORT_CONNECT) == 0:
|
||||
return -1
|
||||
|
||||
if port == 0:
|
||||
_reg_write16(UHCI_PORTSC1, sc | UHCI_PORT_CONNECT_CHANGE | UHCI_PORT_ENABLE_CHANGE)
|
||||
else:
|
||||
_reg_write16(UHCI_PORTSC2, sc | UHCI_PORT_CONNECT_CHANGE | UHCI_PORT_ENABLE_CHANGE)
|
||||
|
||||
if port == 0:
|
||||
_reg_write16(UHCI_PORTSC1, UHCI_PORT_RESET)
|
||||
else:
|
||||
_reg_write16(UHCI_PORTSC2, UHCI_PORT_RESET)
|
||||
|
||||
timer.timer_msleep(50)
|
||||
|
||||
if port == 0:
|
||||
_reg_write16(UHCI_PORTSC1, 0x0000)
|
||||
else:
|
||||
_reg_write16(UHCI_PORTSC2, 0x0000)
|
||||
|
||||
timer.timer_msleep(10)
|
||||
|
||||
if port == 0:
|
||||
sc = _reg_read16(UHCI_PORTSC1)
|
||||
_reg_write16(UHCI_PORTSC1, sc | UHCI_PORT_ENABLE | UHCI_PORT_CONNECT_CHANGE | UHCI_PORT_ENABLE_CHANGE)
|
||||
else:
|
||||
sc = _reg_read16(UHCI_PORTSC2)
|
||||
_reg_write16(UHCI_PORTSC2, sc | UHCI_PORT_ENABLE | UHCI_PORT_CONNECT_CHANGE | UHCI_PORT_ENABLE_CHANGE)
|
||||
|
||||
timer.timer_msleep(10)
|
||||
|
||||
if port == 0:
|
||||
sc = _reg_read16(UHCI_PORTSC1)
|
||||
else:
|
||||
sc = _reg_read16(UHCI_PORTSC2)
|
||||
|
||||
if (sc & UHCI_PORT_ENABLE) == 0:
|
||||
return -2
|
||||
|
||||
return 0
|
||||
|
||||
def port_is_connected(port: int) -> int:
|
||||
sc: uint16
|
||||
if port == 0:
|
||||
sc = _reg_read16(UHCI_PORTSC1)
|
||||
else:
|
||||
sc = _reg_read16(UHCI_PORTSC2)
|
||||
if sc & UHCI_PORT_CONNECT: return 1
|
||||
return 0
|
||||
|
||||
def port_is_low_speed(port: int) -> int:
|
||||
sc: uint16
|
||||
if port == 0:
|
||||
sc = _reg_read16(UHCI_PORTSC1)
|
||||
else:
|
||||
sc = _reg_read16(UHCI_PORTSC2)
|
||||
if sc & UHCI_PORT_LOW_SPEED: return 1
|
||||
return 0
|
||||
|
||||
def control_transfer(dev_addr: uint8, endpoint: uint8, ls: int, max_pkt: uint8, setup_buf: t.CPtr, data_buf: t.CPtr, data_len: uint16, data_in: int) -> int:
|
||||
td_count: int = 2
|
||||
if data_len > 0:
|
||||
td_count = td_count + 1
|
||||
total: uint64 = uint64(td_count) * uhci_td.__sizeof__()
|
||||
tds: uhci_td | t.CPtr = mm.malloc_direct(total)
|
||||
if tds is None: return -1
|
||||
string.memset(c.Addr(tds), 0, total)
|
||||
|
||||
setup_td: uhci_td | t.CPtr = tds
|
||||
_td_set_link(setup_td, uint32(uint64(tds) + uhci_td.__sizeof__()), 0, 0)
|
||||
_td_set_ctrl(setup_td, ls, 8)
|
||||
_td_set_token(setup_td, TD_TOKEN_SETUP, dev_addr, endpoint, TD_TOKEN_DATA0, 8)
|
||||
setup_td.buffer = uint32(uint64(setup_buf))
|
||||
|
||||
if data_len > 0:
|
||||
data_td: uhci_td | t.CPtr = t.CPtr(uint64(tds) + uhci_td.__sizeof__())
|
||||
_td_set_link(data_td, uint32(uint64(data_td) + uhci_td.__sizeof__()), 0, 0)
|
||||
_td_set_ctrl(data_td, ls, max_pkt)
|
||||
if data_in:
|
||||
_td_set_token(data_td, TD_TOKEN_IN, dev_addr, endpoint, TD_TOKEN_DATA1, data_len)
|
||||
else:
|
||||
_td_set_token(data_td, TD_TOKEN_OUT, dev_addr, endpoint, TD_TOKEN_DATA1, data_len)
|
||||
data_td.buffer = uint32(uint64(data_buf))
|
||||
|
||||
status_td: uhci_td | t.CPtr = t.CPtr(uint64(data_td) + uhci_td.__sizeof__())
|
||||
_td_set_link(status_td, 0, 0, 1)
|
||||
_td_set_ctrl(status_td, ls, max_pkt)
|
||||
if data_in:
|
||||
_td_set_token(status_td, TD_TOKEN_OUT, dev_addr, endpoint, TD_TOKEN_DATA1, 0)
|
||||
else:
|
||||
_td_set_token(status_td, TD_TOKEN_IN, dev_addr, endpoint, TD_TOKEN_DATA1, 0)
|
||||
status_td.buffer = 0
|
||||
else:
|
||||
status_td: uhci_td | t.CPtr = t.CPtr(uint64(tds) + uhci_td.__sizeof__())
|
||||
_td_set_link(status_td, 0, 0, 1)
|
||||
_td_set_ctrl(status_td, ls, max_pkt)
|
||||
_td_set_token(status_td, TD_TOKEN_IN, dev_addr, endpoint, TD_TOKEN_DATA1, 0)
|
||||
status_td.buffer = 0
|
||||
|
||||
_qh_set_element(_ctrl_qh, uint32(uint64(setup_td)), 0)
|
||||
|
||||
result: int = _wait_for_complete(status_td, 500)
|
||||
|
||||
_qh_set_element(_ctrl_qh, 0, 1)
|
||||
mm.free(tds)
|
||||
return result
|
||||
+333
-330
@@ -1,330 +1,333 @@
|
||||
import t, c
|
||||
import mm.mm as mm
|
||||
import viperstring as string
|
||||
import drivers.serial.uart.serial as serial
|
||||
import drivers.usb.uhci as uhci
|
||||
import drivers.usb.pci as pci
|
||||
import platform.pch.timer as timer
|
||||
import viperlib
|
||||
|
||||
USB_DESC_DEVICE: t.CDefine = 1
|
||||
USB_DESC_CONFIG: t.CDefine = 2
|
||||
USB_DESC_STRING: t.CDefine = 3
|
||||
USB_DESC_INTERFACE: t.CDefine = 4
|
||||
USB_DESC_ENDPOINT: t.CDefine = 5
|
||||
|
||||
USB_REQ_GET_STATUS: t.CDefine = 0
|
||||
USB_REQ_CLEAR_FEATURE: t.CDefine = 1
|
||||
USB_REQ_SET_FEATURE: t.CDefine = 3
|
||||
USB_REQ_SET_ADDRESS: t.CDefine = 5
|
||||
USB_REQ_GET_DESCRIPTOR: t.CDefine = 6
|
||||
USB_REQ_SET_DESCRIPTOR: t.CDefine = 7
|
||||
USB_REQ_GET_CONFIGURATION: t.CDefine = 8
|
||||
USB_REQ_SET_CONFIGURATION: t.CDefine = 9
|
||||
|
||||
USB_REQ_SET_INTERFACE: t.CDefine = 11
|
||||
|
||||
HID_CLASS: t.CDefine = 0x03
|
||||
HID_SUBCLASS_BOOT: t.CDefine = 0x01
|
||||
HID_PROTO_KEYBOARD: t.CDefine = 0x01
|
||||
HID_PROTO_MOUSE: t.CDefine = 0x02
|
||||
|
||||
HID_REQ_SET_PROTOCOL: t.CDefine = 0x0B
|
||||
HID_REQ_SET_IDLE: t.CDefine = 0x0A
|
||||
HID_REQ_GET_REPORT: t.CDefine = 0x01
|
||||
|
||||
USB_MAX_DEVICES: t.CDefine = 8
|
||||
|
||||
class usb_dev_desc(t.CStruct):
|
||||
bLength: t.CUInt8T
|
||||
bDescriptorType: t.CUInt8T
|
||||
bcdUSB: t.CUInt16T
|
||||
bDeviceClass: t.CUInt8T
|
||||
bDeviceSubClass: t.CUInt8T
|
||||
bDeviceProtocol: t.CUInt8T
|
||||
bMaxPacketSize0: t.CUInt8T
|
||||
idVendor: t.CUInt16T
|
||||
idProduct: t.CUInt16T
|
||||
bcdDevice: t.CUInt16T
|
||||
iManufacturer: t.CUInt8T
|
||||
iProduct: t.CUInt8T
|
||||
iSerialNumber: t.CUInt8T
|
||||
bNumConfigurations: t.CUInt8T
|
||||
|
||||
class usb_config_desc(t.CStruct):
|
||||
bLength: t.CUInt8T
|
||||
bDescriptorType: t.CUInt8T
|
||||
wTotalLength: t.CUInt16T
|
||||
bNumInterfaces: t.CUInt8T
|
||||
bConfigurationValue: t.CUInt8T
|
||||
iConfiguration: t.CUInt8T
|
||||
bmAttributes: t.CUInt8T
|
||||
bMaxPower: t.CUInt8T
|
||||
|
||||
class usb_iface_desc(t.CStruct):
|
||||
bLength: t.CUInt8T
|
||||
bDescriptorType: t.CUInt8T
|
||||
bInterfaceNumber: t.CUInt8T
|
||||
bAlternateSetting: t.CUInt8T
|
||||
bNumEndpoints: t.CUInt8T
|
||||
bInterfaceClass: t.CUInt8T
|
||||
bInterfaceSubClass: t.CUInt8T
|
||||
bInterfaceProtocol: t.CUInt8T
|
||||
iInterface: t.CUInt8T
|
||||
|
||||
class usb_ep_desc(t.CStruct):
|
||||
bLength: t.CUInt8T
|
||||
bDescriptorType: t.CUInt8T
|
||||
bEndpointAddress: t.CUInt8T
|
||||
bmAttributes: t.CUInt8T
|
||||
wMaxPacketSize: t.CUInt16T
|
||||
bInterval: t.CUInt8T
|
||||
|
||||
class usb_setup_pkt(t.CStruct):
|
||||
bmRequestType: t.CUInt8T
|
||||
bRequest: t.CUInt8T
|
||||
wValue: t.CUInt16T
|
||||
wIndex: t.CUInt16T
|
||||
wLength: t.CUInt16T
|
||||
|
||||
class usb_device(t.CStruct):
|
||||
addr: t.CUInt8T
|
||||
ls: t.CInt
|
||||
max_pkt0: t.CUInt8T
|
||||
iface_class: t.CUInt8T
|
||||
iface_subclass: t.CUInt8T
|
||||
iface_protocol: t.CUInt8T
|
||||
iface_num: t.CUInt8T
|
||||
ep_in: t.CUInt8T
|
||||
ep_in_max: t.CUInt16T
|
||||
ep_in_interval: t.CUInt8T
|
||||
ep_in_toggle: t.CUInt8T
|
||||
configured: t.CInt
|
||||
|
||||
_devices: t.CArray[usb_device, USB_MAX_DEVICES]
|
||||
_device_count: t.CInt = 0
|
||||
|
||||
def _setup_packet(bmRequestType: t.CUInt8T, bRequest: t.CUInt8T, wValue: t.CUInt16T, wIndex: t.CUInt16T, wLength: t.CUInt16T, buf: usb_setup_pkt | t.CPtr):
|
||||
buf.bmRequestType = bmRequestType
|
||||
buf.bRequest = bRequest
|
||||
buf.wValue = wValue
|
||||
buf.wIndex = wIndex
|
||||
buf.wLength = wLength
|
||||
|
||||
def _send_control(dev_addr: t.CUInt8T, ls: t.CInt, max_pkt: t.CUInt8T, setup: usb_setup_pkt | t.CPtr, data_buf: t.CVoid | t.CPtr, data_len: t.CUInt16T, data_in: t.CInt) -> t.CInt:
|
||||
return uhci.control_transfer(dev_addr, 0, ls, max_pkt, c.Addr(setup), data_buf, data_len, data_in)
|
||||
|
||||
def get_descriptor(dev_addr: t.CUInt8T, ls: t.CInt, max_pkt: t.CUInt8T, desc_type: t.CUInt8T, desc_idx: t.CUInt8T, buf: t.CVoid | t.CPtr, length: t.CUInt16T) -> t.CInt:
|
||||
setup: usb_setup_pkt
|
||||
_setup_packet(0x80, USB_REQ_GET_DESCRIPTOR, (t.CUInt16T(desc_type) << 8) | desc_idx, 0, length, c.Addr(setup))
|
||||
return _send_control(dev_addr, ls, max_pkt, c.Addr(setup), buf, length, 1)
|
||||
|
||||
def set_address(dev_addr: t.CUInt8T, ls: t.CInt, max_pkt: t.CUInt8T, new_addr: t.CUInt8T) -> t.CInt:
|
||||
setup: usb_setup_pkt
|
||||
_setup_packet(0x00, USB_REQ_SET_ADDRESS, new_addr, 0, 0, c.Addr(setup))
|
||||
return _send_control(dev_addr, ls, max_pkt, c.Addr(setup), None, 0, 0)
|
||||
|
||||
def set_configuration(dev_addr: t.CUInt8T, ls: t.CInt, max_pkt: t.CUInt8T, config_val: t.CUInt8T) -> t.CInt:
|
||||
setup: usb_setup_pkt
|
||||
_setup_packet(0x00, USB_REQ_SET_CONFIGURATION, config_val, 0, 0, c.Addr(setup))
|
||||
return _send_control(dev_addr, ls, max_pkt, c.Addr(setup), None, 0, 0)
|
||||
|
||||
def hid_set_protocol(dev_addr: t.CUInt8T, ls: t.CInt, max_pkt: t.CUInt8T, iface: t.CUInt8T, protocol: t.CUInt8T) -> t.CInt:
|
||||
setup: usb_setup_pkt
|
||||
_setup_packet(0x21, HID_REQ_SET_PROTOCOL, protocol, t.CUInt16T(iface), 0, c.Addr(setup))
|
||||
return _send_control(dev_addr, ls, max_pkt, c.Addr(setup), None, 0, 0)
|
||||
|
||||
def hid_set_idle(dev_addr: t.CUInt8T, ls: t.CInt, max_pkt: t.CUInt8T, iface: t.CUInt8T, duration: t.CUInt8T) -> t.CInt:
|
||||
setup: usb_setup_pkt
|
||||
_setup_packet(0x21, HID_REQ_SET_IDLE, t.CUInt16T(duration) << 8, t.CUInt16T(iface), 0, c.Addr(setup))
|
||||
return _send_control(dev_addr, ls, max_pkt, c.Addr(setup), None, 0, 0)
|
||||
|
||||
def _parse_config(dev: usb_device | t.CPtr, config_buf: t.CVoid | t.CPtr, total_len: t.CUInt16T):
|
||||
offset: t.CInt = 0
|
||||
found_hid: t.CInt = 0
|
||||
while offset < t.CInt(total_len):
|
||||
p: t.CUInt8T | t.CPtr = config_buf + t.CUInt64T(offset)
|
||||
desc_len: t.CUInt8T = c.Deref(p)
|
||||
p2: t.CUInt8T | t.CPtr = config_buf + t.CUInt64T(offset) + 1
|
||||
desc_type: t.CUInt8T = c.Deref(p2)
|
||||
if desc_len == 0: break
|
||||
if desc_type == USB_DESC_INTERFACE:
|
||||
iface: usb_iface_desc | t.CPtr = config_buf + t.CUInt64T(offset)
|
||||
if iface.bInterfaceClass == HID_CLASS:
|
||||
found_hid = 1
|
||||
dev.iface_class = HID_CLASS
|
||||
dev.iface_subclass = iface.bInterfaceSubClass
|
||||
dev.iface_protocol = iface.bInterfaceProtocol
|
||||
dev.iface_num = iface.bInterfaceNumber
|
||||
if desc_type == USB_DESC_ENDPOINT and found_hid:
|
||||
ep: usb_ep_desc | t.CPtr = config_buf + t.CUInt64T(offset)
|
||||
if (ep.bEndpointAddress & 0x80) != 0:
|
||||
dev.ep_in = ep.bEndpointAddress & 0x0F
|
||||
dev.ep_in_max = ep.wMaxPacketSize
|
||||
dev.ep_in_interval = ep.bInterval
|
||||
found_hid = 0
|
||||
offset = offset + t.CInt(desc_len)
|
||||
|
||||
def enumerate_port(port: t.CInt) -> t.CInt:
|
||||
global _device_count
|
||||
if _device_count >= USB_MAX_DEVICES: return -1
|
||||
|
||||
ls: t.CInt = uhci.port_is_low_speed(port)
|
||||
|
||||
reset_ok: t.CInt = -1
|
||||
reset_retry: t.CInt
|
||||
for reset_retry in range(3):
|
||||
if uhci.port_reset(port) == 0:
|
||||
reset_ok = 0
|
||||
break
|
||||
timer.timer_msleep(50)
|
||||
if reset_ok != 0:
|
||||
return -2
|
||||
|
||||
timer.timer_msleep(10)
|
||||
|
||||
dev_buf: t.CVoid | t.CPtr = mm.malloc(usb_dev_desc.__sizeof__())
|
||||
if dev_buf is None: return -3
|
||||
string.memset(dev_buf, 0, usb_dev_desc.__sizeof__())
|
||||
|
||||
result: t.CInt = get_descriptor(0, ls, 8, USB_DESC_DEVICE, 0, dev_buf, 8)
|
||||
retry: t.CInt
|
||||
for retry in range(3):
|
||||
if result == 0: break
|
||||
timer.timer_msleep(50)
|
||||
uhci.port_reset(port)
|
||||
timer.timer_msleep(10)
|
||||
result = get_descriptor(0, ls, 8, USB_DESC_DEVICE, 0, dev_buf, 8)
|
||||
if result != 0:
|
||||
mm.free(dev_buf)
|
||||
return -4
|
||||
|
||||
desc: usb_dev_desc | t.CPtr = dev_buf
|
||||
max_pkt: t.CUInt8T = desc.bMaxPacketSize0
|
||||
if max_pkt < 8: max_pkt = 8
|
||||
|
||||
new_addr: t.CUInt8T = t.CUInt8T(_device_count + 1)
|
||||
result = set_address(0, ls, max_pkt, new_addr)
|
||||
for retry in range(3):
|
||||
if result == 0: break
|
||||
timer.timer_msleep(20)
|
||||
result = set_address(0, ls, max_pkt, new_addr)
|
||||
if result != 0:
|
||||
mm.free(dev_buf)
|
||||
return -5
|
||||
|
||||
timer.timer_msleep(10)
|
||||
|
||||
dev: usb_device | t.CPtr = c.Addr(_devices[_device_count])
|
||||
dev.addr = new_addr
|
||||
dev.ls = ls
|
||||
dev.max_pkt0 = max_pkt
|
||||
dev.configured = 0
|
||||
dev.iface_class = 0
|
||||
dev.iface_subclass = 0
|
||||
dev.iface_protocol = 0
|
||||
dev.ep_in = 0
|
||||
dev.ep_in_max = 0
|
||||
dev.ep_in_interval = 0
|
||||
dev.ep_in_toggle = 0
|
||||
|
||||
config_buf: t.CVoid | t.CPtr = mm.malloc(256)
|
||||
if config_buf is None:
|
||||
mm.free(dev_buf)
|
||||
return -6
|
||||
string.memset(config_buf, 0, 256)
|
||||
|
||||
result = get_descriptor(new_addr, ls, max_pkt, USB_DESC_CONFIG, 0, config_buf, 9)
|
||||
for retry in range(3):
|
||||
if result == 0: break
|
||||
timer.timer_msleep(50)
|
||||
result = get_descriptor(new_addr, ls, max_pkt, USB_DESC_CONFIG, 0, config_buf, 9)
|
||||
if result != 0:
|
||||
mm.free(config_buf)
|
||||
mm.free(dev_buf)
|
||||
return -7
|
||||
|
||||
cfg: usb_config_desc | t.CPtr = config_buf
|
||||
total_len: t.CUInt16T = cfg.wTotalLength
|
||||
if total_len > 256: total_len = 256
|
||||
|
||||
result = get_descriptor(new_addr, ls, max_pkt, USB_DESC_CONFIG, 0, config_buf, total_len)
|
||||
for retry in range(3):
|
||||
if result == 0: break
|
||||
timer.timer_msleep(50)
|
||||
result = get_descriptor(new_addr, ls, max_pkt, USB_DESC_CONFIG, 0, config_buf, total_len)
|
||||
if result != 0:
|
||||
mm.free(config_buf)
|
||||
mm.free(dev_buf)
|
||||
return -8
|
||||
|
||||
_parse_config(dev, config_buf, total_len)
|
||||
|
||||
result = set_configuration(new_addr, ls, max_pkt, cfg.bConfigurationValue)
|
||||
if result != 0:
|
||||
mm.free(config_buf)
|
||||
mm.free(dev_buf)
|
||||
return -9
|
||||
|
||||
dev.configured = 1
|
||||
|
||||
if dev.iface_class == HID_CLASS:
|
||||
hid_set_protocol(new_addr, ls, max_pkt, dev.iface_num, 0)
|
||||
hid_set_idle(new_addr, ls, max_pkt, dev.iface_num, 0)
|
||||
|
||||
_device_count = _device_count + 1
|
||||
mm.free(config_buf)
|
||||
mm.free(dev_buf)
|
||||
return t.CInt(new_addr)
|
||||
|
||||
def init() -> t.CInt:
|
||||
global _device_count
|
||||
_device_count = 0
|
||||
|
||||
io_base: t.CUInt16T = pci.find_uhci()
|
||||
if io_base == 0:
|
||||
serial.puts("[usb] UHCI controller not found\n")
|
||||
return -1
|
||||
|
||||
buf: t.CArray[t.CChar, 64]
|
||||
viperlib.snprintf(c.Addr(buf), 64, "[usb] UHCI at I/O 0x%04X\n", t.CUInt32T(io_base))
|
||||
serial.puts(buf)
|
||||
|
||||
if uhci.init(io_base) != 0:
|
||||
serial.puts("[usb] UHCI init failed\n")
|
||||
return -2
|
||||
|
||||
serial.puts("[usb] UHCI initialized\n")
|
||||
|
||||
timer.timer_msleep(50)
|
||||
|
||||
port: t.CInt
|
||||
for port in range(2):
|
||||
if uhci.port_is_connected(port):
|
||||
viperlib.snprintf(c.Addr(buf), 64, "[usb] port %d connected\n", t.CUInt32T(port))
|
||||
serial.puts(buf)
|
||||
dev_id: t.CInt = enumerate_port(port)
|
||||
if dev_id > 0:
|
||||
dev: usb_device | t.CPtr = c.Addr(_devices[dev_id - 1])
|
||||
viperlib.snprintf(c.Addr(buf), 64, "[usb] device addr=%d class=%02X proto=%02X ep=%d\n",
|
||||
t.CUInt32T(dev.addr), t.CUInt32T(dev.iface_class),
|
||||
t.CUInt32T(dev.iface_protocol), t.CUInt32T(dev.ep_in))
|
||||
serial.puts(buf)
|
||||
else:
|
||||
viperlib.snprintf(c.Addr(buf), 64, "[usb] enumerate port %d failed: %d\n", t.CUInt32T(port), t.CInt32T(dev_id))
|
||||
serial.puts(buf)
|
||||
|
||||
return _device_count
|
||||
|
||||
def find_hid_device(protocol: t.CUInt8T) -> usb_device | t.CPtr:
|
||||
i: t.CInt
|
||||
for i in range(_device_count):
|
||||
dev: usb_device | t.CPtr = c.Addr(_devices[i])
|
||||
if dev.iface_class == HID_CLASS:
|
||||
if dev.iface_protocol == protocol:
|
||||
if dev.configured != 0:
|
||||
return dev
|
||||
return None
|
||||
|
||||
def read_interrupt(dev: usb_device | t.CPtr, buf: t.CVoid | t.CPtr) -> t.CInt:
|
||||
return 0
|
||||
import t, c
|
||||
import mm.mm as mm
|
||||
import viperstring as string
|
||||
import drivers.serial.uart.serial as serial
|
||||
import drivers.usb.uhci as uhci
|
||||
import drivers.usb.pci as pci
|
||||
import platform.pch.timer as timer
|
||||
import viperlib
|
||||
|
||||
USB_DESC_DEVICE: t.CDefine = 1
|
||||
USB_DESC_CONFIG: t.CDefine = 2
|
||||
USB_DESC_STRING: t.CDefine = 3
|
||||
USB_DESC_INTERFACE: t.CDefine = 4
|
||||
USB_DESC_ENDPOINT: t.CDefine = 5
|
||||
|
||||
USB_REQ_GET_STATUS: t.CDefine = 0
|
||||
USB_REQ_CLEAR_FEATURE: t.CDefine = 1
|
||||
USB_REQ_SET_FEATURE: t.CDefine = 3
|
||||
USB_REQ_SET_ADDRESS: t.CDefine = 5
|
||||
USB_REQ_GET_DESCRIPTOR: t.CDefine = 6
|
||||
USB_REQ_SET_DESCRIPTOR: t.CDefine = 7
|
||||
USB_REQ_GET_CONFIGURATION: t.CDefine = 8
|
||||
USB_REQ_SET_CONFIGURATION: t.CDefine = 9
|
||||
|
||||
USB_REQ_SET_INTERFACE: t.CDefine = 11
|
||||
|
||||
HID_CLASS: t.CDefine = 0x03
|
||||
HID_SUBCLASS_BOOT: t.CDefine = 0x01
|
||||
HID_PROTO_KEYBOARD: t.CDefine = 0x01
|
||||
HID_PROTO_MOUSE: t.CDefine = 0x02
|
||||
|
||||
HID_REQ_SET_PROTOCOL: t.CDefine = 0x0B
|
||||
HID_REQ_SET_IDLE: t.CDefine = 0x0A
|
||||
HID_REQ_GET_REPORT: t.CDefine = 0x01
|
||||
|
||||
USB_MAX_DEVICES: t.CDefine = 8
|
||||
|
||||
class usb_dev_desc(t.CStruct):
|
||||
bLength: uint8
|
||||
bDescriptorType: uint8
|
||||
bcdUSB: uint16
|
||||
bDeviceClass: uint8
|
||||
bDeviceSubClass: uint8
|
||||
bDeviceProtocol: uint8
|
||||
bMaxPacketSize0: uint8
|
||||
idVendor: uint16
|
||||
idProduct: uint16
|
||||
bcdDevice: uint16
|
||||
iManufacturer: uint8
|
||||
iProduct: uint8
|
||||
iSerialNumber: uint8
|
||||
bNumConfigurations: uint8
|
||||
|
||||
class usb_config_desc(t.CStruct):
|
||||
bLength: uint8
|
||||
bDescriptorType: uint8
|
||||
wTotalLength: uint16
|
||||
bNumInterfaces: uint8
|
||||
bConfigurationValue: uint8
|
||||
iConfiguration: uint8
|
||||
bmAttributes: uint8
|
||||
bMaxPower: uint8
|
||||
|
||||
class usb_iface_desc(t.CStruct):
|
||||
bLength: uint8
|
||||
bDescriptorType: uint8
|
||||
bInterfaceNumber: uint8
|
||||
bAlternateSetting: uint8
|
||||
bNumEndpoints: uint8
|
||||
bInterfaceClass: uint8
|
||||
bInterfaceSubClass: uint8
|
||||
bInterfaceProtocol: uint8
|
||||
iInterface: uint8
|
||||
|
||||
class usb_ep_desc(t.CStruct):
|
||||
bLength: uint8
|
||||
bDescriptorType: uint8
|
||||
bEndpointAddress: uint8
|
||||
bmAttributes: uint8
|
||||
wMaxPacketSize: uint16
|
||||
bInterval: uint8
|
||||
|
||||
class usb_setup_pkt(t.CStruct):
|
||||
bmRequestType: uint8
|
||||
bRequest: uint8
|
||||
wValue: uint16
|
||||
wIndex: uint16
|
||||
wLength: uint16
|
||||
|
||||
class usb_device(t.CStruct):
|
||||
addr: uint8
|
||||
ls: int
|
||||
max_pkt0: uint8
|
||||
iface_class: uint8
|
||||
iface_subclass: uint8
|
||||
iface_protocol: uint8
|
||||
iface_num: uint8
|
||||
ep_in: uint8
|
||||
ep_in_max: uint16
|
||||
ep_in_interval: uint8
|
||||
ep_in_toggle: uint8
|
||||
configured: int
|
||||
|
||||
_devices: t.CArray[usb_device, USB_MAX_DEVICES]
|
||||
_device_count: int = 0
|
||||
|
||||
def _setup_packet(bmRequestType: uint8, bRequest: uint8, wValue: uint16, wIndex: uint16, wLength: uint16, buf: usb_setup_pkt | t.CPtr):
|
||||
buf.bmRequestType = bmRequestType
|
||||
buf.bRequest = bRequest
|
||||
buf.wValue = wValue
|
||||
buf.wIndex = wIndex
|
||||
buf.wLength = wLength
|
||||
|
||||
def _send_control(dev_addr: uint8, ls: int, max_pkt: uint8, setup: usb_setup_pkt | t.CPtr, data_buf: t.CPtr, data_len: uint16, data_in: int) -> int:
|
||||
return uhci.control_transfer(dev_addr, 0, ls, max_pkt, c.Addr(setup), data_buf, data_len, data_in)
|
||||
|
||||
def get_descriptor(dev_addr: uint8, ls: int, max_pkt: uint8, desc_type: uint8, desc_idx: uint8, buf: t.CPtr, length: uint16) -> int:
|
||||
setup: usb_setup_pkt
|
||||
_setup_packet(0x80, USB_REQ_GET_DESCRIPTOR, (uint16(desc_type) << 8) | desc_idx, 0, length, c.Addr(setup))
|
||||
return _send_control(dev_addr, ls, max_pkt, c.Addr(setup), buf, length, 1)
|
||||
|
||||
def set_address(dev_addr: uint8, ls: int, max_pkt: uint8, new_addr: uint8) -> int:
|
||||
setup: usb_setup_pkt
|
||||
_setup_packet(0x00, USB_REQ_SET_ADDRESS, new_addr, 0, 0, c.Addr(setup))
|
||||
return _send_control(dev_addr, ls, max_pkt, c.Addr(setup), None, 0, 0)
|
||||
|
||||
def set_configuration(dev_addr: uint8, ls: int, max_pkt: uint8, config_val: uint8) -> int:
|
||||
setup: usb_setup_pkt
|
||||
_setup_packet(0x00, USB_REQ_SET_CONFIGURATION, config_val, 0, 0, c.Addr(setup))
|
||||
return _send_control(dev_addr, ls, max_pkt, c.Addr(setup), None, 0, 0)
|
||||
|
||||
def hid_set_protocol(dev_addr: uint8, ls: int, max_pkt: uint8, iface: uint8, protocol: uint8) -> int:
|
||||
setup: usb_setup_pkt
|
||||
_setup_packet(0x21, HID_REQ_SET_PROTOCOL, protocol, uint16(iface), 0, c.Addr(setup))
|
||||
return _send_control(dev_addr, ls, max_pkt, c.Addr(setup), None, 0, 0)
|
||||
|
||||
def hid_set_idle(dev_addr: uint8, ls: int, max_pkt: uint8, iface: uint8, duration: uint8) -> int:
|
||||
setup: usb_setup_pkt
|
||||
_setup_packet(0x21, HID_REQ_SET_IDLE, uint16(duration) << 8, uint16(iface), 0, c.Addr(setup))
|
||||
return _send_control(dev_addr, ls, max_pkt, c.Addr(setup), None, 0, 0)
|
||||
|
||||
def _parse_config(dev: usb_device | t.CPtr, config_buf: t.CPtr, total_len: uint16):
|
||||
offset: int = 0
|
||||
found_hid: int = 0
|
||||
while offset < int(total_len):
|
||||
p: uint8 | t.CPtr = config_buf + uint64(offset)
|
||||
desc_len: uint8 = c.Deref(p)
|
||||
p2: uint8 | t.CPtr = config_buf + uint64(offset) + 1
|
||||
desc_type: uint8 = c.Deref(p2)
|
||||
if desc_len == 0: break
|
||||
# 边界:描述符整体须落在 config_buf(total_len 字节)内,且不得短于
|
||||
# 所访问的结构体(interface=9 / endpoint=7),否则越界读。
|
||||
if offset + int(desc_len) > int(total_len): break
|
||||
if desc_type == USB_DESC_INTERFACE and int(desc_len) >= 9:
|
||||
iface: usb_iface_desc | t.CPtr = config_buf + uint64(offset)
|
||||
if iface.bInterfaceClass == HID_CLASS:
|
||||
found_hid = 1
|
||||
dev.iface_class = HID_CLASS
|
||||
dev.iface_subclass = iface.bInterfaceSubClass
|
||||
dev.iface_protocol = iface.bInterfaceProtocol
|
||||
dev.iface_num = iface.bInterfaceNumber
|
||||
if desc_type == USB_DESC_ENDPOINT and found_hid and int(desc_len) >= 7:
|
||||
ep: usb_ep_desc | t.CPtr = config_buf + uint64(offset)
|
||||
if (ep.bEndpointAddress & 0x80) != 0:
|
||||
dev.ep_in = ep.bEndpointAddress & 0x0F
|
||||
dev.ep_in_max = ep.wMaxPacketSize
|
||||
dev.ep_in_interval = ep.bInterval
|
||||
found_hid = 0
|
||||
offset = offset + int(desc_len)
|
||||
|
||||
def enumerate_port(port: int) -> int:
|
||||
global _device_count
|
||||
if _device_count >= USB_MAX_DEVICES: return -1
|
||||
|
||||
ls: int = uhci.port_is_low_speed(port)
|
||||
|
||||
reset_ok: int = -1
|
||||
reset_retry: int
|
||||
for reset_retry in range(3):
|
||||
if uhci.port_reset(port) == 0:
|
||||
reset_ok = 0
|
||||
break
|
||||
timer.timer_msleep(50)
|
||||
if reset_ok != 0:
|
||||
return -2
|
||||
|
||||
timer.timer_msleep(10)
|
||||
|
||||
dev_buf: t.CPtr = mm.malloc(usb_dev_desc.__sizeof__())
|
||||
if dev_buf is None: return -3
|
||||
string.memset(dev_buf, 0, usb_dev_desc.__sizeof__())
|
||||
|
||||
result: int = get_descriptor(0, ls, 8, USB_DESC_DEVICE, 0, dev_buf, 8)
|
||||
retry: int
|
||||
for retry in range(3):
|
||||
if result == 0: break
|
||||
timer.timer_msleep(50)
|
||||
uhci.port_reset(port)
|
||||
timer.timer_msleep(10)
|
||||
result = get_descriptor(0, ls, 8, USB_DESC_DEVICE, 0, dev_buf, 8)
|
||||
if result != 0:
|
||||
mm.free(dev_buf)
|
||||
return -4
|
||||
|
||||
desc: usb_dev_desc | t.CPtr = dev_buf
|
||||
max_pkt: uint8 = desc.bMaxPacketSize0
|
||||
if max_pkt < 8: max_pkt = 8
|
||||
|
||||
new_addr: uint8 = uint8(_device_count + 1)
|
||||
result = set_address(0, ls, max_pkt, new_addr)
|
||||
for retry in range(3):
|
||||
if result == 0: break
|
||||
timer.timer_msleep(20)
|
||||
result = set_address(0, ls, max_pkt, new_addr)
|
||||
if result != 0:
|
||||
mm.free(dev_buf)
|
||||
return -5
|
||||
|
||||
timer.timer_msleep(10)
|
||||
|
||||
dev: usb_device | t.CPtr = c.Addr(_devices[_device_count])
|
||||
dev.addr = new_addr
|
||||
dev.ls = ls
|
||||
dev.max_pkt0 = max_pkt
|
||||
dev.configured = 0
|
||||
dev.iface_class = 0
|
||||
dev.iface_subclass = 0
|
||||
dev.iface_protocol = 0
|
||||
dev.ep_in = 0
|
||||
dev.ep_in_max = 0
|
||||
dev.ep_in_interval = 0
|
||||
dev.ep_in_toggle = 0
|
||||
|
||||
config_buf: t.CPtr = mm.malloc(256)
|
||||
if config_buf is None:
|
||||
mm.free(dev_buf)
|
||||
return -6
|
||||
string.memset(config_buf, 0, 256)
|
||||
|
||||
result = get_descriptor(new_addr, ls, max_pkt, USB_DESC_CONFIG, 0, config_buf, 9)
|
||||
for retry in range(3):
|
||||
if result == 0: break
|
||||
timer.timer_msleep(50)
|
||||
result = get_descriptor(new_addr, ls, max_pkt, USB_DESC_CONFIG, 0, config_buf, 9)
|
||||
if result != 0:
|
||||
mm.free(config_buf)
|
||||
mm.free(dev_buf)
|
||||
return -7
|
||||
|
||||
cfg: usb_config_desc | t.CPtr = config_buf
|
||||
total_len: uint16 = cfg.wTotalLength
|
||||
if total_len > 256: total_len = 256
|
||||
|
||||
result = get_descriptor(new_addr, ls, max_pkt, USB_DESC_CONFIG, 0, config_buf, total_len)
|
||||
for retry in range(3):
|
||||
if result == 0: break
|
||||
timer.timer_msleep(50)
|
||||
result = get_descriptor(new_addr, ls, max_pkt, USB_DESC_CONFIG, 0, config_buf, total_len)
|
||||
if result != 0:
|
||||
mm.free(config_buf)
|
||||
mm.free(dev_buf)
|
||||
return -8
|
||||
|
||||
_parse_config(dev, config_buf, total_len)
|
||||
|
||||
result = set_configuration(new_addr, ls, max_pkt, cfg.bConfigurationValue)
|
||||
if result != 0:
|
||||
mm.free(config_buf)
|
||||
mm.free(dev_buf)
|
||||
return -9
|
||||
|
||||
dev.configured = 1
|
||||
|
||||
if dev.iface_class == HID_CLASS:
|
||||
hid_set_protocol(new_addr, ls, max_pkt, dev.iface_num, 0)
|
||||
hid_set_idle(new_addr, ls, max_pkt, dev.iface_num, 0)
|
||||
|
||||
_device_count = _device_count + 1
|
||||
mm.free(config_buf)
|
||||
mm.free(dev_buf)
|
||||
return int(new_addr)
|
||||
|
||||
def init() -> int:
|
||||
global _device_count
|
||||
_device_count = 0
|
||||
|
||||
io_base: uint16 = pci.find_uhci()
|
||||
if io_base == 0:
|
||||
serial.puts("[usb] UHCI controller not found\n")
|
||||
return -1
|
||||
|
||||
buf: t.CArray[t.CChar, 64]
|
||||
viperlib.snprintf(c.Addr(buf), 64, "[usb] UHCI at I/O 0x%04X\n", uint32(io_base))
|
||||
serial.puts(buf)
|
||||
|
||||
if uhci.init(io_base) != 0:
|
||||
serial.puts("[usb] UHCI init failed\n")
|
||||
return -2
|
||||
|
||||
serial.puts("[usb] UHCI initialized\n")
|
||||
|
||||
timer.timer_msleep(50)
|
||||
|
||||
port: int
|
||||
for port in range(2):
|
||||
if uhci.port_is_connected(port):
|
||||
viperlib.snprintf(c.Addr(buf), 64, "[usb] port %d connected\n", uint32(port))
|
||||
serial.puts(buf)
|
||||
dev_id: int = enumerate_port(port)
|
||||
if dev_id > 0:
|
||||
dev: usb_device | t.CPtr = c.Addr(_devices[dev_id - 1])
|
||||
viperlib.snprintf(c.Addr(buf), 64, "[usb] device addr=%d class=%02X proto=%02X ep=%d\n",
|
||||
uint32(dev.addr), uint32(dev.iface_class),
|
||||
uint32(dev.iface_protocol), uint32(dev.ep_in))
|
||||
serial.puts(buf)
|
||||
else:
|
||||
viperlib.snprintf(c.Addr(buf), 64, "[usb] enumerate port %d failed: %d\n", uint32(port), int32(dev_id))
|
||||
serial.puts(buf)
|
||||
|
||||
return _device_count
|
||||
|
||||
def find_hid_device(protocol: uint8) -> usb_device | t.CPtr:
|
||||
i: int
|
||||
for i in range(_device_count):
|
||||
dev: usb_device | t.CPtr = c.Addr(_devices[i])
|
||||
if dev.iface_class == HID_CLASS:
|
||||
if dev.iface_protocol == protocol:
|
||||
if dev.configured != 0:
|
||||
return dev
|
||||
return None
|
||||
|
||||
def read_interrupt(dev: usb_device | t.CPtr, buf: t.CPtr) -> int:
|
||||
return 0
|
||||
@@ -5,25 +5,25 @@ import t, c
|
||||
MAX_SHEETS: t.CDefine = 64
|
||||
MAX_UI_COMPONENTS: t.CDefine = 256
|
||||
|
||||
_next_sheet_id: t.CInt = 0
|
||||
_next_component_id: t.CInt = 0
|
||||
_next_sheet_id: int = 0
|
||||
_next_component_id: int = 0
|
||||
|
||||
@t.Object
|
||||
class Sheet:
|
||||
id: t.CInt
|
||||
x: t.CInt
|
||||
y: t.CInt
|
||||
w: t.CInt
|
||||
h: t.CInt
|
||||
visible: t.CInt
|
||||
id: int
|
||||
x: int
|
||||
y: int
|
||||
w: int
|
||||
h: int
|
||||
visible: int
|
||||
_surf_obj: gfx.Surface
|
||||
_renderer_obj: gfx.Renderer
|
||||
surf: gfx.Surface | t.CPtr
|
||||
renderer: gfx.Renderer | t.CPtr
|
||||
parent: 'Sheet | t.CPtr'
|
||||
bg_color: t.CUInt32T
|
||||
bg_color: uint32
|
||||
|
||||
def __init__(self, fb: UINT32PTR, zb: float | t.CPtr, x: t.CInt, y: t.CInt, w: t.CInt, h: t.CInt, parent: 'Sheet | t.CPtr' = None):
|
||||
def __init__(self, fb: UINT32PTR, zb: float | t.CPtr, x: int, y: int, w: int, h: int, parent: 'Sheet | t.CPtr' = None):
|
||||
global _next_sheet_id
|
||||
self.id = _next_sheet_id
|
||||
_next_sheet_id += 1
|
||||
@@ -34,16 +34,19 @@ class Sheet:
|
||||
self.visible = 1
|
||||
self._surf_obj = gfx.Surface(fb, zb, w, h)
|
||||
self.surf = c.Addr(self._surf_obj)
|
||||
self._renderer_obj = gfx.Renderer(self.surf)
|
||||
# gfx.Renderer.__init__(fb, zb, w, h):此前只传 self.surf(Surface*)→
|
||||
# fb 被 bitcast 错位、w/h 缺省为 0 → Renderer 的 _w/_h = 0 →
|
||||
# Sheet.Clear/Fill/DrawRect(走 renderer)全部空操作。按 Surface 同参构造。
|
||||
self._renderer_obj = gfx.Renderer(fb, zb, w, h)
|
||||
self.renderer = c.Addr(self._renderer_obj)
|
||||
self.parent = parent
|
||||
self.bg_color = gfx.COLOR_RGB(20, 20, 30)
|
||||
|
||||
def MoveTo(self, nx: t.CInt, ny: t.CInt):
|
||||
def MoveTo(self, nx: int, ny: int):
|
||||
self.x = nx
|
||||
self.y = ny
|
||||
|
||||
def Resize(self, nw: t.CInt, nh: t.CInt):
|
||||
def Resize(self, nw: int, nh: int):
|
||||
self.w = nw
|
||||
self.h = nh
|
||||
|
||||
@@ -57,29 +60,29 @@ class Sheet:
|
||||
r: gfx.Renderer = c.Deref(self.renderer)
|
||||
r.Clear(self.bg_color)
|
||||
|
||||
def Fill(self, color: t.CUInt32T):
|
||||
def Fill(self, color: uint32):
|
||||
r: gfx.Renderer = c.Deref(self.renderer)
|
||||
r.Clear(color)
|
||||
|
||||
def DrawRect(self, rx: t.CInt, ry: t.CInt, rw: t.CInt, rh: t.CInt, color: t.CUInt32T):
|
||||
def DrawRect(self, rx: int, ry: int, rw: int, rh: int, color: uint32):
|
||||
r: gfx.Renderer = c.Deref(self.renderer)
|
||||
r.DrawLine2D(rx, ry, rx + rw - 1, ry, color)
|
||||
r.DrawLine2D(rx + rw - 1, ry, rx + rw - 1, ry + rh - 1, color)
|
||||
r.DrawLine2D(rx + rw - 1, ry + rh - 1, rx, ry + rh - 1, color)
|
||||
r.DrawLine2D(rx, ry + rh - 1, rx, ry, color)
|
||||
|
||||
def DrawFilledRect(self, rx: t.CInt, ry: t.CInt, rw: t.CInt, rh: t.CInt, color: t.CUInt32T):
|
||||
def DrawFilledRect(self, rx: int, ry: int, rw: int, rh: int, color: uint32):
|
||||
surf: gfx.Surface = c.Deref(self.surf)
|
||||
fb: UINT32PTR = surf.fb
|
||||
w: t.CInt = surf.w
|
||||
h: t.CInt = surf.h
|
||||
w: int = surf.w
|
||||
h: int = surf.h
|
||||
for py in range(ry, ry + rh):
|
||||
if py < 0 or py >= h: continue
|
||||
for px in range(rx, rx + rw):
|
||||
if px < 0 or px >= w: continue
|
||||
fb[py * w + px] = color
|
||||
|
||||
def Contains(self, px: t.CInt, py: t.CInt) -> t.CInt:
|
||||
def Contains(self, px: int, py: int) -> int:
|
||||
if px >= self.x and px < self.x + self.w and py >= self.y and py < self.y + self.h:
|
||||
return 1
|
||||
return 0
|
||||
@@ -11,21 +11,21 @@ UI_PROGRESS: t.CDefine = 3
|
||||
|
||||
@t.Object
|
||||
class UIComponent:
|
||||
id: t.CInt
|
||||
ctype: t.CInt
|
||||
x: t.CInt
|
||||
y: t.CInt
|
||||
w: t.CInt
|
||||
h: t.CInt
|
||||
visible: t.CInt
|
||||
id: int
|
||||
ctype: int
|
||||
x: int
|
||||
y: int
|
||||
w: int
|
||||
h: int
|
||||
visible: int
|
||||
sheet: sheet.Sheet | t.CPtr
|
||||
fg_color: t.CUInt32T
|
||||
bg_color: t.CUInt32T
|
||||
fg_color: uint32
|
||||
bg_color: uint32
|
||||
text: t.CArray[t.CChar, 128]
|
||||
text_len: t.CInt
|
||||
value: t.CInt
|
||||
text_len: int
|
||||
value: int
|
||||
|
||||
def __init__(self, ctype: t.CInt, sh: sheet.Sheet | t.CPtr, x: t.CInt, y: t.CInt, w: t.CInt, h: t.CInt):
|
||||
def __init__(self, ctype: int, sh: sheet.Sheet | t.CPtr, x: int, y: int, w: int, h: int):
|
||||
self.id = sheet._next_component_id
|
||||
sheet._next_component_id += 1
|
||||
self.ctype = ctype
|
||||
@@ -42,7 +42,7 @@ class UIComponent:
|
||||
self.value = 0
|
||||
|
||||
def SetText(self, s: str):
|
||||
i: t.CInt = 0
|
||||
i: int = 0
|
||||
for ch in s:
|
||||
if i >= 127: break
|
||||
self.text[i] = ch
|
||||
@@ -50,7 +50,7 @@ class UIComponent:
|
||||
self.text[i] = 0
|
||||
self.text_len = i
|
||||
|
||||
def SetValue(self, v: t.CInt):
|
||||
def SetValue(self, v: int):
|
||||
self.value = v
|
||||
|
||||
def Render(self):
|
||||
@@ -79,12 +79,12 @@ class UIComponent:
|
||||
|
||||
def _RenderProgress(self, sh: sheet.Sheet):
|
||||
sh.DrawFilledRect(self.x, self.y, self.w, self.h, gfx.COLOR_RGB(30, 30, 40))
|
||||
fill_w: t.CInt = self.w * self.value / 100
|
||||
fill_w: int = self.w * self.value / 100
|
||||
if fill_w > 0:
|
||||
sh.DrawFilledRect(self.x, self.y, fill_w, self.h, gfx.COLOR_RGB(0, 180, 255))
|
||||
sh.DrawRect(self.x, self.y, self.w, self.h, gfx.COLOR_RGB(80, 80, 100))
|
||||
|
||||
def Contains(self, px: t.CInt, py: t.CInt) -> t.CInt:
|
||||
def Contains(self, px: int, py: int) -> int:
|
||||
if px >= self.x and px < self.x + self.w and py >= self.y and py < self.y + self.h:
|
||||
return 1
|
||||
return 0
|
||||
@@ -93,37 +93,37 @@ class UIComponent:
|
||||
@t.Object
|
||||
class UIManager:
|
||||
sheets: t.CArray[sheet.Sheet | t.CPtr, 64]
|
||||
sheet_count: t.CInt
|
||||
sheet_count: int
|
||||
components: t.CArray[UIComponent | t.CPtr, 256]
|
||||
component_count: t.CInt
|
||||
screen_w: t.CInt
|
||||
screen_h: t.CInt
|
||||
component_count: int
|
||||
screen_w: int
|
||||
screen_h: int
|
||||
|
||||
def __init__(self, w: t.CInt, h: t.CInt):
|
||||
def __init__(self, w: int, h: int):
|
||||
self.sheet_count = 0
|
||||
self.component_count = 0
|
||||
self.screen_w = w
|
||||
self.screen_h = h
|
||||
i: t.CInt
|
||||
i: int
|
||||
for i in range(64):
|
||||
self.sheets[i] = None
|
||||
for i in range(256):
|
||||
self.components[i] = None
|
||||
|
||||
def AddSheet(self, sh: sheet.Sheet | t.CPtr) -> t.CInt:
|
||||
def AddSheet(self, sh: sheet.Sheet | t.CPtr) -> int:
|
||||
if self.sheet_count >= 64: return -1
|
||||
self.sheets[self.sheet_count] = sh
|
||||
self.sheet_count += 1
|
||||
return 0
|
||||
|
||||
def AddComponent(self, comp: UIComponent | t.CPtr) -> t.CInt:
|
||||
def AddComponent(self, comp: UIComponent | t.CPtr) -> int:
|
||||
if self.component_count >= 256: return -1
|
||||
self.components[self.component_count] = comp
|
||||
self.component_count += 1
|
||||
return 0
|
||||
|
||||
def FindComponent(self, cid: t.CInt) -> UIComponent | t.CPtr:
|
||||
i: t.CInt
|
||||
def FindComponent(self, cid: int) -> UIComponent | t.CPtr:
|
||||
i: int
|
||||
for i in range(self.component_count):
|
||||
p: UIComponent | t.CPtr = self.components[i]
|
||||
if p is not None:
|
||||
@@ -132,15 +132,15 @@ class UIManager:
|
||||
return None
|
||||
|
||||
def RenderAll(self):
|
||||
i: t.CInt
|
||||
i: int
|
||||
for i in range(self.component_count):
|
||||
p: UIComponent | t.CPtr = self.components[i]
|
||||
if p is not None:
|
||||
comp: UIComponent = c.Deref(p)
|
||||
comp.Render()
|
||||
|
||||
def HitTest(self, px: t.CInt, py: t.CInt) -> UIComponent | t.CPtr:
|
||||
i: t.CInt = self.component_count - 1
|
||||
def HitTest(self, px: int, py: int) -> UIComponent | t.CPtr:
|
||||
i: int = self.component_count - 1
|
||||
while i >= 0:
|
||||
p: UIComponent | t.CPtr = self.components[i]
|
||||
if p is not None:
|
||||
|
||||
@@ -10,7 +10,7 @@ SPHERE_SLICES: t.CDefine = (24 * 1)
|
||||
SPHERE_STACKS: t.CDefine = (16 * 1)
|
||||
SIN_WAVE_GRID: t.CDefine = (40 * 1)
|
||||
|
||||
def COLOR_RGB(r: int, g: int, b: int) -> t.CInline | t.CInt:
|
||||
def COLOR_RGB(r: int, g: int, b: int) -> t.CInline | int:
|
||||
return (255 << 24) | (r << 16) | (g << 8) | (b)
|
||||
|
||||
@t.Object
|
||||
@@ -115,7 +115,7 @@ class Renderer:
|
||||
self._w = w
|
||||
self._h = h
|
||||
|
||||
def Clear(self, color: t.CUInt32T):
|
||||
def Clear(self, color: uint32):
|
||||
fb: UINT32PTR = self._fb
|
||||
zb: float | t.CPtr = self._zb
|
||||
size: int = self._w * self._h
|
||||
@@ -123,7 +123,7 @@ class Renderer:
|
||||
fb[i] = color
|
||||
zb[i] = float(1.0)
|
||||
|
||||
def DrawLine2D(self, x0: int, y0: int, x1: int, y1: int, col: t.CUInt32T):
|
||||
def DrawLine2D(self, x0: int, y0: int, x1: int, y1: int, col: uint32):
|
||||
fb: UINT32PTR = self._fb
|
||||
w: int = self._w; h: int = self._h
|
||||
dx: int = abs(x1-x0); dy: int = abs(y1-y0)
|
||||
@@ -136,7 +136,7 @@ class Renderer:
|
||||
if e2 > -dy: err -= dy; x0 += sx
|
||||
if e2 < dx: err += dx; y0 += sy
|
||||
|
||||
def DrawTriangle(self, v0: Vec3, v1: Vec3, v2: Vec3, col: t.CUInt32T):
|
||||
def DrawTriangle(self, v0: Vec3, v1: Vec3, v2: Vec3, col: uint32):
|
||||
if v0.z < float(0.0) or v1.z < float(0.0) or v2.z < float(0.0): return
|
||||
if (v0.x > float(10.0) or v0.x < float(-10.0) or v0.y > float(10.0) or v0.y < float(-10.0) or
|
||||
v1.x > float(10.0) or v1.x < float(-10.0) or v1.y > float(10.0) or v1.y < float(-10.0) or
|
||||
@@ -179,7 +179,7 @@ class Renderer:
|
||||
fb[idx] = col
|
||||
dxP += float(1.0)
|
||||
|
||||
def DrawGlowDot(self, x: float, y: float, radius: float, core_col: t.CUInt32T, intensity: float):
|
||||
def DrawGlowDot(self, x: float, y: float, radius: float, core_col: uint32, intensity: float):
|
||||
fb: UINT32PTR = self._fb; w: int = self._w; h: int = self._h
|
||||
r: int = int(radius) + 4
|
||||
ix: int = int(x); iy: int = int(y)
|
||||
@@ -196,13 +196,13 @@ class Renderer:
|
||||
fade: float = 1.0 - (dist - radius) / 4.0
|
||||
self.BlendPixel(px, py, core_col, intensity * fade * 0.5)
|
||||
|
||||
def BlendPixel(self, x: int, y: int, col: t.CUInt32T, alpha: float):
|
||||
def BlendPixel(self, x: int, y: int, col: uint32, alpha: float):
|
||||
if alpha <= 0.0: return
|
||||
fb: UINT32PTR = self._fb; w: int = self._w; h: int = self._h
|
||||
if x < 0 or x >= w or y < 0 or y >= h: return
|
||||
|
||||
idx: int = y * w + x
|
||||
bg: t.CUInt32T = fb[idx]
|
||||
bg: uint32 = fb[idx]
|
||||
bg_b: int = bg & 0xFF; bg_g: int = (bg >> 8) & 0xFF; bg_r: int = (bg >> 16) & 0xFF
|
||||
f_b: int = col & 0xFF; f_g: int = (col >> 8) & 0xFF; f_r: int = (col >> 16) & 0xFF
|
||||
|
||||
@@ -240,7 +240,7 @@ class Scene3D:
|
||||
cubeMVP: Mat4 = Mat4_Mul(vp, Mat4_Translate(cubeX, 0, 0))
|
||||
self._DrawCube(cubeMVP, COLOR_RGB(180, 180, 180))
|
||||
|
||||
colors: t.CArray[t.CUInt32T, 4] = [COLOR_RGB(255,50,50), COLOR_RGB(50,50,255), COLOR_RGB(255,255,50), COLOR_RGB(50,255,255)]
|
||||
colors: t.CArray[uint32, 4] = [COLOR_RGB(255,50,50), COLOR_RGB(50,50,255), COLOR_RGB(255,255,50), COLOR_RGB(50,255,255)]
|
||||
for i in range(4):
|
||||
a: float = time * float(1.5) + i * (PI / float(2.0)); r: float = float(3.0)
|
||||
pos: Vec3 = Vec3(vipermath.cosf(a) * r + cubeX, 0, vipermath.sinf(a) * r)
|
||||
@@ -259,7 +259,7 @@ class Scene3D:
|
||||
self.renderer.DrawLine2D(prev_x, prev_y, cx, cy, COLOR_RGB(0, 255, 100))
|
||||
prev_x = cx; prev_y = cy
|
||||
|
||||
def _DrawCube(self, mvp: Mat4, col: t.CUInt32T):
|
||||
def _DrawCube(self, mvp: Mat4, col: uint32):
|
||||
v: t.CArray[Vec3, 8] = [
|
||||
Vec3(-1, -1, -1), Vec3(-1, -1, 1), Vec3(-1, 1, -1), Vec3(-1, 1, 1),
|
||||
Vec3( 1, -1, -1), Vec3( 1, -1, 1), Vec3( 1, 1, -1), Vec3( 1, 1, 1)
|
||||
@@ -271,7 +271,7 @@ class Scene3D:
|
||||
]
|
||||
for i in range(12): self.renderer.DrawTriangle(v[faces[i][0]], v[faces[i][1]], v[faces[i][2]], col)
|
||||
|
||||
def _DrawSphere(self, mvp: Mat4, center: Vec3, radius: float, col: t.CUInt32T):
|
||||
def _DrawSphere(self, mvp: Mat4, center: Vec3, radius: float, col: uint32):
|
||||
step_pi: float = PI / SPHERE_STACKS; step_2pi: float = float(2.0) * PI / SPHERE_SLICES
|
||||
for i in range(SPHERE_STACKS):
|
||||
for j in range(SPHERE_SLICES):
|
||||
@@ -296,9 +296,9 @@ class Scene3D:
|
||||
y01: float = vipermath.sinf(x0) * vipermath.cosf(z1) * scale; y11: float = vipermath.sinf(x1) * vipermath.cosf(z1) * scale
|
||||
|
||||
t1: float = (y00 / scale + float(1.0)) * float(0.5); r1: int = int(50 + 205 * t1); g1: int = int(80 + 120 * vipermath.sinf(t1 * PI)); b1: int = int(255 - 205 * t1)
|
||||
col1: t.CUInt32T = COLOR_RGB(255 if (r1 > 255) else (0 if (r1 < 0) else r1), 255 if (g1 > 255) else (0 if (g1 < 0) else g1), 255 if (b1 > 255) else (0 if (b1 < 0) else b1))
|
||||
col1: uint32 = COLOR_RGB(255 if (r1 > 255) else (0 if (r1 < 0) else r1), 255 if (g1 > 255) else (0 if (g1 < 0) else g1), 255 if (b1 > 255) else (0 if (b1 < 0) else b1))
|
||||
t2: float = (y11 / scale + float(1.0)) * float(0.5); r2: int = int(50 + 205 * t2); g2: int = int(80 + 120 * vipermath.sinf(t2 * PI)); b2: int = int(255 - 205 * t2)
|
||||
col2: t.CUInt32T = COLOR_RGB(255 if (r2 > 255) else (0 if (r2 < 0) else r2), 255 if (g2 > 255) else (0 if (g2 < 0) else g2), 255 if (b2 > 255) else (0 if (b2 < 0) else b2))
|
||||
col2: uint32 = COLOR_RGB(255 if (r2 > 255) else (0 if (r2 < 0) else r2), 255 if (g2 > 255) else (0 if (g2 < 0) else g2), 255 if (b2 > 255) else (0 if (b2 < 0) else b2))
|
||||
|
||||
v00: Vec3 = Mat4_MulVec(mvp, Vec3(x0, y00, z0)); v10: Vec3 = Mat4_MulVec(mvp, Vec3(x1, y10, z0))
|
||||
v01: Vec3 = Mat4_MulVec(mvp, Vec3(x0, y01, z1)); v11: Vec3 = Mat4_MulVec(mvp, Vec3(x1, y11, z1))
|
||||
|
||||
@@ -19,7 +19,7 @@ DEFAULT_CHAR: t.CDefine = 0 # 非ASCII字符的默认替换字符
|
||||
SERIAL_PORT: t.CDefine = 0x3F8 # 串口调试端口地址
|
||||
|
||||
# 8x16字符点阵字库 (每个字符16字节,共256个字符)
|
||||
font: t.CArray[t.CArray[t.CUInt8T, 16], 256] = [
|
||||
font: t.CArray[t.CArray[uint8, 16], 256] = [
|
||||
# 字符编号 0x00 - 0x0F
|
||||
{0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x55, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, # 0x00
|
||||
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, # 0x01
|
||||
@@ -312,7 +312,7 @@ font: t.CArray[t.CArray[t.CUInt8T, 16], 256] = [
|
||||
@t.Object
|
||||
class _VGAScreenDriver:
|
||||
# 帧缓冲区信息
|
||||
fbv: t.CVoid | t.CPtr # = None
|
||||
fbv: t.CPtr # = None
|
||||
fb: t.CUnsignedChar | t.CPtr # = None
|
||||
fw: int # = 800
|
||||
fh: int # = 600
|
||||
@@ -321,7 +321,7 @@ class _VGAScreenDriver:
|
||||
BgColor: t.CUnsignedInt = 0xFF000080 # RGBA: 不透明深蓝色
|
||||
|
||||
# 初始化VGA驱动
|
||||
def __init__(self, fb: t.CVoid | t.CPtr, width: int, height: int, pitch: int, format: int):
|
||||
def __init__(self, fb: t.CPtr, width: int, height: int, pitch: int, format: int):
|
||||
# 先做参数合法性检查
|
||||
if fb is None or width <= 0 or height <= 0 or pitch <= 0: return
|
||||
# 更新帧缓冲区参数
|
||||
@@ -350,7 +350,7 @@ class _VGAScreenDriver:
|
||||
testY: int = 0
|
||||
offset: int = testY * self.fp + testX * 4
|
||||
# 保存测试位置原始像素值,避免污染屏幕
|
||||
OriginalPixel: t.CUInt32T = c.Deref(t.CUInt32T(fb + offset, t.CPtr))
|
||||
OriginalPixel: uint32 = c.Deref(uint32(fb + offset, t.CPtr))
|
||||
# 写入测试颜色:青色 (RGBA逻辑值: 0xFF00FFFF)
|
||||
fb[offset + 0] = 0xFF # B
|
||||
fb[offset + 1] = 0xFF # G
|
||||
@@ -362,7 +362,7 @@ class _VGAScreenDriver:
|
||||
r: t.CUnsignedChar = fb[offset + 2]
|
||||
# t.CVoid(fb[offset + 3]) # 忽略Alpha
|
||||
# 恢复原始像素
|
||||
c.Set(c.Deref(t.CUInt32T(fb + offset, t.CPtr)), OriginalPixel)
|
||||
c.Set(c.Deref(uint32(fb + offset, t.CPtr)), OriginalPixel)
|
||||
# 判定颜色格式
|
||||
if r == 0x00 and g == 0xFF and b == 0xFF: self.ColorFormat = __ColorFormat.ColorFormat_BGRA
|
||||
elif r == 0xFF and g == 0xFF and b == 0x00: self.ColorFormat = __ColorFormat.ColorFormat_RGBA
|
||||
@@ -370,7 +370,7 @@ class _VGAScreenDriver:
|
||||
|
||||
# 设置像素颜色 - 统一接口,输入为RGBA逻辑颜色
|
||||
# color格式: 0xAARRGGBB (Alpha, Red, Green, Blue)
|
||||
def SetPixel(self, x: int, y: int, color: t.CUInt32T):
|
||||
def SetPixel(self, x: int, y: int, color: uint32):
|
||||
fb: t.CUnsignedChar | t.CPtr = self.fb
|
||||
if fb is None: return
|
||||
if x < 0 or x >= self.fw or y < 0 or y >= self.fh: return
|
||||
@@ -408,7 +408,7 @@ class _VGAScreenDriver:
|
||||
fb[offset + 3] = a
|
||||
|
||||
# 清除屏幕 - 优化循环效率,减少函数调用开销
|
||||
def ClearScreen(self, color: t.CUInt32T):
|
||||
def ClearScreen(self, color: uint32):
|
||||
fb: t.CUnsignedChar | t.CPtr = self.fb
|
||||
fp: int = self.fp
|
||||
if fb is None: return
|
||||
@@ -458,7 +458,7 @@ class _VGAScreenDriver:
|
||||
ch: t.CUnsignedChar = t.CUnsignedChar(cr)
|
||||
if ch >= 128: ch = DEFAULT_CHAR
|
||||
# 预解析背景色Alpha,避免内层循环重复计算
|
||||
bg_alpha: t.CUInt8T = (bgcolor >> 24) & 0xFF
|
||||
bg_alpha: uint8 = (bgcolor >> 24) & 0xFF
|
||||
draw_bg: int = (bg_alpha != 0) # 背景是否需要绘制
|
||||
# 渲染8x16点阵字符
|
||||
for fy in range(FONT_HEIGHT):
|
||||
|
||||
+816
-803
File diff suppressed because it is too large.
Load diff
+142
-142
@@ -1,142 +1,142 @@
|
||||
import t, c
|
||||
|
||||
|
||||
@c.Attribute(t.attr.packed)
|
||||
class gdt_entry:
|
||||
limit_low: t.CUInt16T
|
||||
base_low: t.CUInt16T
|
||||
base_middle: t.CUInt8T
|
||||
access: t.CUInt8T
|
||||
granularity: t.CUInt8T
|
||||
base_high: t.CUInt8T
|
||||
|
||||
@c.Attribute(t.attr.packed)
|
||||
class gdt_entry64:
|
||||
limit_low: t.CUInt16T
|
||||
base_low: t.CUInt16T
|
||||
base_middle: t.CUInt8T
|
||||
access: t.CUInt8T
|
||||
granularity: t.CUInt8T
|
||||
base_high: t.CUInt8T
|
||||
base_upper: t.CUInt32T
|
||||
reserved: t.CUInt32T
|
||||
|
||||
@c.Attribute(t.attr.packed)
|
||||
class gdt_ptr:
|
||||
limit: t.CUInt16T
|
||||
base: t.CUInt64T
|
||||
|
||||
gdt: t.CArray[gdt_entry, 7] | t.CExport = []
|
||||
gp: t.CArray[t.CUInt8T, 10] | t.CExport
|
||||
# TSS buffer: 104 bytes, raw byte array to avoid packed struct issues
|
||||
# x86_64 TSS layout: reserved0(4) rsp0(8) rsp1(8) rsp2(8) reserved1(8) ist1-ist7(56) reserved2(8) reserved3(2) iomap_base(2)
|
||||
tss_buf: t.CArray[t.CUInt8T, 104]
|
||||
|
||||
CODE_SEG: t.CDefine | t.CUInt16T = 0x08
|
||||
DATA_SEG: t.CDefine | t.CUInt16T = 0x10
|
||||
USER_CODE_SEG: t.CDefine | t.CUInt16T = 0x18
|
||||
USER_DATA_SEG: t.CDefine | t.CUInt16T = 0x20
|
||||
TSS_SEG: t.CDefine | t.CUInt16T = 0x28
|
||||
|
||||
|
||||
def init():
|
||||
global gp, gdt, tss_buf
|
||||
gdt[0].limit_low = 0
|
||||
gdt[0].base_low = 0
|
||||
gdt[0].base_middle = 0
|
||||
gdt[0].access = 0
|
||||
gdt[0].granularity = 0
|
||||
gdt[0].base_high = 0
|
||||
gdt[1].limit_low = 0
|
||||
gdt[1].base_low = 0
|
||||
gdt[1].base_middle = 0
|
||||
gdt[1].access = 0x9A
|
||||
gdt[1].granularity = 0x20
|
||||
gdt[1].base_high = 0
|
||||
gdt[2].limit_low = 0
|
||||
gdt[2].base_low = 0
|
||||
gdt[2].base_middle = 0
|
||||
gdt[2].access = 0x92
|
||||
gdt[2].granularity = 0xCF
|
||||
gdt[2].base_high = 0
|
||||
gdt[3].limit_low = 0
|
||||
gdt[3].base_low = 0
|
||||
gdt[3].base_middle = 0
|
||||
gdt[3].access = 0xFA
|
||||
gdt[3].granularity = 0x20
|
||||
gdt[3].base_high = 0
|
||||
gdt[4].limit_low = 0
|
||||
gdt[4].base_low = 0
|
||||
gdt[4].base_middle = 0
|
||||
gdt[4].access = 0xF2
|
||||
gdt[4].granularity = 0xCF
|
||||
gdt[4].base_high = 0
|
||||
# Set up TSS descriptor in GDT entries 5-6 (selector 0x28)
|
||||
setTSS64(5, t.CUInt64T(c.Addr(tss_buf)), 103)
|
||||
c.Asm("""lea rax, [rip + gdt]
|
||||
lea rcx, [rip + gp]
|
||||
mov word ptr [rcx], 0x37
|
||||
mov qword ptr [rcx+2], rax""",
|
||||
op=[t.ASM_DESCR.CLOBBER_MEMORY, t.ASM_DESCR.CLOBBER_RAX, t.ASM_DESCR.CLOBBER_RCX])
|
||||
c.Asm("sfence; mfence", op=[t.ASM_DESCR.CLOBBER_MEMORY])
|
||||
flush()
|
||||
# Initialize TSS: set iomap_base = 104 (0x68) at offset 102
|
||||
tss_buf[102] = 0x68
|
||||
tss_buf[103] = 0x00
|
||||
# Load Task Register with TSS selector 0x28
|
||||
c.Asm("""mov ax, 0x28
|
||||
ltr ax""",
|
||||
op=[t.ASM_DESCR.CLOBBER_RAX])
|
||||
|
||||
@c.Attribute(t.attr.naked)
|
||||
def flush():
|
||||
c.Asm("""lea rax, [rip + gp]
|
||||
lgdt [rax]
|
||||
push 0x08
|
||||
lea rax, [rip+2f]
|
||||
push rax
|
||||
.byte 0x48, 0xcb
|
||||
2:
|
||||
mov eax, 0x10
|
||||
mov ds, eax
|
||||
mov es, eax
|
||||
mov fs, eax
|
||||
mov gs, eax
|
||||
mov ss, eax
|
||||
ret""", op=[t.ASM_DESCR.CLOBBER_MEMORY, t.ASM_DESCR.CLOBBER_RAX])
|
||||
|
||||
def set_tss_rsp0(rsp0: t.CUInt64T):
|
||||
global tss_buf
|
||||
# TSS RSP0 is at offset 4 (8 bytes) in x86_64 TSS layout
|
||||
tss_buf[4] = t.CUInt8T(rsp0 & 0xFF)
|
||||
tss_buf[5] = t.CUInt8T((rsp0 >> 8) & 0xFF)
|
||||
tss_buf[6] = t.CUInt8T((rsp0 >> 16) & 0xFF)
|
||||
tss_buf[7] = t.CUInt8T((rsp0 >> 24) & 0xFF)
|
||||
tss_buf[8] = t.CUInt8T((rsp0 >> 32) & 0xFF)
|
||||
tss_buf[9] = t.CUInt8T((rsp0 >> 40) & 0xFF)
|
||||
tss_buf[10] = t.CUInt8T((rsp0 >> 48) & 0xFF)
|
||||
tss_buf[11] = t.CUInt8T((rsp0 >> 56) & 0xFF)
|
||||
|
||||
def setGate(num: int, base: t.CUInt64T, limit: t.CUInt32T, access: t.CUInt8T, gran: t.CUInt8T):
|
||||
global gdt
|
||||
gdt[num].limit_low = (limit & 0xFFFF)
|
||||
gdt[num].base_low = (base & 0xFFFF)
|
||||
gdt[num].base_middle = (base >> 16) & 0xFF
|
||||
gdt[num].base_high = (base >> 24) & 0xFF
|
||||
gdt[num].granularity = ((limit >> 16) & 0x0F) | (gran & 0xF0)
|
||||
gdt[num].access = access
|
||||
|
||||
def setTSS64(num: int, base: t.CUInt64T, limit: t.CUInt32T):
|
||||
global gdt
|
||||
gdt[num].limit_low = limit & 0xFFFF
|
||||
gdt[num].base_low = base & 0xFFFF
|
||||
gdt[num].base_middle = (base >> 16) & 0xFF
|
||||
gdt[num].access = 0x89
|
||||
gdt[num].granularity = 0x00
|
||||
gdt[num].base_high = (base >> 24) & 0xFF
|
||||
gdt[num + 1].limit_low = (base >> 32) & 0xFFFF
|
||||
gdt[num + 1].base_low = (base >> 48) & 0xFFFF
|
||||
gdt[num + 1].base_middle = 0
|
||||
gdt[num + 1].access = 0
|
||||
gdt[num + 1].granularity = 0
|
||||
gdt[num + 1].base_high = 0
|
||||
import t, c
|
||||
|
||||
|
||||
@c.Attribute(t.attr.packed)
|
||||
class gdt_entry:
|
||||
limit_low: uint16
|
||||
base_low: uint16
|
||||
base_middle: uint8
|
||||
access: uint8
|
||||
granularity: uint8
|
||||
base_high: uint8
|
||||
|
||||
@c.Attribute(t.attr.packed)
|
||||
class gdt_entry64:
|
||||
limit_low: uint16
|
||||
base_low: uint16
|
||||
base_middle: uint8
|
||||
access: uint8
|
||||
granularity: uint8
|
||||
base_high: uint8
|
||||
base_upper: uint32
|
||||
reserved: uint32
|
||||
|
||||
@c.Attribute(t.attr.packed)
|
||||
class gdt_ptr:
|
||||
limit: uint16
|
||||
base: uint64
|
||||
|
||||
gdt: t.CArray[gdt_entry, 7] | t.CExport = []
|
||||
gp: t.CArray[uint8, 10] | t.CExport
|
||||
# TSS buffer: 104 bytes, raw byte array to avoid packed struct issues
|
||||
# x86_64 TSS layout: reserved0(4) rsp0(8) rsp1(8) rsp2(8) reserved1(8) ist1-ist7(56) reserved2(8) reserved3(2) iomap_base(2)
|
||||
tss_buf: t.CArray[uint8, 104]
|
||||
|
||||
CODE_SEG: t.CDefine | uint16 = 0x08
|
||||
DATA_SEG: t.CDefine | uint16 = 0x10
|
||||
USER_CODE_SEG: t.CDefine | uint16 = 0x18
|
||||
USER_DATA_SEG: t.CDefine | uint16 = 0x20
|
||||
TSS_SEG: t.CDefine | uint16 = 0x28
|
||||
|
||||
|
||||
def init():
|
||||
global gp, gdt, tss_buf
|
||||
gdt[0].limit_low = 0
|
||||
gdt[0].base_low = 0
|
||||
gdt[0].base_middle = 0
|
||||
gdt[0].access = 0
|
||||
gdt[0].granularity = 0
|
||||
gdt[0].base_high = 0
|
||||
gdt[1].limit_low = 0
|
||||
gdt[1].base_low = 0
|
||||
gdt[1].base_middle = 0
|
||||
gdt[1].access = 0x9A
|
||||
gdt[1].granularity = 0x20
|
||||
gdt[1].base_high = 0
|
||||
gdt[2].limit_low = 0
|
||||
gdt[2].base_low = 0
|
||||
gdt[2].base_middle = 0
|
||||
gdt[2].access = 0x92
|
||||
gdt[2].granularity = 0xCF
|
||||
gdt[2].base_high = 0
|
||||
gdt[3].limit_low = 0
|
||||
gdt[3].base_low = 0
|
||||
gdt[3].base_middle = 0
|
||||
gdt[3].access = 0xFA
|
||||
gdt[3].granularity = 0x20
|
||||
gdt[3].base_high = 0
|
||||
gdt[4].limit_low = 0
|
||||
gdt[4].base_low = 0
|
||||
gdt[4].base_middle = 0
|
||||
gdt[4].access = 0xF2
|
||||
gdt[4].granularity = 0xCF
|
||||
gdt[4].base_high = 0
|
||||
# Set up TSS descriptor in GDT entries 5-6 (selector 0x28)
|
||||
setTSS64(5, uint64(c.Addr(tss_buf)), 103)
|
||||
c.Asm("""lea rax, [rip + gdt]
|
||||
lea rcx, [rip + gp]
|
||||
mov word ptr [rcx], 0x37
|
||||
mov qword ptr [rcx+2], rax""",
|
||||
op=[t.ASM_DESCR.CLOBBER_MEMORY, t.ASM_DESCR.CLOBBER_RAX, t.ASM_DESCR.CLOBBER_RCX])
|
||||
c.Asm("sfence; mfence", op=[t.ASM_DESCR.CLOBBER_MEMORY])
|
||||
flush()
|
||||
# Initialize TSS: set iomap_base = 104 (0x68) at offset 102
|
||||
tss_buf[102] = 0x68
|
||||
tss_buf[103] = 0x00
|
||||
# Load Task Register with TSS selector 0x28
|
||||
c.Asm("""mov ax, 0x28
|
||||
ltr ax""",
|
||||
op=[t.ASM_DESCR.CLOBBER_RAX])
|
||||
|
||||
@c.Attribute(t.attr.naked)
|
||||
def flush():
|
||||
c.Asm("""lea rax, [rip + gp]
|
||||
lgdt [rax]
|
||||
push 0x08
|
||||
lea rax, [rip+2f]
|
||||
push rax
|
||||
.byte 0x48, 0xcb
|
||||
2:
|
||||
mov eax, 0x10
|
||||
mov ds, eax
|
||||
mov es, eax
|
||||
mov fs, eax
|
||||
mov gs, eax
|
||||
mov ss, eax
|
||||
ret""", op=[t.ASM_DESCR.CLOBBER_MEMORY, t.ASM_DESCR.CLOBBER_RAX])
|
||||
|
||||
def set_tss_rsp0(rsp0: uint64):
|
||||
global tss_buf
|
||||
# TSS RSP0 is at offset 4 (8 bytes) in x86_64 TSS layout
|
||||
tss_buf[4] = uint8(rsp0 & 0xFF)
|
||||
tss_buf[5] = uint8((rsp0 >> 8) & 0xFF)
|
||||
tss_buf[6] = uint8((rsp0 >> 16) & 0xFF)
|
||||
tss_buf[7] = uint8((rsp0 >> 24) & 0xFF)
|
||||
tss_buf[8] = uint8((rsp0 >> 32) & 0xFF)
|
||||
tss_buf[9] = uint8((rsp0 >> 40) & 0xFF)
|
||||
tss_buf[10] = uint8((rsp0 >> 48) & 0xFF)
|
||||
tss_buf[11] = uint8((rsp0 >> 56) & 0xFF)
|
||||
|
||||
def setGate(num: int, base: uint64, limit: uint32, access: uint8, gran: uint8):
|
||||
global gdt
|
||||
gdt[num].limit_low = (limit & 0xFFFF)
|
||||
gdt[num].base_low = (base & 0xFFFF)
|
||||
gdt[num].base_middle = (base >> 16) & 0xFF
|
||||
gdt[num].base_high = (base >> 24) & 0xFF
|
||||
gdt[num].granularity = ((limit >> 16) & 0x0F) | (gran & 0xF0)
|
||||
gdt[num].access = access
|
||||
|
||||
def setTSS64(num: int, base: uint64, limit: uint32):
|
||||
global gdt
|
||||
gdt[num].limit_low = limit & 0xFFFF
|
||||
gdt[num].base_low = base & 0xFFFF
|
||||
gdt[num].base_middle = (base >> 16) & 0xFF
|
||||
gdt[num].access = 0x89
|
||||
gdt[num].granularity = 0x00
|
||||
gdt[num].base_high = (base >> 24) & 0xFF
|
||||
gdt[num + 1].limit_low = (base >> 32) & 0xFFFF
|
||||
gdt[num + 1].base_low = (base >> 48) & 0xFFFF
|
||||
gdt[num + 1].base_middle = 0
|
||||
gdt[num + 1].access = 0
|
||||
gdt[num + 1].granularity = 0
|
||||
gdt[num + 1].base_high = 0
|
||||
+95
-88
@@ -7,20 +7,20 @@ import viperlib
|
||||
import asm
|
||||
import t, c
|
||||
|
||||
CODE_SEG: t.CDefine | t.CUInt16T = 0x08
|
||||
CODE_SEG: t.CDefine | uint16 = 0x08
|
||||
|
||||
@c.Attribute(t.attr.packed)
|
||||
class idt_entry:
|
||||
base_low: t.CUInt16T
|
||||
selector: t.CUInt16T
|
||||
ist_attr: t.CUInt8T
|
||||
type_attr: t.CUInt8T
|
||||
base_middle: t.CUInt16T
|
||||
base_high: t.CUInt32T
|
||||
reserved1: t.CUInt32T
|
||||
base_low: uint16
|
||||
selector: uint16
|
||||
ist_attr: uint8
|
||||
type_attr: uint8
|
||||
base_middle: uint16
|
||||
base_high: uint32
|
||||
reserved1: uint32
|
||||
idt: t.CArray[idt_entry, 256] | t.CExport = []
|
||||
|
||||
irq_handler_t: t.CTypedef = t.Callable[[], t.CInt]
|
||||
irq_handler_t: t.CTypedef = t.Callable[[], int]
|
||||
|
||||
def isr0() -> t.State: pass
|
||||
def isr1() -> t.State: pass
|
||||
@@ -75,7 +75,7 @@ def isr80() -> t.State: pass
|
||||
|
||||
def isr_default() -> t.State: pass
|
||||
|
||||
def setGate(num: int, base: t.CUInt64T, sel: t.CUInt16T, flags: t.CUInt8T):
|
||||
def setGate(num: int, base: uint64, sel: uint16, flags: uint8):
|
||||
global idt
|
||||
idt[num].base_low = (base & 0xFFFF)
|
||||
idt[num].base_middle = (base >> 16) & 0xFFFF
|
||||
@@ -85,7 +85,7 @@ def setGate(num: int, base: t.CUInt64T, sel: t.CUInt16T, flags: t.CUInt8T):
|
||||
idt[num].type_attr = flags
|
||||
idt[num].reserved1 = 0
|
||||
|
||||
def isrCommonhandler(interrupt: t.CInt):
|
||||
def isrCommonhandler(interrupt: int):
|
||||
c.Asm(f"""mov dx, 0x3F8
|
||||
mov al, 91
|
||||
out dx, al
|
||||
@@ -112,12 +112,12 @@ def isrCommonhandler(interrupt: t.CInt):
|
||||
op=[t.ASM_DESCR.CLOBBER_RAX, t.ASM_DESCR.CLOBBER_RCX, t.ASM_DESCR.CLOBBER_RDX])
|
||||
# Print CR2 for page faults (ISR 14)
|
||||
if interrupt == 14:
|
||||
cr2: t.CUInt64T = 0
|
||||
cr2: uint64 = 0
|
||||
c.Asm(f"""mov {c.AsmOut(cr2, t.ASM_DESCR.OUTPUT_REG)}, cr2""",
|
||||
op=[t.ASM_DESCR.CLOBBER_RAX])
|
||||
fault_rip: t.CUInt64T = 0
|
||||
fault_err: t.CUInt64T = 0
|
||||
fault_rsp: t.CUInt64T = 0
|
||||
fault_rip: uint64 = 0
|
||||
fault_err: uint64 = 0
|
||||
fault_rsp: uint64 = 0
|
||||
c.Asm(f"""mov {c.AsmOut(fault_rip, t.ASM_DESCR.OUTPUT_REG)}, [_fault_rip]
|
||||
mov {c.AsmOut(fault_err, t.ASM_DESCR.OUTPUT_REG)}, [_fault_err]
|
||||
mov {c.AsmOut(fault_rsp, t.ASM_DESCR.OUTPUT_REG)}, [_fault_rsp]""",
|
||||
@@ -128,14 +128,14 @@ def isrCommonhandler(interrupt: t.CInt):
|
||||
# [CR3] 当前 pml4:定位栈区/对象写缺页是否因 pml4 被 switch_pid 切走
|
||||
# (内核 pml4=0xf801000,用户 pml4=0x9781xxx —— 若显示用户 pml4 而 rsp
|
||||
# 在 bootloader 栈区 0x60000-0x80000,则是进程切换后未切回内核页表)。
|
||||
cur_cr3: t.CUInt64T = 0
|
||||
cur_cr3: uint64 = 0
|
||||
c.Asm(f"mov {c.AsmOut(cur_cr3, t.ASM_DESCR.OUTPUT_REG)}, cr3",
|
||||
op=[t.ASM_DESCR.CLOBBER_RAX])
|
||||
cr3_buf: t.CArray[t.CChar, 80]
|
||||
viperlib.snprintf(c.Addr(cr3_buf), 80, "[CR3] pml4=0x%lx\n", cur_cr3)
|
||||
serial.puts(cr3_buf)
|
||||
# [RAX] 崩溃时 rax(isr.s 保存):定位 cr2 与 rax 关系(rax-偏移=cr2)
|
||||
f_rax: t.CUInt64T = 0
|
||||
f_rax: uint64 = 0
|
||||
c.Asm(f"""mov {c.AsmOut(f_rax, t.ASM_DESCR.OUTPUT_REG)}, [_fault_rax]""",
|
||||
op=[t.ASM_DESCR.CLOBBER_RAX])
|
||||
rax_buf: t.CArray[t.CChar, 80]
|
||||
@@ -143,7 +143,7 @@ def isrCommonhandler(interrupt: t.CInt):
|
||||
serial.puts(rax_buf)
|
||||
# [STK] rbp 链回溯(定位栈损坏源:崩溃帧 + 4 级调用链的返回地址)
|
||||
# 先读崩溃 rbp 判断(用户 rbp 不回溯,避免读用户地址嵌套 #PF)
|
||||
fr0: t.CUInt64T = 0
|
||||
fr0: uint64 = 0
|
||||
c.Asm(f"""mov rax, [_fault_rbp]
|
||||
mov {c.AsmOut(fr0, t.ASM_DESCR.OUTPUT_REG)}, rax""",
|
||||
op=[t.ASM_DESCR.CLOBBER_RAX])
|
||||
@@ -153,10 +153,10 @@ def isrCommonhandler(interrupt: t.CInt):
|
||||
viperlib.snprintf(c.Addr(stk_buf), 160, "[STK] user rbp=0x%lx, chain skipped\n", fr0)
|
||||
serial.puts(stk_buf)
|
||||
else:
|
||||
fr1: t.CUInt64T = 0
|
||||
fr2: t.CUInt64T = 0
|
||||
fr3: t.CUInt64T = 0
|
||||
fr4: t.CUInt64T = 0
|
||||
fr1: uint64 = 0
|
||||
fr2: uint64 = 0
|
||||
fr3: uint64 = 0
|
||||
fr4: uint64 = 0
|
||||
c.Asm(f"""mov rax, [_fault_rbp]
|
||||
mov rax, [rax + 8]
|
||||
mov {c.AsmOut(fr1, t.ASM_DESCR.OUTPUT_REG)}, rax
|
||||
@@ -175,11 +175,11 @@ def isrCommonhandler(interrupt: t.CInt):
|
||||
fr0, fr1, fr2, fr3, fr4)
|
||||
serial.puts(stk_buf)
|
||||
elif interrupt == 13:
|
||||
gp_rip: t.CUInt64T = 0
|
||||
gp_err: t.CUInt64T = 0
|
||||
gp_rsp: t.CUInt64T = 0
|
||||
gp_cr4: t.CUInt64T = 0
|
||||
gp_cr0: t.CUInt64T = 0
|
||||
gp_rip: uint64 = 0
|
||||
gp_err: uint64 = 0
|
||||
gp_rsp: uint64 = 0
|
||||
gp_cr4: uint64 = 0
|
||||
gp_cr0: uint64 = 0
|
||||
c.Asm(f"""mov {c.AsmOut(gp_rip, t.ASM_DESCR.OUTPUT_REG)}, [_fault_rip]
|
||||
mov {c.AsmOut(gp_err, t.ASM_DESCR.OUTPUT_REG)}, [_fault_err]
|
||||
mov {c.AsmOut(gp_rsp, t.ASM_DESCR.OUTPUT_REG)}, [_fault_rsp]
|
||||
@@ -194,8 +194,8 @@ def isrCommonhandler(interrupt: t.CInt):
|
||||
serial.puts(gp_buf)
|
||||
else:
|
||||
# 其他异常(#UD 等):打印 rip/rsp 定位执行位置(isr.s 已保存 _fault_rip)
|
||||
ex_rip: t.CUInt64T = 0
|
||||
ex_rsp: t.CUInt64T = 0
|
||||
ex_rip: uint64 = 0
|
||||
ex_rsp: uint64 = 0
|
||||
c.Asm(f"""mov {c.AsmOut(ex_rip, t.ASM_DESCR.OUTPUT_REG)}, [_fault_rip]
|
||||
mov {c.AsmOut(ex_rsp, t.ASM_DESCR.OUTPUT_REG)}, [_fault_rsp]""",
|
||||
op=[t.ASM_DESCR.CLOBBER_RAX])
|
||||
@@ -203,18 +203,18 @@ def isrCommonhandler(interrupt: t.CInt):
|
||||
viperlib.snprintf(c.Addr(ex_buf), 100, "[EX] int=%d rip=0x%lx rsp=0x%lx\n", interrupt, ex_rip, ex_rsp)
|
||||
serial.puts(ex_buf)
|
||||
# [RAX] 崩溃时 rax(isr.s 保存)
|
||||
f_rax: t.CUInt64T = 0
|
||||
f_rax: uint64 = 0
|
||||
c.Asm(f"""mov {c.AsmOut(f_rax, t.ASM_DESCR.OUTPUT_REG)}, [_fault_rax]""",
|
||||
op=[t.ASM_DESCR.CLOBBER_RAX])
|
||||
rax_buf: t.CArray[t.CChar, 80]
|
||||
viperlib.snprintf(c.Addr(rax_buf), 80, "[RAX] rax=0x%lx\n", f_rax)
|
||||
serial.puts(rax_buf)
|
||||
# [STK] rbp 链回溯(与 #PF 分支一致,定位栈损坏源)
|
||||
fr0: t.CUInt64T = 0
|
||||
fr1: t.CUInt64T = 0
|
||||
fr2: t.CUInt64T = 0
|
||||
fr3: t.CUInt64T = 0
|
||||
fr4: t.CUInt64T = 0
|
||||
fr0: uint64 = 0
|
||||
fr1: uint64 = 0
|
||||
fr2: uint64 = 0
|
||||
fr3: uint64 = 0
|
||||
fr4: uint64 = 0
|
||||
c.Asm(f"""mov rax, [_fault_rbp]
|
||||
mov {c.AsmOut(fr0, t.ASM_DESCR.OUTPUT_REG)}, rax
|
||||
mov rax, [rax + 8]
|
||||
@@ -246,13 +246,20 @@ def isrCommonhandler(interrupt: t.CInt):
|
||||
asm.sti()
|
||||
asm.hlt()
|
||||
pass
|
||||
tid: t.CInt = s.current_tid
|
||||
tid: int = s.current_tid
|
||||
if tid == 0:
|
||||
serial.puts(" KERNEL PANIC\n")
|
||||
while True:
|
||||
asm.sti()
|
||||
asm.hlt()
|
||||
pass
|
||||
# s.threads 为 [16 x Thread](sched.MAX_THREADS),越界写会破坏调度器状态
|
||||
if tid < 0 or tid >= 16:
|
||||
serial.puts(" KERNEL PANIC (bad tid)\n")
|
||||
while True:
|
||||
asm.sti()
|
||||
asm.hlt()
|
||||
pass
|
||||
buf2: t.CArray[t.CChar, 64]
|
||||
viperlib.snprintf(c.Addr(buf2), 64, " exc in tid=%d, terminating\n", tid)
|
||||
serial.puts(buf2)
|
||||
@@ -460,78 +467,78 @@ def isr47_handler() -> t.CExport | t.CVoid:
|
||||
apic.eoi()
|
||||
|
||||
def init_exceptions():
|
||||
setGate(0, t.CUInt64T(isr0), CODE_SEG, 0x8E)
|
||||
setGate(1, t.CUInt64T(isr1), CODE_SEG, 0x8E)
|
||||
setGate(2, t.CUInt64T(isr2), CODE_SEG, 0x8E)
|
||||
setGate(3, t.CUInt64T(isr3), CODE_SEG, 0x8E)
|
||||
setGate(4, t.CUInt64T(isr4), CODE_SEG, 0x8E)
|
||||
setGate(5, t.CUInt64T(isr5), CODE_SEG, 0x8E)
|
||||
setGate(6, t.CUInt64T(isr6), CODE_SEG, 0x8E)
|
||||
setGate(7, t.CUInt64T(isr7), CODE_SEG, 0x8E)
|
||||
setGate(8, t.CUInt64T(isr8), CODE_SEG, 0x8E)
|
||||
setGate(9, t.CUInt64T(isr9), CODE_SEG, 0x8E)
|
||||
setGate(10, t.CUInt64T(isr10), CODE_SEG, 0x8E)
|
||||
setGate(11, t.CUInt64T(isr11), CODE_SEG, 0x8E)
|
||||
setGate(12, t.CUInt64T(isr12), CODE_SEG, 0x8E)
|
||||
setGate(13, t.CUInt64T(isr13), CODE_SEG, 0x8E)
|
||||
setGate(14, t.CUInt64T(isr14), CODE_SEG, 0x8E)
|
||||
setGate(15, t.CUInt64T(isr15), CODE_SEG, 0x8E)
|
||||
setGate(16, t.CUInt64T(isr16), CODE_SEG, 0x8E)
|
||||
setGate(17, t.CUInt64T(isr17), CODE_SEG, 0x8E)
|
||||
setGate(18, t.CUInt64T(isr18), CODE_SEG, 0x8E)
|
||||
setGate(19, t.CUInt64T(isr19), CODE_SEG, 0x8E)
|
||||
setGate(20, t.CUInt64T(isr20), CODE_SEG, 0x8E)
|
||||
setGate(21, t.CUInt64T(isr21), CODE_SEG, 0x8E)
|
||||
setGate(22, t.CUInt64T(isr22), CODE_SEG, 0x8E)
|
||||
setGate(23, t.CUInt64T(isr23), CODE_SEG, 0x8E)
|
||||
setGate(24, t.CUInt64T(isr24), CODE_SEG, 0x8E)
|
||||
setGate(25, t.CUInt64T(isr25), CODE_SEG, 0x8E)
|
||||
setGate(26, t.CUInt64T(isr26), CODE_SEG, 0x8E)
|
||||
setGate(27, t.CUInt64T(isr27), CODE_SEG, 0x8E)
|
||||
setGate(28, t.CUInt64T(isr28), CODE_SEG, 0x8E)
|
||||
setGate(29, t.CUInt64T(isr29), CODE_SEG, 0x8E)
|
||||
setGate(30, t.CUInt64T(isr30), CODE_SEG, 0x8E)
|
||||
setGate(31, t.CUInt64T(isr31), CODE_SEG, 0x8E)
|
||||
setGate(0, uint64(isr0), CODE_SEG, 0x8E)
|
||||
setGate(1, uint64(isr1), CODE_SEG, 0x8E)
|
||||
setGate(2, uint64(isr2), CODE_SEG, 0x8E)
|
||||
setGate(3, uint64(isr3), CODE_SEG, 0x8E)
|
||||
setGate(4, uint64(isr4), CODE_SEG, 0x8E)
|
||||
setGate(5, uint64(isr5), CODE_SEG, 0x8E)
|
||||
setGate(6, uint64(isr6), CODE_SEG, 0x8E)
|
||||
setGate(7, uint64(isr7), CODE_SEG, 0x8E)
|
||||
setGate(8, uint64(isr8), CODE_SEG, 0x8E)
|
||||
setGate(9, uint64(isr9), CODE_SEG, 0x8E)
|
||||
setGate(10, uint64(isr10), CODE_SEG, 0x8E)
|
||||
setGate(11, uint64(isr11), CODE_SEG, 0x8E)
|
||||
setGate(12, uint64(isr12), CODE_SEG, 0x8E)
|
||||
setGate(13, uint64(isr13), CODE_SEG, 0x8E)
|
||||
setGate(14, uint64(isr14), CODE_SEG, 0x8E)
|
||||
setGate(15, uint64(isr15), CODE_SEG, 0x8E)
|
||||
setGate(16, uint64(isr16), CODE_SEG, 0x8E)
|
||||
setGate(17, uint64(isr17), CODE_SEG, 0x8E)
|
||||
setGate(18, uint64(isr18), CODE_SEG, 0x8E)
|
||||
setGate(19, uint64(isr19), CODE_SEG, 0x8E)
|
||||
setGate(20, uint64(isr20), CODE_SEG, 0x8E)
|
||||
setGate(21, uint64(isr21), CODE_SEG, 0x8E)
|
||||
setGate(22, uint64(isr22), CODE_SEG, 0x8E)
|
||||
setGate(23, uint64(isr23), CODE_SEG, 0x8E)
|
||||
setGate(24, uint64(isr24), CODE_SEG, 0x8E)
|
||||
setGate(25, uint64(isr25), CODE_SEG, 0x8E)
|
||||
setGate(26, uint64(isr26), CODE_SEG, 0x8E)
|
||||
setGate(27, uint64(isr27), CODE_SEG, 0x8E)
|
||||
setGate(28, uint64(isr28), CODE_SEG, 0x8E)
|
||||
setGate(29, uint64(isr29), CODE_SEG, 0x8E)
|
||||
setGate(30, uint64(isr30), CODE_SEG, 0x8E)
|
||||
setGate(31, uint64(isr31), CODE_SEG, 0x8E)
|
||||
|
||||
def init_irqs():
|
||||
setGate(32, t.CUInt64T(isr32), CODE_SEG, 0x8E)
|
||||
setGate(33, t.CUInt64T(isr33), CODE_SEG, 0x8E)
|
||||
setGate(34, t.CUInt64T(isr34), CODE_SEG, 0x8E)
|
||||
setGate(35, t.CUInt64T(isr35), CODE_SEG, 0x8E)
|
||||
setGate(36, t.CUInt64T(isr36), CODE_SEG, 0x8E)
|
||||
setGate(37, t.CUInt64T(isr37), CODE_SEG, 0x8E)
|
||||
setGate(38, t.CUInt64T(isr38), CODE_SEG, 0x8E)
|
||||
setGate(39, t.CUInt64T(isr39), CODE_SEG, 0x8E)
|
||||
setGate(40, t.CUInt64T(isr40), CODE_SEG, 0x8E)
|
||||
setGate(41, t.CUInt64T(isr41), CODE_SEG, 0x8E)
|
||||
setGate(42, t.CUInt64T(isr42), CODE_SEG, 0x8E)
|
||||
setGate(43, t.CUInt64T(isr43), CODE_SEG, 0x8E)
|
||||
setGate(44, t.CUInt64T(isr44), CODE_SEG, 0x8E)
|
||||
setGate(45, t.CUInt64T(isr45), CODE_SEG, 0x8E)
|
||||
setGate(46, t.CUInt64T(isr46), CODE_SEG, 0x8E)
|
||||
setGate(47, t.CUInt64T(isr47), CODE_SEG, 0x8E)
|
||||
setGate(32, uint64(isr32), CODE_SEG, 0x8E)
|
||||
setGate(33, uint64(isr33), CODE_SEG, 0x8E)
|
||||
setGate(34, uint64(isr34), CODE_SEG, 0x8E)
|
||||
setGate(35, uint64(isr35), CODE_SEG, 0x8E)
|
||||
setGate(36, uint64(isr36), CODE_SEG, 0x8E)
|
||||
setGate(37, uint64(isr37), CODE_SEG, 0x8E)
|
||||
setGate(38, uint64(isr38), CODE_SEG, 0x8E)
|
||||
setGate(39, uint64(isr39), CODE_SEG, 0x8E)
|
||||
setGate(40, uint64(isr40), CODE_SEG, 0x8E)
|
||||
setGate(41, uint64(isr41), CODE_SEG, 0x8E)
|
||||
setGate(42, uint64(isr42), CODE_SEG, 0x8E)
|
||||
setGate(43, uint64(isr43), CODE_SEG, 0x8E)
|
||||
setGate(44, uint64(isr44), CODE_SEG, 0x8E)
|
||||
setGate(45, uint64(isr45), CODE_SEG, 0x8E)
|
||||
setGate(46, uint64(isr46), CODE_SEG, 0x8E)
|
||||
setGate(47, uint64(isr47), CODE_SEG, 0x8E)
|
||||
|
||||
irq_handlers: t.CStatic | t.CArray[irq_handler_t, 16] = [None]
|
||||
|
||||
def irqInstallHandler(irq: t.CInt, handler: irq_handler_t, name: str) -> t.CInt:
|
||||
def irqInstallHandler(irq: int, handler: irq_handler_t, name: str) -> int:
|
||||
global irq_handlers
|
||||
if irq < 0 or irq > 15: return -1
|
||||
irq_handlers[irq] = handler
|
||||
return 0
|
||||
|
||||
def irqGetHandler(irq: t.CInt) -> irq_handler_t:
|
||||
def irqGetHandler(irq: int) -> irq_handler_t:
|
||||
if irq < 0 or irq > 15: return None
|
||||
return irq_handlers[irq]
|
||||
|
||||
def init():
|
||||
global idt
|
||||
for i in range(256):
|
||||
setGate(i, t.CUInt64T(isr_default), CODE_SEG, 0x8E)
|
||||
setGate(i, uint64(isr_default), CODE_SEG, 0x8E)
|
||||
pic.init()
|
||||
init_exceptions()
|
||||
init_irqs()
|
||||
# Register ISR 0x80 for int 0x80 syscall interface (user-mode ELF apps)
|
||||
setGate(0x80, t.CUInt64T(isr80), CODE_SEG, 0xEE) # DPL=3 allows Ring 3 to call int 0x80
|
||||
setGate(0x80, uint64(isr80), CODE_SEG, 0xEE) # DPL=3 allows Ring 3 to call int 0x80
|
||||
# Build idt_ptr on stack and load directly in one asm block
|
||||
c.Asm("""lea rax, [rip + idt]
|
||||
sub rsp, 16
|
||||
|
||||
+142
-142
@@ -50,18 +50,18 @@ IA32_STAR: t.CDefine = 0xC0000081
|
||||
IA32_LSTAR: t.CDefine = 0xC0000082
|
||||
IA32_FMASK: t.CDefine = 0xC0000084
|
||||
|
||||
def wrmsr(msr: t.CUInt32T, val: t.CUInt64T):
|
||||
lo: t.CUInt32T = t.CUInt32T(val & 0xFFFFFFFF)
|
||||
hi: t.CUInt32T = t.CUInt32T(val >> 32)
|
||||
def wrmsr(msr: uint32, val: uint64):
|
||||
lo: uint32 = uint32(val & 0xFFFFFFFF)
|
||||
hi: uint32 = uint32(val >> 32)
|
||||
c.Asm(f"""mov ecx, {c.AsmInp(msr, t.ASM_DESCR.REG_ANY)}
|
||||
mov eax, {c.AsmInp(lo, t.ASM_DESCR.REG_ANY)}
|
||||
mov edx, {c.AsmInp(hi, t.ASM_DESCR.REG_ANY)}
|
||||
wrmsr""",
|
||||
op=[t.ASM_DESCR.CLOBBER_RCX, t.ASM_DESCR.CLOBBER_RAX, t.ASM_DESCR.CLOBBER_RDX])
|
||||
|
||||
def rdmsr(msr: t.CUInt32T) -> t.CUInt64T:
|
||||
lo: t.CUInt32T
|
||||
hi: t.CUInt32T
|
||||
def rdmsr(msr: uint32) -> uint64:
|
||||
lo: uint32
|
||||
hi: uint32
|
||||
# rdmsr 固定写 EDX:EAX;out 绑定 + CLOBBER_RAX/RDX 冲突会导致 lo/hi
|
||||
# 分配到非 EAX/EDX 读到垃圾。显式 mov 到输出寄存器(与 asm.inb 修复同模式)。
|
||||
c.Asm(f"""mov ecx, {c.AsmInp(msr, t.ASM_DESCR.REG_ANY)}
|
||||
@@ -70,67 +70,67 @@ def rdmsr(msr: t.CUInt32T) -> t.CUInt64T:
|
||||
mov {c.AsmOut(hi, t.ASM_DESCR.OUTPUT_REG)}, edx""",
|
||||
out=[c.AsmOut(lo, t.ASM_DESCR.OUTPUT_REG), c.AsmOut(hi, t.ASM_DESCR.OUTPUT_REG)],
|
||||
op=[t.ASM_DESCR.CLOBBER_RCX, t.ASM_DESCR.CLOBBER_RAX, t.ASM_DESCR.CLOBBER_RDX])
|
||||
return t.CUInt64T(lo) | (t.CUInt64T(hi) << 32)
|
||||
return uint64(lo) | (uint64(hi) << 32)
|
||||
|
||||
def _current_proc() -> process.Process | t.CPtr:
|
||||
return process.ProcessManager.current()
|
||||
|
||||
def _fd_alloc(p: process.Process | t.CPtr) -> t.CInt:
|
||||
def _fd_alloc(p: process.Process | t.CPtr) -> int:
|
||||
for i in range(process.PROC_MAX_FDS):
|
||||
if not p.fd_used[i]:
|
||||
p.fd_used[i] = 1
|
||||
return i
|
||||
return -1
|
||||
|
||||
def _fd_free(p: process.Process | t.CPtr, fd: t.CInt):
|
||||
def _fd_free(p: process.Process | t.CPtr, fd: int):
|
||||
if fd >= 0 and fd < process.PROC_MAX_FDS:
|
||||
p.fd_used[fd] = 0
|
||||
p.fd_table[fd] = t.CVoid(0, t.CPtr)
|
||||
|
||||
def _dir_alloc(p: process.Process | t.CPtr) -> t.CInt:
|
||||
def _dir_alloc(p: process.Process | t.CPtr) -> int:
|
||||
for i in range(process.PROC_MAX_DIRS):
|
||||
if not p.dir_used[i]:
|
||||
p.dir_used[i] = 1
|
||||
return i
|
||||
return -1
|
||||
|
||||
def _dir_free(p: process.Process | t.CPtr, dd: t.CInt):
|
||||
def _dir_free(p: process.Process | t.CPtr, dd: int):
|
||||
if dd >= 0 and dd < process.PROC_MAX_DIRS:
|
||||
p.dir_used[dd] = 0
|
||||
p.dir_table[dd] = t.CVoid(0, t.CPtr)
|
||||
|
||||
def CREATE_WINDOW(x: t.CInt, y: t.CInt, w: t.CInt, h: t.CInt, title: t.CConst | t.CChar | t.CPtr, style: t.CInt) -> t.CInt:
|
||||
def CREATE_WINDOW(x: int, y: int, w: int, h: int, title: t.CConst | t.CChar | t.CPtr, style: int) -> int:
|
||||
desktop.set_app_pid(process.current())
|
||||
return desktop.create(x, y, w, h, title, style)
|
||||
|
||||
def DRAW_TEXT(win_id: t.CInt, x: t.CInt, y: t.CInt, text: t.CConst | t.CChar | t.CPtr, color: t.CUInt32T) -> t.CInt:
|
||||
def DRAW_TEXT(win_id: int, x: int, y: int, text: t.CConst | t.CChar | t.CPtr, color: uint32) -> int:
|
||||
return desktop.draw_text(win_id, x, y, text, color)
|
||||
|
||||
def EXIT(code: t.CInt) -> t.CInt:
|
||||
def EXIT(code: int) -> int:
|
||||
serial.puts("[syscall] exit called\n")
|
||||
desktop.destroy_by_pid(process.current())
|
||||
return 0
|
||||
|
||||
def WAIT_WINDOW(win_id: t.CInt) -> t.CInt:
|
||||
def WAIT_WINDOW(win_id: int) -> int:
|
||||
while desktop.is_active(win_id):
|
||||
sched.Scheduler.try_reschedule()
|
||||
return 0
|
||||
|
||||
def SERIAL_PUTS(str_ptr: t.CVoid | t.CPtr) -> t.CInt:
|
||||
def SERIAL_PUTS(str_ptr: t.CPtr) -> int:
|
||||
s: t.CConst | t.CChar | t.CPtr = t.CVoid(str_ptr, t.CPtr)
|
||||
serial.puts(s)
|
||||
return 0
|
||||
|
||||
_loaded_so_base: t.CVoid | t.CPtr = None
|
||||
_loaded_so_base: t.CPtr = None
|
||||
_loaded_so_path: t.CArray[t.CChar, 64]
|
||||
|
||||
def LOAD_SO(path_ptr: t.CVoid | t.CPtr) -> t.CUInt64T:
|
||||
def LOAD_SO(path_ptr: t.CPtr) -> uint64:
|
||||
global _loaded_so_base
|
||||
path: t.CConst | t.CChar | t.CPtr = t.CVoid(path_ptr, t.CPtr)
|
||||
serial.puts("[so] loading: ")
|
||||
serial.puts(path)
|
||||
serial.puts("\n")
|
||||
base: t.CVoid | t.CPtr = elf.load_so(path)
|
||||
base: t.CPtr = elf.load_so(path)
|
||||
if base is not None:
|
||||
_loaded_so_base = base
|
||||
for i in range(63):
|
||||
@@ -138,13 +138,13 @@ def LOAD_SO(path_ptr: t.CVoid | t.CPtr) -> t.CUInt64T:
|
||||
_loaded_so_path[i] = ch
|
||||
if ch == 0: break
|
||||
_loaded_so_path[63] = 0
|
||||
return t.CUInt64T(base)
|
||||
return uint64(base)
|
||||
return 0
|
||||
|
||||
def SO_CALL1(sym_name_ptr: t.CVoid | t.CPtr, arg1: t.CVoid | t.CPtr) -> t.CInt:
|
||||
def SO_CALL1(sym_name_ptr: t.CPtr, arg1: t.CPtr) -> int:
|
||||
if _loaded_so_base is None: return -1
|
||||
sym_name: t.CConst | t.CChar | t.CPtr = t.CVoid(sym_name_ptr, t.CPtr)
|
||||
fn: t.CVoid | t.CPtr = elf.get_so_symbol(_loaded_so_base, sym_name, c.Addr(_loaded_so_path[0]))
|
||||
fn: t.CPtr = elf.get_so_symbol(_loaded_so_base, sym_name, c.Addr(_loaded_so_path[0]))
|
||||
if fn is None:
|
||||
serial.puts("[so] symbol not found\n")
|
||||
return -2
|
||||
@@ -158,29 +158,29 @@ def SO_CALL1(sym_name_ptr: t.CVoid | t.CPtr, arg1: t.CVoid | t.CPtr) -> t.CInt:
|
||||
serial.puts("[so] call returned\n")
|
||||
return 0
|
||||
|
||||
def GET_WINBUF(win_id: t.CInt) -> t.CUInt64T:
|
||||
buf: t.CVoid | t.CPtr = desktop.get_fb(win_id)
|
||||
def GET_WINBUF(win_id: int) -> uint64:
|
||||
buf: t.CPtr = desktop.get_fb(win_id)
|
||||
if buf is None:
|
||||
return 0
|
||||
return t.CUInt64T(buf)
|
||||
return uint64(buf)
|
||||
|
||||
def WIN_FLUSH(win_id: t.CInt) -> t.CInt:
|
||||
def WIN_FLUSH(win_id: int) -> int:
|
||||
desktop.flush(win_id)
|
||||
return 0
|
||||
|
||||
def SET_CURSOR(win_id: t.CInt, cursor_t: t.CInt) -> t.CInt:
|
||||
def SET_CURSOR(win_id: int, cursor_t: int) -> int:
|
||||
desktop.set_cursor_type(win_id, cursor_t)
|
||||
return 0
|
||||
|
||||
def OPEN(path_ptr: t.CVoid | t.CPtr, mode: t.CUInt32T) -> t.CInt:
|
||||
def OPEN(path_ptr: t.CPtr, mode: uint32) -> int:
|
||||
p: process.Process | t.CPtr = _current_proc()
|
||||
path: t.CConst | t.CChar | t.CPtr = t.CVoid(path_ptr, t.CPtr)
|
||||
fat32.lock()
|
||||
fp: t.CVoid | t.CPtr = fat32.open(path, t.CUInt8T(mode))
|
||||
fp: t.CPtr = fat32.open(path, uint8(mode))
|
||||
if not fp:
|
||||
fat32.unlock()
|
||||
return -1
|
||||
fd: t.CInt = _fd_alloc(p)
|
||||
fd: int = _fd_alloc(p)
|
||||
if fd < 0:
|
||||
fat32.close(fp)
|
||||
fat32.unlock()
|
||||
@@ -189,146 +189,146 @@ def OPEN(path_ptr: t.CVoid | t.CPtr, mode: t.CUInt32T) -> t.CInt:
|
||||
fat32.unlock()
|
||||
return fd
|
||||
|
||||
def CLOSE(fd: t.CInt) -> t.CInt:
|
||||
def CLOSE(fd: int) -> int:
|
||||
p: process.Process | t.CPtr = _current_proc()
|
||||
if fd < 0 or fd >= process.PROC_MAX_FDS:
|
||||
return t.CInt(fat32_types.FRESULT.FR_INVALID_OBJECT)
|
||||
fp: t.CVoid | t.CPtr = p.fd_table[fd]
|
||||
return int(fat32_types.FRESULT.FR_INVALID_OBJECT)
|
||||
fp: t.CPtr = p.fd_table[fd]
|
||||
if not fp:
|
||||
return t.CInt(fat32_types.FRESULT.FR_INVALID_OBJECT)
|
||||
return int(fat32_types.FRESULT.FR_INVALID_OBJECT)
|
||||
fat32.lock()
|
||||
res: t.CInt = t.CInt(fat32.close(fp))
|
||||
res: int = int(fat32.close(fp))
|
||||
fat32.unlock()
|
||||
_fd_free(p, fd)
|
||||
return res
|
||||
|
||||
def READ(fd: t.CInt, buf_ptr: t.CVoid | t.CPtr, count: t.CUInt32T) -> t.CInt:
|
||||
def READ(fd: int, buf_ptr: t.CPtr, count: uint32) -> int:
|
||||
p: process.Process | t.CPtr = _current_proc()
|
||||
if fd < 0 or fd >= process.PROC_MAX_FDS:
|
||||
return -1
|
||||
fp: t.CVoid | t.CPtr = p.fd_table[fd]
|
||||
fp: t.CPtr = p.fd_table[fd]
|
||||
if not fp:
|
||||
return -1
|
||||
fat32.lock()
|
||||
br: t.CUInt32T = fat32.read(fp, buf_ptr, count)
|
||||
br: uint32 = fat32.read(fp, buf_ptr, count)
|
||||
fat32.unlock()
|
||||
return t.CInt(br)
|
||||
return int(br)
|
||||
|
||||
def WRITE(fd: t.CInt, buf_ptr: t.CVoid | t.CPtr, count: t.CUInt32T) -> t.CInt:
|
||||
def WRITE(fd: int, buf_ptr: t.CPtr, count: uint32) -> int:
|
||||
p: process.Process | t.CPtr = _current_proc()
|
||||
if fd < 0 or fd >= process.PROC_MAX_FDS:
|
||||
return -1
|
||||
fp: t.CVoid | t.CPtr = p.fd_table[fd]
|
||||
fp: t.CPtr = p.fd_table[fd]
|
||||
if not fp:
|
||||
return -1
|
||||
fat32.lock()
|
||||
bw: t.CUInt32T = fat32.write(fp, buf_ptr, count)
|
||||
bw: uint32 = fat32.write(fp, buf_ptr, count)
|
||||
fat32.unlock()
|
||||
return t.CInt(bw)
|
||||
return int(bw)
|
||||
|
||||
def SEEK(fd: t.CInt, offset: t.CUInt32T) -> t.CInt:
|
||||
def SEEK(fd: int, offset: uint32) -> int:
|
||||
p: process.Process | t.CPtr = _current_proc()
|
||||
if fd < 0 or fd >= process.PROC_MAX_FDS:
|
||||
return t.CInt(fat32_types.FRESULT.FR_INVALID_OBJECT)
|
||||
fp: t.CVoid | t.CPtr = p.fd_table[fd]
|
||||
return int(fat32_types.FRESULT.FR_INVALID_OBJECT)
|
||||
fp: t.CPtr = p.fd_table[fd]
|
||||
if not fp:
|
||||
return t.CInt(fat32_types.FRESULT.FR_INVALID_OBJECT)
|
||||
return int(fat32_types.FRESULT.FR_INVALID_OBJECT)
|
||||
fat32.lock()
|
||||
r: t.CInt = t.CInt(fat32.seek(fp, offset))
|
||||
r: int = int(fat32.seek(fp, offset))
|
||||
fat32.unlock()
|
||||
return r
|
||||
|
||||
def TELL(fd: t.CInt) -> t.CUInt32T:
|
||||
def TELL(fd: int) -> uint32:
|
||||
p: process.Process | t.CPtr = _current_proc()
|
||||
if fd < 0 or fd >= process.PROC_MAX_FDS:
|
||||
return 0
|
||||
fp: t.CVoid | t.CPtr = p.fd_table[fd]
|
||||
fp: t.CPtr = p.fd_table[fd]
|
||||
if not fp:
|
||||
return 0
|
||||
fat32.lock()
|
||||
pos: t.CUInt32T = fat32.tell(fp)
|
||||
pos: uint32 = fat32.tell(fp)
|
||||
fat32.unlock()
|
||||
return pos
|
||||
|
||||
def fsize(fd: t.CInt) -> t.CUInt32T:
|
||||
def fsize(fd: int) -> uint32:
|
||||
p: process.Process | t.CPtr = _current_proc()
|
||||
if fd < 0 or fd >= process.PROC_MAX_FDS:
|
||||
return 0
|
||||
fp: t.CVoid | t.CPtr = p.fd_table[fd]
|
||||
fp: t.CPtr = p.fd_table[fd]
|
||||
if not fp:
|
||||
return 0
|
||||
fat32.lock()
|
||||
sz: t.CUInt32T = fat32.size(fp)
|
||||
sz: uint32 = fat32.size(fp)
|
||||
fat32.unlock()
|
||||
return sz
|
||||
|
||||
def MKDIR(path_ptr: t.CVoid | t.CPtr) -> t.CInt:
|
||||
def MKDIR(path_ptr: t.CPtr) -> int:
|
||||
path: t.CConst | t.CChar | t.CPtr = t.CVoid(path_ptr, t.CPtr)
|
||||
fat32.lock()
|
||||
r: t.CInt = t.CInt(fat32.mkdir(path))
|
||||
r: int = int(fat32.mkdir(path))
|
||||
fat32.unlock()
|
||||
return r
|
||||
|
||||
def REMOVE(path_ptr: t.CVoid | t.CPtr) -> t.CInt:
|
||||
def REMOVE(path_ptr: t.CPtr) -> int:
|
||||
path: t.CConst | t.CChar | t.CPtr = t.CVoid(path_ptr, t.CPtr)
|
||||
fat32.lock()
|
||||
r: t.CInt = t.CInt(fat32.remove(path))
|
||||
r: int = int(fat32.remove(path))
|
||||
fat32.unlock()
|
||||
return r
|
||||
|
||||
def OPENdir(path_ptr: t.CVoid | t.CPtr) -> t.CInt:
|
||||
def OPENdir(path_ptr: t.CPtr) -> int:
|
||||
p: process.Process | t.CPtr = _current_proc()
|
||||
path: t.CConst | t.CChar | t.CPtr = t.CVoid(path_ptr, t.CPtr)
|
||||
dd: t.CInt = _dir_alloc(p)
|
||||
dd: int = _dir_alloc(p)
|
||||
if dd < 0:
|
||||
return -1
|
||||
dp: fat32_types.dirobj | t.CPtr = c.Addr(p.dir_pool[dd])
|
||||
fat32.lock()
|
||||
res: t.CInt = t.CInt(fat32.opendir(path, dp))
|
||||
res: int = int(fat32.opendir(path, dp))
|
||||
fat32.unlock()
|
||||
if res != 0:
|
||||
_dir_free(p, dd)
|
||||
return -1
|
||||
p.dir_table[dd] = t.CVoid(t.CUInt64T(dp), t.CPtr)
|
||||
p.dir_table[dd] = t.CVoid(uint64(dp), t.CPtr)
|
||||
return dd
|
||||
|
||||
def READdir(dd: t.CInt, info_ptr: t.CVoid | t.CPtr) -> t.CInt:
|
||||
def READdir(dd: int, info_ptr: t.CPtr) -> int:
|
||||
p: process.Process | t.CPtr = _current_proc()
|
||||
if dd < 0 or dd >= process.PROC_MAX_DIRS:
|
||||
return t.CInt(fat32_types.FRESULT.FR_INVALID_OBJECT)
|
||||
dp: t.CVoid | t.CPtr = p.dir_table[dd]
|
||||
return int(fat32_types.FRESULT.FR_INVALID_OBJECT)
|
||||
dp: t.CPtr = p.dir_table[dd]
|
||||
if not dp:
|
||||
return t.CInt(fat32_types.FRESULT.FR_INVALID_OBJECT)
|
||||
return int(fat32_types.FRESULT.FR_INVALID_OBJECT)
|
||||
info: fat32_types.fileinfo | t.CPtr = info_ptr
|
||||
fat32.lock()
|
||||
r: t.CInt = t.CInt(fat32.readdir(dp, info))
|
||||
r: int = int(fat32.readdir(dp, info))
|
||||
fat32.unlock()
|
||||
return r
|
||||
|
||||
def CLOSEdir(dd: t.CInt) -> t.CInt:
|
||||
def CLOSEdir(dd: int) -> int:
|
||||
p: process.Process | t.CPtr = _current_proc()
|
||||
if dd < 0 or dd >= process.PROC_MAX_DIRS:
|
||||
return t.CInt(fat32_types.FRESULT.FR_INVALID_OBJECT)
|
||||
dp: t.CVoid | t.CPtr = p.dir_table[dd]
|
||||
return int(fat32_types.FRESULT.FR_INVALID_OBJECT)
|
||||
dp: t.CPtr = p.dir_table[dd]
|
||||
if not dp:
|
||||
return t.CInt(fat32_types.FRESULT.FR_INVALID_OBJECT)
|
||||
return int(fat32_types.FRESULT.FR_INVALID_OBJECT)
|
||||
fat32.lock()
|
||||
fat32.closedir(dp)
|
||||
fat32.unlock()
|
||||
_dir_free(p, dd)
|
||||
return 0
|
||||
|
||||
def STAT(path_ptr: t.CVoid | t.CPtr, info_ptr: t.CVoid | t.CPtr) -> t.CInt:
|
||||
def STAT(path_ptr: t.CPtr, info_ptr: t.CPtr) -> int:
|
||||
path: t.CConst | t.CChar | t.CPtr = t.CVoid(path_ptr, t.CPtr)
|
||||
info: fat32_types.fileinfo | t.CPtr = info_ptr
|
||||
fat32.lock()
|
||||
r: t.CInt = t.CInt(fat32.stat(path, info))
|
||||
r: int = int(fat32.stat(path, info))
|
||||
fat32.unlock()
|
||||
return r
|
||||
|
||||
def SPAWN(path_ptr: t.CVoid | t.CPtr, blocking: t.CInt) -> t.CInt:
|
||||
def SPAWN(path_ptr: t.CPtr, blocking: int) -> int:
|
||||
path: t.CConst | t.CChar | t.CPtr = t.CVoid(path_ptr, t.CPtr)
|
||||
pid: t.CInt = elf.spawn_elf(path)
|
||||
pid: int = elf.spawn_elf(path)
|
||||
if pid < 0:
|
||||
return pid
|
||||
if blocking:
|
||||
@@ -340,135 +340,135 @@ def SPAWN(path_ptr: t.CVoid | t.CPtr, blocking: t.CInt) -> t.CInt:
|
||||
|
||||
USER_HEAP_BASE: t.CDefine = 0x20000000
|
||||
|
||||
def MMAP(size: t.CUInt64T) -> t.CUInt64T:
|
||||
def MMAP(size: uint64) -> uint64:
|
||||
p: process.Process | t.CPtr = _current_proc()
|
||||
if size == 0: return 0
|
||||
aligned_size: t.CUInt64T = (size + 4095) & ~t.CUInt64T(4095)
|
||||
aligned_size: uint64 = (size + 4095) & ~uint64(4095)
|
||||
if p.heap_start == 0:
|
||||
p.heap_start = USER_HEAP_BASE
|
||||
heap_end: t.CUInt64T = p.heap_start + p.heap_size
|
||||
new_end: t.CUInt64T = heap_end + aligned_size
|
||||
heap_end: uint64 = p.heap_start + p.heap_size
|
||||
new_end: uint64 = heap_end + aligned_size
|
||||
for va in range(heap_end, new_end, 4096):
|
||||
phys_page: t.CVoid | t.CPtr = mm.malloc(4096)
|
||||
phys_page: t.CPtr = mm.malloc(4096)
|
||||
if phys_page is None: return 0
|
||||
paging.MapPage(va, t.CUInt64T(phys_page), paging.PTE_PRESENT | paging.PTE_WRITABLE | paging.PTE_USER)
|
||||
paging.MapPage(va, uint64(phys_page), paging.PTE_PRESENT | paging.PTE_WRITABLE | paging.PTE_USER)
|
||||
p.heap_size = p.heap_size + aligned_size
|
||||
return heap_end
|
||||
|
||||
def MUNMAP(ptr: t.CUInt64T, size: t.CUInt64T) -> t.CInt:
|
||||
def MUNMAP(ptr: uint64, size: uint64) -> int:
|
||||
return 0
|
||||
|
||||
def syscall_entry() -> t.CExtern | t.CVoid | t.State: pass
|
||||
|
||||
def syscall_handler(num: t.CUInt64T, arg1: t.CUInt64T, arg2: t.CUInt64T, arg3: t.CUInt64T, arg4: t.CUInt64T, arg5: t.CUInt64T, arg6: t.CUInt64T) -> t.CExport | t.CUInt64T:
|
||||
n: t.CInt = t.CInt(num)
|
||||
def syscall_handler(num: uint64, arg1: uint64, arg2: uint64, arg3: uint64, arg4: uint64, arg5: uint64, arg6: uint64) -> t.CExport | uint64:
|
||||
n: int = int(num)
|
||||
if n == CREATE_WINDOW:
|
||||
title_ptr: t.CVoid | t.CPtr = t.CVoid(arg5, t.CPtr)
|
||||
return t.CUInt64T(CREATE_WINDOW(t.CInt(arg1), t.CInt(arg2), t.CInt(arg3), t.CInt(arg4), title_ptr, t.CInt(arg6)))
|
||||
title_ptr: t.CPtr = t.CVoid(arg5, t.CPtr)
|
||||
return uint64(CREATE_WINDOW(int(arg1), int(arg2), int(arg3), int(arg4), title_ptr, int(arg6)))
|
||||
elif n == DRAW_TEXT:
|
||||
text_ptr: t.CVoid | t.CPtr = t.CVoid(arg4, t.CPtr)
|
||||
return t.CUInt64T(DRAW_TEXT(t.CInt(arg1), t.CInt(arg2), t.CInt(arg3), text_ptr, t.CUInt32T(arg5)))
|
||||
text_ptr: t.CPtr = t.CVoid(arg4, t.CPtr)
|
||||
return uint64(DRAW_TEXT(int(arg1), int(arg2), int(arg3), text_ptr, uint32(arg5)))
|
||||
elif n == EXIT:
|
||||
return t.CUInt64T(EXIT(t.CInt(arg1)))
|
||||
return uint64(EXIT(int(arg1)))
|
||||
elif n == OPEN:
|
||||
path_ptr: t.CVoid | t.CPtr = t.CVoid(arg1, t.CPtr)
|
||||
return t.CUInt64T(OPEN(path_ptr, t.CUInt32T(arg2)))
|
||||
path_ptr: t.CPtr = t.CVoid(arg1, t.CPtr)
|
||||
return uint64(OPEN(path_ptr, uint32(arg2)))
|
||||
elif n == CLOSE:
|
||||
return t.CUInt64T(CLOSE(t.CInt(arg1)))
|
||||
return uint64(CLOSE(int(arg1)))
|
||||
elif n == READ:
|
||||
buf_ptr: t.CVoid | t.CPtr = t.CVoid(arg2, t.CPtr)
|
||||
return t.CUInt64T(READ(t.CInt(arg1), buf_ptr, t.CUInt32T(arg3)))
|
||||
buf_ptr: t.CPtr = t.CVoid(arg2, t.CPtr)
|
||||
return uint64(READ(int(arg1), buf_ptr, uint32(arg3)))
|
||||
elif n == WRITE:
|
||||
buf_ptr: t.CVoid | t.CPtr = t.CVoid(arg2, t.CPtr)
|
||||
return t.CUInt64T(WRITE(t.CInt(arg1), buf_ptr, t.CUInt32T(arg3)))
|
||||
buf_ptr: t.CPtr = t.CVoid(arg2, t.CPtr)
|
||||
return uint64(WRITE(int(arg1), buf_ptr, uint32(arg3)))
|
||||
elif n == SEEK:
|
||||
return t.CUInt64T(SEEK(t.CInt(arg1), t.CUInt32T(arg2)))
|
||||
return uint64(SEEK(int(arg1), uint32(arg2)))
|
||||
elif n == TELL:
|
||||
return t.CUInt64T(TELL(t.CInt(arg1)))
|
||||
return uint64(TELL(int(arg1)))
|
||||
elif n == SIZE:
|
||||
return t.CUInt64T(fsize(t.CInt(arg1)))
|
||||
return uint64(fsize(int(arg1)))
|
||||
elif n == MKDIR:
|
||||
path_ptr: t.CVoid | t.CPtr = t.CVoid(arg1, t.CPtr)
|
||||
return t.CUInt64T(MKDIR(path_ptr))
|
||||
path_ptr: t.CPtr = t.CVoid(arg1, t.CPtr)
|
||||
return uint64(MKDIR(path_ptr))
|
||||
elif n == REMOVE:
|
||||
path_ptr: t.CVoid | t.CPtr = t.CVoid(arg1, t.CPtr)
|
||||
return t.CUInt64T(REMOVE(path_ptr))
|
||||
path_ptr: t.CPtr = t.CVoid(arg1, t.CPtr)
|
||||
return uint64(REMOVE(path_ptr))
|
||||
elif n == OPENDIR:
|
||||
path_ptr: t.CVoid | t.CPtr = t.CVoid(arg1, t.CPtr)
|
||||
return t.CUInt64T(OPENdir(path_ptr))
|
||||
path_ptr: t.CPtr = t.CVoid(arg1, t.CPtr)
|
||||
return uint64(OPENdir(path_ptr))
|
||||
elif n == READDIR:
|
||||
info_ptr: t.CVoid | t.CPtr = t.CVoid(arg2, t.CPtr)
|
||||
return t.CUInt64T(READdir(t.CInt(arg1), info_ptr))
|
||||
info_ptr: t.CPtr = t.CVoid(arg2, t.CPtr)
|
||||
return uint64(READdir(int(arg1), info_ptr))
|
||||
elif n == CLOSEDIR:
|
||||
return t.CUInt64T(CLOSEdir(t.CInt(arg1)))
|
||||
return uint64(CLOSEdir(int(arg1)))
|
||||
elif n == STAT:
|
||||
path_ptr: t.CVoid | t.CPtr = t.CVoid(arg1, t.CPtr)
|
||||
info_ptr: t.CVoid | t.CPtr = t.CVoid(arg2, t.CPtr)
|
||||
return t.CUInt64T(STAT(path_ptr, info_ptr))
|
||||
path_ptr: t.CPtr = t.CVoid(arg1, t.CPtr)
|
||||
info_ptr: t.CPtr = t.CVoid(arg2, t.CPtr)
|
||||
return uint64(STAT(path_ptr, info_ptr))
|
||||
elif n == WAIT_WINDOW:
|
||||
if t.CInt(arg2) == 1:
|
||||
return t.CUInt64T(desktop.is_active(t.CInt(arg1)))
|
||||
elif t.CInt(arg2) == 2:
|
||||
if int(arg2) == 1:
|
||||
return uint64(desktop.is_active(int(arg1)))
|
||||
elif int(arg2) == 2:
|
||||
sched.Scheduler.try_reschedule()
|
||||
return 0
|
||||
return t.CUInt64T(WAIT_WINDOW(t.CInt(arg1)))
|
||||
return uint64(WAIT_WINDOW(int(arg1)))
|
||||
elif n == SERIAL_PUTS:
|
||||
str_ptr_sp: t.CVoid | t.CPtr = t.CVoid(arg1, t.CPtr)
|
||||
return t.CUInt64T(SERIAL_PUTS(str_ptr_sp))
|
||||
str_ptr_sp: t.CPtr = t.CVoid(arg1, t.CPtr)
|
||||
return uint64(SERIAL_PUTS(str_ptr_sp))
|
||||
elif n == LOAD_SO:
|
||||
path_ptr_so: t.CVoid | t.CPtr = t.CVoid(arg1, t.CPtr)
|
||||
path_ptr_so: t.CPtr = t.CVoid(arg1, t.CPtr)
|
||||
return LOAD_SO(path_ptr_so)
|
||||
elif n == SO_CALL1:
|
||||
sym_ptr: t.CVoid | t.CPtr = t.CVoid(arg1, t.CPtr)
|
||||
return t.CUInt64T(SO_CALL1(sym_ptr, t.CPtr(arg2)))
|
||||
sym_ptr: t.CPtr = t.CVoid(arg1, t.CPtr)
|
||||
return uint64(SO_CALL1(sym_ptr, t.CPtr(arg2)))
|
||||
elif n == GET_WINBUF:
|
||||
return GET_WINBUF(t.CInt(arg1))
|
||||
return GET_WINBUF(int(arg1))
|
||||
elif n == WIN_FLUSH:
|
||||
return t.CUInt64T(WIN_FLUSH(t.CInt(arg1)))
|
||||
return uint64(WIN_FLUSH(int(arg1)))
|
||||
elif n == POLL_EVENT:
|
||||
buf_ptr_ev: t.CVoid | t.CPtr = t.CVoid(arg1, t.CPtr)
|
||||
caller_pid_ev: t.CInt = process.current()
|
||||
return t.CUInt64T(desktop.poll_event(buf_ptr_ev, caller_pid_ev))
|
||||
buf_ptr_ev: t.CPtr = t.CVoid(arg1, t.CPtr)
|
||||
caller_pid_ev: int = process.current()
|
||||
return uint64(desktop.poll_event(buf_ptr_ev, caller_pid_ev))
|
||||
elif n == SET_CURSOR:
|
||||
desktop.set_cursor_type(t.CInt(arg1), t.CInt(arg2))
|
||||
desktop.set_cursor_type(int(arg1), int(arg2))
|
||||
return 0
|
||||
elif n == YIELD:
|
||||
sched.Scheduler.try_reschedule()
|
||||
return 0
|
||||
elif n == SET_TITLE:
|
||||
title_ptr_st: t.CVoid | t.CPtr = t.CVoid(arg2, t.CPtr)
|
||||
return t.CUInt64T(desktop.set_title(t.CInt(arg1), title_ptr_st))
|
||||
title_ptr_st: t.CPtr = t.CVoid(arg2, t.CPtr)
|
||||
return uint64(desktop.set_title(int(arg1), title_ptr_st))
|
||||
elif n == SET_GEOMETRY:
|
||||
return t.CUInt64T(desktop.set_geometry(t.CInt(arg1), t.CInt(arg2), t.CInt(arg3), t.CInt(arg4), t.CInt(arg5)))
|
||||
return uint64(desktop.set_geometry(int(arg1), int(arg2), int(arg3), int(arg4), int(arg5)))
|
||||
elif n == SET_RESIZABLE:
|
||||
return t.CUInt64T(desktop.set_resizable(t.CInt(arg1), t.CInt(arg2), t.CInt(arg3)))
|
||||
return uint64(desktop.set_resizable(int(arg1), int(arg2), int(arg3)))
|
||||
elif n == GET_WIN_SIZE:
|
||||
return t.CUInt64T(desktop.get_size(t.CInt(arg1)))
|
||||
return uint64(desktop.get_size(int(arg1)))
|
||||
elif n == SPAWN:
|
||||
path_ptr_sp: t.CVoid | t.CPtr = t.CVoid(arg1, t.CPtr)
|
||||
return t.CUInt64T(SPAWN(path_ptr_sp, t.CInt(arg2)))
|
||||
path_ptr_sp: t.CPtr = t.CVoid(arg1, t.CPtr)
|
||||
return uint64(SPAWN(path_ptr_sp, int(arg2)))
|
||||
elif n == MMAP:
|
||||
return MMAP(arg1)
|
||||
elif n == MUNMAP:
|
||||
return t.CUInt64T(MUNMAP(arg1, arg2))
|
||||
return uint64(MUNMAP(arg1, arg2))
|
||||
elif n == THREAD_CREATE:
|
||||
func_ptr: t.CVoid | t.CPtr = t.CVoid(arg1, t.CPtr)
|
||||
arg_ptr: t.CVoid | t.CPtr = t.CVoid(arg2, t.CPtr)
|
||||
cur_pid: t.CInt = process.current()
|
||||
func_ptr: t.CPtr = t.CVoid(arg1, t.CPtr)
|
||||
arg_ptr: t.CPtr = t.CVoid(arg2, t.CPtr)
|
||||
cur_pid: int = process.current()
|
||||
th: sched.Thread | t.CPtr = sched.Scheduler.create_thread(func_ptr, arg_ptr, cur_pid)
|
||||
if th is None: return t.CUInt64T(0xFFFFFFFFFFFFFFFF)
|
||||
if th is None: return uint64(0xFFFFFFFFFFFFFFFF)
|
||||
p: process.Process | t.CPtr = process.ProcessManager.get_process(cur_pid)
|
||||
if p:
|
||||
p.addThread(th.tid)
|
||||
return t.CUInt64T(th.tid)
|
||||
return uint64(th.tid)
|
||||
return 0
|
||||
|
||||
def init():
|
||||
efer: t.CUInt64T = rdmsr(IA32_EFER)
|
||||
efer: uint64 = rdmsr(IA32_EFER)
|
||||
efer = efer | 1
|
||||
wrmsr(IA32_EFER, efer)
|
||||
star_val: t.CUInt64T = (t.CUInt64T(0x08) << 32) | (t.CUInt64T(0x1B) << 48)
|
||||
star_val: uint64 = (uint64(0x08) << 32) | (uint64(0x1B) << 48)
|
||||
wrmsr(IA32_STAR, star_val)
|
||||
wrmsr(IA32_LSTAR, t.CUInt64T(syscall_entry))
|
||||
wrmsr(IA32_LSTAR, uint64(syscall_entry))
|
||||
wrmsr(IA32_FMASK, 0x200)
|
||||
serial.puts("[syscall] MSR init done\n")
|
||||
+44
-44
@@ -32,8 +32,8 @@ import t, c
|
||||
import asm
|
||||
|
||||
|
||||
kbd_tid: t.CInt = -1
|
||||
mse_tid: t.CInt = -1
|
||||
kbd_tid: int = -1
|
||||
mse_tid: int = -1
|
||||
|
||||
BootInfo: bootinfo.bootinfo | t.CPtr
|
||||
|
||||
@@ -61,7 +61,7 @@ class ViperKernel:
|
||||
# Set IA32_KERNEL_GS_BASE = &_per_cpu so swapgs in ISR/syscall works.
|
||||
# _CPUObject is never instantiated, so __init_tss__ never runs;
|
||||
# without this, GS base stays 0 and gs:[0] writes hit null -> triple fault.
|
||||
cpu.msr_write(cpu.IA32_KERNEL_GS_BASE, t.CUInt64T(c.Addr(cpu._per_cpu)))
|
||||
cpu.msr_write(cpu.IA32_KERNEL_GS_BASE, uint64(c.Addr(cpu._per_cpu)))
|
||||
serial.puts("[main] gdt init done\n")
|
||||
intr.idt.init()
|
||||
syscall.init()
|
||||
@@ -84,12 +84,12 @@ class ViperKernel:
|
||||
serial.puts("[main] apic init done\n")
|
||||
|
||||
# [DBG] 综合诊断:判定 LAPIC MMIO 是否真正可访问/可写(用后移除)
|
||||
_dbg_base: t.CUInt64T = apic.get_base()
|
||||
_dbg_ver: t.CUInt32T = apic.read(0x030) # LAPIC_VERSION:真 LAPIC 应为 0x50014
|
||||
_dbg_svr: t.CUInt32T = apic.read(0x0F0) # LAPIC_SVR:init 已写 0x1FF
|
||||
_dbg_base: uint64 = apic.get_base()
|
||||
_dbg_ver: uint32 = apic.read(0x030) # LAPIC_VERSION:真 LAPIC 应为 0x50014
|
||||
_dbg_svr: uint32 = apic.read(0x0F0) # LAPIC_SVR:init 已写 0x1FF
|
||||
apic.write(0x350, 0x700) # 再次写 LINT0,验证写粘性
|
||||
_dbg_lint0: t.CUInt32T = apic.read(0x350)
|
||||
_dbg_feat: t.CUInt32T = cpu.detect_features_static()
|
||||
_dbg_lint0: uint32 = apic.read(0x350)
|
||||
_dbg_feat: uint32 = cpu.detect_features_static()
|
||||
_dbg_buf: t.CArray[t.CChar, 160]
|
||||
viperlib.snprintf(c.Addr(_dbg_buf), 160,
|
||||
"[DBG] base=0x%lx ver=0x%x svr=0x%x lint0=0x%x feat=0x%x apic=%d\n",
|
||||
@@ -98,9 +98,9 @@ class ViperKernel:
|
||||
serial.puts(c.Addr(_dbg_buf))
|
||||
|
||||
# [DBG] 读回 IDT 门 32,验证 isr32 分发地址是否正确安装(用后移除)
|
||||
_g32: t.CUInt64T = (t.CUInt64T(intr.idt.idt[32].base_low) |
|
||||
(t.CUInt64T(intr.idt.idt[32].base_middle) << 16) |
|
||||
(t.CUInt64T(intr.idt.idt[32].base_high) << 32))
|
||||
_g32: uint64 = (uint64(intr.idt.idt[32].base_low) |
|
||||
(uint64(intr.idt.idt[32].base_middle) << 16) |
|
||||
(uint64(intr.idt.idt[32].base_high) << 32))
|
||||
_g32buf: t.CArray[t.CChar, 96]
|
||||
viperlib.snprintf(c.Addr(_g32buf), 96, "[DBG] idt32 base=0x%lx sel=0x%x type=0x%x\n",
|
||||
_g32, intr.idt.idt[32].selector, intr.idt.idt[32].type_attr)
|
||||
@@ -118,7 +118,7 @@ class ViperKernel:
|
||||
# [DBG] 读 PIC1 ISR:bit0 置位说明 PIT IRQ0 已到达 PIC 并被响应(用后移除)
|
||||
asm.outb(0x20, 0x0B) # OCW3 读 ISR
|
||||
asm.io_wait()
|
||||
_pic_isr: t.CUInt8T = asm.inb(0x20)
|
||||
_pic_isr: uint8 = asm.inb(0x20)
|
||||
_isrbuf: t.CArray[t.CChar, 48]
|
||||
viperlib.snprintf(c.Addr(_isrbuf), 48, "[DBG] pic_isr=0x%x\n", _pic_isr)
|
||||
serial.puts(c.Addr(_isrbuf))
|
||||
@@ -127,7 +127,7 @@ class ViperKernel:
|
||||
serial.puts("[main] msleep done\n")
|
||||
rtc.rtc_init()
|
||||
serial.puts("[main] rtc init done\n")
|
||||
ncpu: t.CUInt32T = apic.get_cpu_count()
|
||||
ncpu: uint32 = apic.get_cpu_count()
|
||||
ncpu_cr: t.CArray[t.CChar, 32]
|
||||
viperlib.snprintf(c.Addr(ncpu_cr), 32, "[main] cpu_count=%u\n", ncpu)
|
||||
serial.puts(ncpu_cr)
|
||||
@@ -135,26 +135,26 @@ class ViperKernel:
|
||||
apic.start_aps()
|
||||
serial.puts("[main] kernel init done\n")
|
||||
|
||||
fb: t.CVoid | t.CPtr = t.CPtr(BootInfo.framebuffer_addr)
|
||||
width: t.CUInt64T = BootInfo.framebuffer_width
|
||||
height: t.CUInt64T = BootInfo.framebuffer_height
|
||||
pitch: t.CUInt64T = BootInfo.framebuffer_pitch
|
||||
fb_format: t.CUInt64T = BootInfo.framebuffer_format
|
||||
fb_size: t.CUInt64T = BootInfo.framebuffer_size
|
||||
fb: t.CPtr = t.CPtr(BootInfo.framebuffer_addr)
|
||||
width: uint64 = BootInfo.framebuffer_width
|
||||
height: uint64 = BootInfo.framebuffer_height
|
||||
pitch: uint64 = BootInfo.framebuffer_pitch
|
||||
fb_format: uint64 = BootInfo.framebuffer_format
|
||||
fb_size: uint64 = BootInfo.framebuffer_size
|
||||
# [DBG] 打印 BootInfo 指针与 memmap 原始字段,定位全 0 根因(用后移除)
|
||||
_dbbuf: t.CArray[t.CChar, 140]
|
||||
viperlib.snprintf(c.Addr(_dbbuf), 140, "[main] BootInfo=0x%lx mmap=0x%lx mmsz=%lu mmd=%lu fb=0x%lx\n",
|
||||
t.CUInt64T(BootInfo), BootInfo.MemmapAddr, BootInfo.MemmapSize,
|
||||
uint64(BootInfo), BootInfo.MemmapAddr, BootInfo.MemmapSize,
|
||||
BootInfo.MemmapDescSize, BootInfo.framebuffer_addr)
|
||||
serial.puts(c.Addr(_dbbuf))
|
||||
# [DBG] 转储 BootInfo 地址处原始 88 字节(用后移除)
|
||||
_dbraw: t.CArray[t.CChar, 16]
|
||||
_dbi: t.CInt = 0
|
||||
_dbi: int = 0
|
||||
while _dbi < 88:
|
||||
if (_dbi % 16) == 0:
|
||||
viperlib.snprintf(c.Addr(_dbraw), 16, "\n[DB] %04x:", _dbi)
|
||||
serial.puts(c.Addr(_dbraw))
|
||||
_dbv: t.CUInt8T = c.Deref(t.CUInt8T(t.CUInt64T(BootInfo) + t.CUInt64T(_dbi), t.CPtr))
|
||||
_dbv: uint8 = c.Deref(uint8(uint64(BootInfo) + uint64(_dbi), t.CPtr))
|
||||
viperlib.snprintf(c.Addr(_dbraw), 16, " %02x", _dbv)
|
||||
serial.puts(c.Addr(_dbraw))
|
||||
_dbi += 1
|
||||
@@ -162,20 +162,20 @@ class ViperKernel:
|
||||
|
||||
if BootInfo is not None:
|
||||
paging.init(BootInfo.MemmapAddr, BootInfo.MemmapSize)
|
||||
fb_pages: t.CUInt64T = (fb_size + t.CUInt64T(0xFFF)) >> t.CUInt64T(12)
|
||||
fpi: t.CUInt64T = 0
|
||||
fb_pages: uint64 = (fb_size + uint64(0xFFF)) >> uint64(12)
|
||||
fpi: uint64 = 0
|
||||
while fpi < fb_pages:
|
||||
fva: t.CUInt64T = t.CUInt64T(fb) + fpi * t.CUInt64T(0x1000)
|
||||
fva: uint64 = uint64(fb) + fpi * uint64(0x1000)
|
||||
paging.MapPage(fva, fva, paging.PTE_WRITABLE | paging.PTE_PCD)
|
||||
fpi += 1
|
||||
mm.init(BootInfo.MemmapAddr, BootInfo.MemmapSize, BootInfo.MemmapDescSize, BootInfo.framebuffer_addr, fb_size)
|
||||
pt_pool_buf: t.CVoid | t.CPtr = mm.malloc(t.CUInt64T(513) * t.CUInt64T(4096))
|
||||
paging.init_pool(pt_pool_buf, t.CUInt64T(513) * t.CUInt64T(4096))
|
||||
pt_pool_buf: t.CPtr = mm.malloc(uint64(513) * uint64(4096))
|
||||
paging.init_pool(pt_pool_buf, uint64(513) * uint64(4096))
|
||||
else:
|
||||
paging.init(0, 0)
|
||||
mm.init(0, 0, 0, 0, 0)
|
||||
pt_pool_buf2: t.CVoid | t.CPtr = mm.malloc(t.CUInt64T(513) * t.CUInt64T(4096))
|
||||
paging.init_pool(pt_pool_buf2, t.CUInt64T(513) * t.CUInt64T(4096))
|
||||
pt_pool_buf2: t.CPtr = mm.malloc(uint64(513) * uint64(4096))
|
||||
paging.init_pool(pt_pool_buf2, uint64(513) * uint64(4096))
|
||||
serial.puts("[main] paging and mm init done\n")
|
||||
# 把 .rodata(字符串常量/vtable)映射只读 + CR0.WP=1:
|
||||
# 越界写立即 #PF 暴露 cr2/rip(此前静默破坏格式串/路径/符号名 → P2/P3/P4/P5 连锁)
|
||||
@@ -192,26 +192,26 @@ class ViperKernel:
|
||||
serial.puts("[main] ide init done\n")
|
||||
|
||||
serial.puts("[main] initializing FAT32 filesystem\n")
|
||||
scan_res: t.CInt = fat32.scan_drives()
|
||||
ndrives: t.CInt = fat32.get_drive_count()
|
||||
scan_res: int = fat32.scan_drives()
|
||||
ndrives: int = fat32.get_drive_count()
|
||||
ndrives_cr: t.CArray[t.CChar, 64]
|
||||
viperlib.snprintf(c.Addr(ndrives_cr), 64, "[fat32] scan_res=%d found %d drives\n", scan_res, ndrives)
|
||||
serial.puts(ndrives_cr)
|
||||
|
||||
if ndrives > 0:
|
||||
mount_res: t.CInt = fat32.mount()
|
||||
mount_res: int = fat32.mount()
|
||||
if mount_res == 0:
|
||||
dp: fat32_types.dirobj
|
||||
res: t.CInt = fat32.opendir("/", c.Addr(dp))
|
||||
res: int = fat32.opendir("/", c.Addr(dp))
|
||||
if res == 0:
|
||||
serial.puts("[fat32] listing 0:/\n")
|
||||
count: t.CInt = 0
|
||||
count: int = 0
|
||||
while count < 20:
|
||||
info: fat32_types.fileinfo
|
||||
res2: t.CInt = fat32.readdir(c.Addr(dp), c.Addr(info))
|
||||
res2: int = fat32.readdir(c.Addr(dp), c.Addr(info))
|
||||
if res2 != 0: break
|
||||
if info.fname[0] == 0: break
|
||||
is_dir: t.CInt = 1 if (info.attr & fat32_types.AM_DIR) else 0
|
||||
is_dir: int = 1 if (info.attr & fat32_types.AM_DIR) else 0
|
||||
entry_cr: t.CArray[t.CChar, 300]
|
||||
viperlib.snprintf(c.Addr(entry_cr), 300, " %s size=%lu dir=%d\n", c.Addr(info.fname[0]), info.file_size, is_dir)
|
||||
serial.puts(entry_cr)
|
||||
@@ -224,13 +224,13 @@ class ViperKernel:
|
||||
# Load ELF apps BEFORE running destructive FAT32 tests
|
||||
serial.puts("[main] loading ELF apps...\n")
|
||||
dp_apps: fat32_types.dirobj
|
||||
apps_res: t.CInt = fat32.opendir("/APPS", c.Addr(dp_apps))
|
||||
apps_res: int = fat32.opendir("/APPS", c.Addr(dp_apps))
|
||||
if apps_res == 0:
|
||||
serial.puts("[main] APPS dir listing:\n")
|
||||
ac: t.CInt = 0
|
||||
ac: int = 0
|
||||
while ac < 20:
|
||||
ai: fat32_types.fileinfo
|
||||
ar: t.CInt = fat32.readdir(c.Addr(dp_apps), c.Addr(ai))
|
||||
ar: int = fat32.readdir(c.Addr(dp_apps), c.Addr(ai))
|
||||
if ar != 0: break
|
||||
if ai.fname[0] == 0: break
|
||||
ae: t.CArray[t.CChar, 300]
|
||||
@@ -265,7 +265,7 @@ class ViperKernel:
|
||||
|
||||
serial.puts("[main] sched started\n")
|
||||
|
||||
fd: t.CInt = devfs.devfs_open("/dev/serial0", 0)
|
||||
fd: int = devfs.devfs_open("/dev/serial0", 0)
|
||||
buf: t.CArray[t.CChar, 64]
|
||||
string.memset(c.Addr(buf), 0, 64)
|
||||
devfs.devfs_write(fd, "hello from devfs!", 17)
|
||||
@@ -327,10 +327,10 @@ class ViperKernel:
|
||||
|
||||
serial.puts("[main] entering main loop\n")
|
||||
# sched.sched_dump()
|
||||
last_sec: t.CUInt32T = 0
|
||||
loop_cnt: t.CUInt32T = 0
|
||||
last_sec: uint32 = 0
|
||||
loop_cnt: uint32 = 0
|
||||
while True:
|
||||
cur_sec: t.CUInt32T = timer.timer_get_seconds()
|
||||
cur_sec: uint32 = timer.timer_get_seconds()
|
||||
if cur_sec != last_sec:
|
||||
last_sec = cur_sec
|
||||
#if cur_sec % 5 == 0:
|
||||
@@ -360,7 +360,7 @@ VKP: ViperKernel | t.CPtr
|
||||
# stackrealign:_start 由 bootloader jmp 进入(rsp≡0 mod 16),llc 按 call 约定
|
||||
# 假设入口 rsp≡8 → 帧偏 8 → 变参函数 movaps #GP。动态重对齐栈修复。
|
||||
@c.Attribute(t.attr.section(".text.startup"), t.attr.aligned(16), t.attr.stackrealign)
|
||||
def _start() -> t.CInt:
|
||||
def _start() -> int:
|
||||
global VKP, BootInfo
|
||||
saved_rdi: t.CUnsignedLong
|
||||
c.Asm(f"mov {c.AsmOut(saved_rdi, t.ASM_DESCR.OUTPUT_REG)}, rdi",
|
||||
|
||||
+179
-179
@@ -15,24 +15,24 @@ BLOCK_FREE: t.CDefine = 0 # 空闲
|
||||
BLOCK_USED: t.CDefine = 1 # 已使用
|
||||
|
||||
# 内存类型定义
|
||||
MEMORY_TYPE_AVAILABLE: t.CUInt64T = 7
|
||||
MEMORY_TYPE_RESERVED: t.CUInt64T = 0
|
||||
MEMORY_TYPE_LOADER_CODE: t.CUInt64T = 1
|
||||
MEMORY_TYPE_LOADER_DATA: t.CUInt64T = 2
|
||||
MEMORY_TYPE_BOOT_SERVICES_CODE: t.CUInt64T = 3
|
||||
MEMORY_TYPE_BOOT_SERVICES_DATA: t.CUInt64T = 4
|
||||
MEMORY_TYPE_RUNTIME_SERVICES_CODE: t.CUInt64T = 5
|
||||
MEMORY_TYPE_RUNTIME_SERVICES_DATA: t.CUInt64T = 6
|
||||
MEMORY_TYPE_ACPI_RECLAIMABLE: t.CUInt64T = 9
|
||||
MEMORY_TYPE_ACPI_NVS: t.CUInt64T = 10
|
||||
MEMORY_TYPE_BAD_MEMORY: t.CUInt64T = 8
|
||||
MEMORY_TYPE_AVAILABLE: uint64 = 7
|
||||
MEMORY_TYPE_RESERVED: uint64 = 0
|
||||
MEMORY_TYPE_LOADER_CODE: uint64 = 1
|
||||
MEMORY_TYPE_LOADER_DATA: uint64 = 2
|
||||
MEMORY_TYPE_BOOT_SERVICES_CODE: uint64 = 3
|
||||
MEMORY_TYPE_BOOT_SERVICES_DATA: uint64 = 4
|
||||
MEMORY_TYPE_RUNTIME_SERVICES_CODE: uint64 = 5
|
||||
MEMORY_TYPE_RUNTIME_SERVICES_DATA: uint64 = 6
|
||||
MEMORY_TYPE_ACPI_RECLAIMABLE: uint64 = 9
|
||||
MEMORY_TYPE_ACPI_NVS: uint64 = 10
|
||||
MEMORY_TYPE_BAD_MEMORY: uint64 = 8
|
||||
|
||||
# 内存区域结构
|
||||
class memory_region(t.CStruct):
|
||||
start: t.CUInt64T
|
||||
end: t.CUInt64T
|
||||
size: t.CUInt64T
|
||||
type: t.CUInt32T
|
||||
start: uint64
|
||||
end: uint64
|
||||
size: uint64
|
||||
type: uint32
|
||||
next: 'memory_region' | t.CPtr
|
||||
|
||||
# 全局内存区域链表
|
||||
@@ -40,20 +40,20 @@ memory_regions: t.CStatic | memory_region | t.CPtr = None
|
||||
|
||||
# 内存块结构
|
||||
class memory_block(t.CStruct):
|
||||
size: t.CUInt64T # 块大小
|
||||
state: t.CUInt8T # 块状态
|
||||
order: t.CUInt8T # 块阶数
|
||||
size: uint64 # 块大小
|
||||
state: uint8 # 块状态
|
||||
order: uint8 # 块阶数
|
||||
next: 'memory_block' | t.CPtr # 下一个块
|
||||
prev: 'memory_block' | t.CPtr # 上一个块
|
||||
|
||||
# 伙伴系统结构
|
||||
class __buddy_system(t.CStruct):
|
||||
free_lists: t.CArray[memory_block | t.CPtr, MAX_ORDER + 1]
|
||||
total_memory: t.CUInt64T # 总内存大小
|
||||
used_memory: t.CUInt64T # 已使用内存大小
|
||||
free_memory: t.CUInt64T # 空闲内存大小
|
||||
start_addr: t.CVoid | t.CPtr # 内存起始地址
|
||||
end_addr: t.CVoid | t.CPtr # 内存结束地址
|
||||
total_memory: uint64 # 总内存大小
|
||||
used_memory: uint64 # 已使用内存大小
|
||||
free_memory: uint64 # 空闲内存大小
|
||||
start_addr: t.CPtr # 内存起始地址
|
||||
end_addr: t.CPtr # 内存结束地址
|
||||
|
||||
|
||||
SLAB_MAGIC: t.CDefine = 0x534C4142
|
||||
@@ -61,34 +61,34 @@ SLAB_NUM_SIZES: t.CDefine = 6
|
||||
SLAB_THRESHOLD: t.CDefine = 1024
|
||||
|
||||
class slab_page(t.CStruct):
|
||||
magic: t.CUInt32T
|
||||
obj_size: t.CUInt16T
|
||||
free_count: t.CUInt16T
|
||||
data_offset: t.CUInt16T
|
||||
total_objs: t.CUInt16T
|
||||
free_head: t.CVoid | t.CPtr
|
||||
magic: uint32
|
||||
obj_size: uint16
|
||||
free_count: uint16
|
||||
data_offset: uint16
|
||||
total_objs: uint16
|
||||
free_head: t.CPtr
|
||||
block_ptr: memory_block | t.CPtr
|
||||
next: 'slab_page' | t.CPtr
|
||||
prev: 'slab_page' | t.CPtr
|
||||
|
||||
|
||||
# 4K对齐函数
|
||||
def align_4k(addr: t.CUInt64T) -> t.CUInt64T:
|
||||
def align_4k(addr: uint64) -> uint64:
|
||||
return (addr + 0xFFF) & ~0xFFF
|
||||
|
||||
# 计算阶数
|
||||
def get_order(size: t.CUInt64T) -> t.CStatic | t.CInt:
|
||||
order: t.CInt = 0
|
||||
def get_order(size: uint64) -> t.CStatic | int:
|
||||
order: int = 0
|
||||
while size > MIN_BLOCK_SIZE:
|
||||
size >>= 1
|
||||
order += 1
|
||||
return order
|
||||
|
||||
# 计算块大小
|
||||
def get_block_size(order: t.CInt) -> t.CStatic | t.CUInt64T:
|
||||
def get_block_size(order: int) -> t.CStatic | uint64:
|
||||
# 4096 << 20 = 4GB 超出 i32 范围 → 0x0 → 伙伴初始化无限循环(bs=0x0)。
|
||||
# 必须用 64 位移位(4096<<20 = 4294967296)。
|
||||
return t.CUInt64T(MIN_BLOCK_SIZE) << t.CUInt64T(order)
|
||||
return uint64(MIN_BLOCK_SIZE) << uint64(order)
|
||||
|
||||
|
||||
@t.Object
|
||||
@@ -96,27 +96,27 @@ class _BuddySystemObject:
|
||||
# 全局伙伴系统实例
|
||||
buddy: __buddy_system
|
||||
# 初始化伙伴系统
|
||||
def __init__(self, start_addr: t.CVoid | t.CPtr, size: t.CUInt64T):
|
||||
def __init__(self, start_addr: t.CPtr, size: uint64):
|
||||
for i in range(MAX_ORDER + 1):
|
||||
self.buddy.free_lists[i] = None
|
||||
self.buddy.total_memory = size
|
||||
self.buddy.used_memory = 0
|
||||
self.buddy.free_memory = size
|
||||
self.buddy.start_addr = start_addr
|
||||
self.buddy.end_addr = t.CVoid(t.CUInt64T(start_addr) + size, t.CPtr)
|
||||
remaining: t.CUInt64T = size
|
||||
cur_addr: t.CUInt64T = t.CUInt64T(start_addr)
|
||||
self.buddy.end_addr = t.CVoid(uint64(start_addr) + size, t.CPtr)
|
||||
remaining: uint64 = size
|
||||
cur_addr: uint64 = uint64(start_addr)
|
||||
# [DBG] buddy 初始化循环进度(用后移除)
|
||||
import drivers.serial.uart.serial as _sdbg
|
||||
_dbp: t.CArray[t.CChar, 80]
|
||||
_itc: t.CInt = 0
|
||||
_itc: int = 0
|
||||
while remaining >= MIN_BLOCK_SIZE:
|
||||
order: t.CInt = 0
|
||||
tmp: t.CUInt64T = remaining
|
||||
order: int = 0
|
||||
tmp: uint64 = remaining
|
||||
while tmp > MIN_BLOCK_SIZE:
|
||||
tmp >>= 1
|
||||
order += 1
|
||||
block_size: t.CUInt64T = get_block_size(order)
|
||||
block_size: uint64 = get_block_size(order)
|
||||
while block_size > remaining and order > 0:
|
||||
order -= 1
|
||||
block_size = get_block_size(order)
|
||||
@@ -144,23 +144,23 @@ class _BuddySystemObject:
|
||||
import drivers.serial.uart.serial as serial
|
||||
_dmsg: t.CArray[t.CChar, 40]
|
||||
serial.puts("[mm] buddy init:")
|
||||
_di: t.CInt = 0
|
||||
_di: int = 0
|
||||
while _di <= MAX_ORDER:
|
||||
if self.buddy.free_lists[_di]:
|
||||
viperlib.snprintf(c.Addr(_dmsg), 40, " [%d]=0x%lx", _di, t.CUInt64T(self.buddy.free_lists[_di]))
|
||||
viperlib.snprintf(c.Addr(_dmsg), 40, " [%d]=0x%lx", _di, uint64(self.buddy.free_lists[_di]))
|
||||
serial.puts(_dmsg)
|
||||
_di += 1
|
||||
serial.puts("\n")
|
||||
|
||||
# 分割内存块
|
||||
def split_block(self, block: memory_block | t.CPtr, target_order: t.CInt) -> memory_block | t.CPtr:
|
||||
current_order: t.CInt = block.order
|
||||
def split_block(self, block: memory_block | t.CPtr, target_order: int) -> memory_block | t.CPtr:
|
||||
current_order: int = block.order
|
||||
# 从当前阶数向下分割,直到达到目标阶数
|
||||
while current_order > target_order:
|
||||
current_order -= 1
|
||||
new_block_size: t.CUInt64T = get_block_size(current_order)
|
||||
new_block_size: uint64 = get_block_size(current_order)
|
||||
# 创建新块
|
||||
new_block: memory_block | t.CPtr = t.CPtr(t.CUInt64T(block) + new_block_size)
|
||||
new_block: memory_block | t.CPtr = t.CPtr(uint64(block) + new_block_size)
|
||||
new_block.size = new_block_size
|
||||
new_block.state = BLOCK_FREE
|
||||
new_block.order = current_order
|
||||
@@ -179,13 +179,13 @@ class _BuddySystemObject:
|
||||
|
||||
# 合并内存块
|
||||
def merge_blocks(self, block: memory_block | t.CPtr) -> t.CStatic | memory_block | t.CPtr:
|
||||
order: t.CInt = block.order
|
||||
order: int = block.order
|
||||
while order < MAX_ORDER:
|
||||
block_size: t.CUInt64T = get_block_size(order)
|
||||
block_addr: t.CUInt64T = t.CUInt64T(block) - t.CUInt64T(self.buddy.start_addr)
|
||||
buddy_addr: t.CUInt64T = block_addr ^ block_size
|
||||
block_size: uint64 = get_block_size(order)
|
||||
block_addr: uint64 = uint64(block) - uint64(self.buddy.start_addr)
|
||||
buddy_addr: uint64 = block_addr ^ block_size
|
||||
# 计算伙伴块地址
|
||||
buddy: memory_block | t.CPtr = t.CPtr(t.CUInt64T(self.buddy.start_addr) + buddy_addr)
|
||||
buddy: memory_block | t.CPtr = t.CPtr(uint64(self.buddy.start_addr) + buddy_addr)
|
||||
# 检查伙伴块是否存在且空闲
|
||||
if buddy >= t.CType(self.buddy.end_addr, memory_block, t.CPtr):
|
||||
break # 伙伴块超出内存范围
|
||||
@@ -205,12 +205,12 @@ class _BuddySystemObject:
|
||||
return block
|
||||
|
||||
# 分配内存块
|
||||
def allocate_block(self, size: t.CUInt64T) -> t.CStatic | memory_block | t.CPtr:
|
||||
def allocate_block(self, size: uint64) -> t.CStatic | memory_block | t.CPtr:
|
||||
# 计算所需阶数
|
||||
order: t.CInt = get_order(size)
|
||||
order: int = get_order(size)
|
||||
if order > MAX_ORDER: return None # 所需块大小超过最大限制
|
||||
# 查找合适的空闲块
|
||||
found_order: t.CInt = -1
|
||||
found_order: int = -1
|
||||
for i in range(order, MAX_ORDER + 1):
|
||||
if self.buddy.free_lists[i]:
|
||||
found_order = i
|
||||
@@ -222,11 +222,11 @@ class _BuddySystemObject:
|
||||
viperlib.snprintf(c.Addr(_dba), 120, "[mm] alloc FAIL size=%lu order=%d\n", size, order)
|
||||
serial.puts(_dba)
|
||||
_dbf: t.CArray[t.CChar, 200]
|
||||
_fi: t.CInt = 0
|
||||
_fo: t.CInt = 0
|
||||
_fi: int = 0
|
||||
_fo: int = 0
|
||||
while _fi <= MAX_ORDER:
|
||||
if self.buddy.free_lists[_fi]:
|
||||
_fs: t.CInt = viperlib.snprintf(c.Addr(_dbf) + _fo, 200 - _fo, "[%d]=0x%lx ", _fi, t.CUInt64T(self.buddy.free_lists[_fi]))
|
||||
_fs: int = viperlib.snprintf(c.Addr(_dbf) + _fo, 200 - _fo, "[%d]=0x%lx ", _fi, uint64(self.buddy.free_lists[_fi]))
|
||||
_fo = _fo + _fs
|
||||
_fi += 1
|
||||
if _fo == 0:
|
||||
@@ -249,7 +249,7 @@ class _BuddySystemObject:
|
||||
# 更新内存统计
|
||||
self.buddy.used_memory += block.size
|
||||
self.buddy.free_memory -= block.size
|
||||
viperlib.snprintf(c.Addr(_dba), 120, "[mm] alloc OK size=%lu order=%d found=%d block=0x%lx\n", size, order, found_order, t.CUInt64T(block))
|
||||
viperlib.snprintf(c.Addr(_dba), 120, "[mm] alloc OK size=%lu order=%d found=%d block=0x%lx\n", size, order, found_order, uint64(block))
|
||||
serial.puts(_dba)
|
||||
return block
|
||||
|
||||
@@ -263,7 +263,7 @@ class _BuddySystemObject:
|
||||
# 尝试合并块
|
||||
block = self.merge_blocks(block)
|
||||
# 将块添加到对应阶数的空闲链表
|
||||
order: t.CInt = block.order
|
||||
order: int = block.order
|
||||
if order <= MAX_ORDER:
|
||||
block.next = self.buddy.free_lists[order]
|
||||
block.prev = None
|
||||
@@ -273,7 +273,7 @@ class _BuddySystemObject:
|
||||
BuddySystemObject: _BuddySystemObject
|
||||
|
||||
|
||||
def _slab_obj_size(size_class: t.CInt) -> t.CUInt16T:
|
||||
def _slab_obj_size(size_class: int) -> uint16:
|
||||
if size_class == 0: return 32
|
||||
if size_class == 1: return 64
|
||||
if size_class == 2: return 128
|
||||
@@ -281,7 +281,7 @@ def _slab_obj_size(size_class: t.CInt) -> t.CUInt16T:
|
||||
if size_class == 4: return 512
|
||||
return 1024
|
||||
|
||||
def _slab_size_class(size: t.CUInt64T) -> t.CInt:
|
||||
def _slab_size_class(size: uint64) -> int:
|
||||
if size <= 32: return 0
|
||||
if size <= 64: return 1
|
||||
if size <= 128: return 2
|
||||
@@ -290,31 +290,31 @@ def _slab_size_class(size: t.CUInt64T) -> t.CInt:
|
||||
if size <= 1024: return 5
|
||||
return -1
|
||||
|
||||
def _slab_read_ptr(addr: t.CVoid | t.CPtr) -> t.CVoid | t.CPtr:
|
||||
result: t.CVoid | t.CPtr
|
||||
def _slab_read_ptr(addr: t.CPtr) -> t.CPtr:
|
||||
result: t.CPtr
|
||||
c.Asm(f"""mov rax, [{c.AsmInp(addr, t.ASM_DESCR.REG_ANY)}]
|
||||
mov {c.AsmOut(result, t.ASM_DESCR.OUTPUT_REG)}, rax""",
|
||||
op=[t.ASM_DESCR.CLOBBER_MEMORY, t.ASM_DESCR.CLOBBER_RAX])
|
||||
return result
|
||||
|
||||
def _slab_write_ptr(addr: t.CVoid | t.CPtr, val: t.CVoid | t.CPtr):
|
||||
def _slab_write_ptr(addr: t.CPtr, val: t.CPtr):
|
||||
c.Asm(f"""mov rax, {c.AsmInp(val, t.ASM_DESCR.REG_ANY)}
|
||||
mov [{c.AsmInp(addr, t.ASM_DESCR.REG_ANY)}], rax""",
|
||||
op=[t.ASM_DESCR.CLOBBER_RAX, t.ASM_DESCR.CLOBBER_MEMORY])
|
||||
|
||||
def _slab_find_page(ptr: t.CVoid | t.CPtr) -> slab_page | t.CPtr:
|
||||
def _slab_find_page(ptr: t.CPtr) -> slab_page | t.CPtr:
|
||||
if ptr is None: return None
|
||||
hdr_off: t.CUInt64T = memory_block.__sizeof__()
|
||||
page_addr: t.CUInt64T = t.CUInt64T(ptr) & ~t.CUInt64T(0xFFF)
|
||||
hdr_off: uint64 = memory_block.__sizeof__()
|
||||
page_addr: uint64 = uint64(ptr) & ~uint64(0xFFF)
|
||||
page: slab_page | t.CPtr = t.CPtr(page_addr + hdr_off)
|
||||
if page.magic == SLAB_MAGIC:
|
||||
os: t.CUInt16T = page.obj_size
|
||||
os: uint16 = page.obj_size
|
||||
if os == 32 or os == 64 or os == 128 or os == 256 or os == 512 or os == 1024:
|
||||
return page
|
||||
page_addr2: t.CUInt64T = page_addr - 4096
|
||||
page_addr2: uint64 = page_addr - 4096
|
||||
page2: slab_page | t.CPtr = t.CPtr(page_addr2 + hdr_off)
|
||||
if page2.magic == SLAB_MAGIC:
|
||||
os2: t.CUInt16T = page2.obj_size
|
||||
os2: uint16 = page2.obj_size
|
||||
if os2 == 32 or os2 == 64 or os2 == 128 or os2 == 256 or os2 == 512 or os2 == 1024:
|
||||
return page2
|
||||
return None
|
||||
@@ -327,34 +327,34 @@ class _SlabAllocator:
|
||||
for i in range(SLAB_NUM_SIZES):
|
||||
self.caches[i] = None
|
||||
|
||||
def _create_page(self, size_class: t.CInt) -> slab_page | t.CPtr:
|
||||
obj_size: t.CUInt16T = _slab_obj_size(size_class)
|
||||
aligned_size: t.CUInt16T = t.CUInt16T((obj_size + 15) & ~15)
|
||||
def _create_page(self, size_class: int) -> slab_page | t.CPtr:
|
||||
obj_size: uint16 = _slab_obj_size(size_class)
|
||||
aligned_size: uint16 = uint16((obj_size + 15) & ~15)
|
||||
block: memory_block | t.CPtr = BuddySystemObject.allocate_block(4096 + memory_block.__sizeof__())
|
||||
if not block: return None
|
||||
hdr_off: t.CUInt64T = memory_block.__sizeof__()
|
||||
page: slab_page | t.CPtr = t.CPtr(t.CUInt64T(block) + hdr_off)
|
||||
hdr_off: uint64 = memory_block.__sizeof__()
|
||||
page: slab_page | t.CPtr = t.CPtr(uint64(block) + hdr_off)
|
||||
page.magic = SLAB_MAGIC
|
||||
page.obj_size = aligned_size
|
||||
d_off: t.CUInt16T = t.CUInt16T((hdr_off + slab_page.__sizeof__() + 15) & ~15)
|
||||
d_off: uint16 = uint16((hdr_off + slab_page.__sizeof__() + 15) & ~15)
|
||||
page.data_offset = d_off
|
||||
total: t.CUInt16T = t.CUInt16T((block.size - d_off) / aligned_size)
|
||||
total: uint16 = uint16((block.size - d_off) / aligned_size)
|
||||
page.total_objs = total
|
||||
page.free_count = total
|
||||
page.block_ptr = block
|
||||
page.next = None
|
||||
page.prev = None
|
||||
data_start: t.CUInt64T = t.CUInt64T(block) + d_off
|
||||
data_start: uint64 = uint64(block) + d_off
|
||||
page.free_head = t.CVoid(data_start, t.CPtr)
|
||||
for i in range(1, total):
|
||||
cur: t.CVoid | t.CPtr = t.CVoid(data_start + t.CUInt64T(i - 1) * aligned_size, t.CPtr)
|
||||
nxt: t.CVoid | t.CPtr = t.CVoid(data_start + t.CUInt64T(i) * aligned_size, t.CPtr)
|
||||
cur: t.CPtr = t.CVoid(data_start + uint64(i - 1) * aligned_size, t.CPtr)
|
||||
nxt: t.CPtr = t.CVoid(data_start + uint64(i) * aligned_size, t.CPtr)
|
||||
_slab_write_ptr(cur, nxt)
|
||||
last: t.CVoid | t.CPtr = t.CVoid(data_start + t.CUInt64T(total - 1) * aligned_size, t.CPtr)
|
||||
last: t.CPtr = t.CVoid(data_start + uint64(total - 1) * aligned_size, t.CPtr)
|
||||
_slab_write_ptr(last, t.CVoid(0, t.CPtr))
|
||||
return page
|
||||
|
||||
def alloc(self, size_class: t.CInt) -> t.CVoid | t.CPtr:
|
||||
def alloc(self, size_class: int) -> t.CPtr:
|
||||
page: slab_page | t.CPtr = self.caches[size_class]
|
||||
while page:
|
||||
if page.free_count > 0: break
|
||||
@@ -366,12 +366,12 @@ class _SlabAllocator:
|
||||
if self.caches[size_class]:
|
||||
self.caches[size_class].prev = page
|
||||
self.caches[size_class] = page
|
||||
obj: t.CVoid | t.CPtr = page.free_head
|
||||
obj: t.CPtr = page.free_head
|
||||
page.free_head = _slab_read_ptr(obj)
|
||||
page.free_count -= 1
|
||||
return obj
|
||||
|
||||
def free_obj(self, ptr: t.CVoid | t.CPtr, page: slab_page | t.CPtr):
|
||||
def free_obj(self, ptr: t.CPtr, page: slab_page | t.CPtr):
|
||||
_slab_write_ptr(ptr, page.free_head)
|
||||
page.free_head = ptr
|
||||
page.free_count += 1
|
||||
@@ -379,7 +379,7 @@ class _SlabAllocator:
|
||||
if page.prev:
|
||||
page.prev.next = page.next
|
||||
else:
|
||||
sc: t.CInt = _slab_size_class(page.obj_size)
|
||||
sc: int = _slab_size_class(page.obj_size)
|
||||
if sc >= 0:
|
||||
self.caches[sc] = page.next
|
||||
if page.next:
|
||||
@@ -391,99 +391,99 @@ SlabAllocator: _SlabAllocator
|
||||
|
||||
|
||||
# 内存分配函数
|
||||
def malloc(size: t.CUInt64T) -> t.CVoid | t.CPtr | t.CExport:
|
||||
def malloc(size: uint64) -> t.CPtr | t.CExport:
|
||||
if size == 0: return None
|
||||
if size <= SLAB_THRESHOLD:
|
||||
sc: t.CInt = _slab_size_class(size)
|
||||
sc: int = _slab_size_class(size)
|
||||
if sc >= 0:
|
||||
result: t.CVoid | t.CPtr = SlabAllocator.alloc(sc)
|
||||
result: t.CPtr = SlabAllocator.alloc(sc)
|
||||
return result
|
||||
hdr: t.CUInt64T = memory_block.__sizeof__()
|
||||
hdr: uint64 = memory_block.__sizeof__()
|
||||
if size >= 4096:
|
||||
total: t.CUInt64T = size + 4096
|
||||
total: uint64 = size + 4096
|
||||
total = align_4k(total)
|
||||
order: t.CInt = get_order(total)
|
||||
order: int = get_order(total)
|
||||
if order > MAX_ORDER: return None
|
||||
block: memory_block | t.CPtr = BuddySystemObject.allocate_block(total)
|
||||
import drivers.serial.uart.serial as serial
|
||||
_dbm: t.CArray[t.CChar, 120]
|
||||
viperlib.snprintf(c.Addr(_dbm), 120, "[mm] malloc buddy size=%lu block=0x%lx\n", size, t.CUInt64T(block))
|
||||
viperlib.snprintf(c.Addr(_dbm), 120, "[mm] malloc buddy size=%lu block=0x%lx\n", size, uint64(block))
|
||||
serial.puts(_dbm)
|
||||
if not block: return None
|
||||
user_ptr: t.CUInt64T = (t.CUInt64T(block) + hdr + 4095) & ~t.CUInt64T(4095)
|
||||
real_hdr: t.CUInt64T = user_ptr - 8
|
||||
user_ptr: uint64 = (uint64(block) + hdr + 4095) & ~uint64(4095)
|
||||
real_hdr: uint64 = user_ptr - 8
|
||||
c.Asm(f"""mov rax, {c.AsmInp(block, t.ASM_DESCR.REG_ANY)}
|
||||
mov [{c.AsmInp(t.CVoid(real_hdr, t.CPtr), t.ASM_DESCR.REG_ANY)}], rax""",
|
||||
op=[t.ASM_DESCR.CLOBBER_RAX, t.ASM_DESCR.CLOBBER_MEMORY])
|
||||
viperlib.snprintf(c.Addr(_dbm), 120, "[mm] malloc ret user_ptr=0x%lx\n", user_ptr)
|
||||
serial.puts(_dbm)
|
||||
return t.CVoid(user_ptr, t.CPtr)
|
||||
total2: t.CUInt64T = size + hdr
|
||||
total2: uint64 = size + hdr
|
||||
total2 = align_4k(total2)
|
||||
order2: t.CInt = get_order(total2)
|
||||
order2: int = get_order(total2)
|
||||
if order2 > MAX_ORDER: return None
|
||||
block2: memory_block | t.CPtr = BuddySystemObject.allocate_block(total2)
|
||||
if not block2: return None
|
||||
return t.CVoid(t.CUInt64T(block2) + hdr, t.CPtr)
|
||||
return t.CVoid(uint64(block2) + hdr, t.CPtr)
|
||||
|
||||
|
||||
def malloc_direct(size: t.CUInt64T) -> t.CVoid | t.CPtr | t.CExport:
|
||||
def malloc_direct(size: uint64) -> t.CPtr | t.CExport:
|
||||
if size == 0: return None
|
||||
hdr: t.CUInt64T = memory_block.__sizeof__()
|
||||
total: t.CUInt64T = size + hdr
|
||||
hdr: uint64 = memory_block.__sizeof__()
|
||||
total: uint64 = size + hdr
|
||||
total = align_4k(total)
|
||||
order: t.CInt = get_order(total)
|
||||
order: int = get_order(total)
|
||||
if order > MAX_ORDER: return None
|
||||
block: memory_block | t.CPtr = BuddySystemObject.allocate_block(total)
|
||||
if not block: return None
|
||||
return t.CVoid(t.CUInt64T(block) + hdr, t.CPtr)
|
||||
return t.CVoid(uint64(block) + hdr, t.CPtr)
|
||||
|
||||
|
||||
def free(ptr: t.CVoid | t.CPtr) -> t.CExport:
|
||||
def free(ptr: t.CPtr) -> t.CExport:
|
||||
if ptr is None: return
|
||||
sp: slab_page | t.CPtr = _slab_find_page(ptr)
|
||||
if sp:
|
||||
SlabAllocator.free_obj(ptr, sp)
|
||||
return
|
||||
if (t.CUInt64T(ptr) & 0xFFF) == 0:
|
||||
real_hdr: t.CUInt64T = t.CUInt64T(ptr) - 8
|
||||
if (uint64(ptr) & 0xFFF) == 0:
|
||||
real_hdr: uint64 = uint64(ptr) - 8
|
||||
block: memory_block | t.CPtr
|
||||
c.Asm(f"""mov rax, [{c.AsmInp(t.CVoid(real_hdr, t.CPtr), t.ASM_DESCR.REG_ANY)}]
|
||||
mov {c.AsmOut(block, t.ASM_DESCR.OUTPUT_REG)}, rax""",
|
||||
op=[t.ASM_DESCR.CLOBBER_MEMORY, t.ASM_DESCR.CLOBBER_RAX])
|
||||
BuddySystemObject.free_block(block)
|
||||
return
|
||||
block2: memory_block | t.CPtr = t.CPtr(t.CUInt64T(ptr) - memory_block.__sizeof__())
|
||||
block2: memory_block | t.CPtr = t.CPtr(uint64(ptr) - memory_block.__sizeof__())
|
||||
BuddySystemObject.free_block(block2)
|
||||
|
||||
def calloc(nmemb: t.CUInt64T, size: t.CUInt64T) -> t.CVoid | t.CPtr | t.CExport:
|
||||
total_size: t.CUInt64T = nmemb * size
|
||||
ptr: t.CVoid | t.CPtr = malloc(total_size)
|
||||
def calloc(nmemb: uint64, size: uint64) -> t.CPtr | t.CExport:
|
||||
total_size: uint64 = nmemb * size
|
||||
ptr: t.CPtr = malloc(total_size)
|
||||
if ptr:
|
||||
string.memset(ptr, 0, total_size)
|
||||
return ptr
|
||||
|
||||
def realloc(ptr: t.CVoid | t.CPtr, size: t.CUInt64T) -> t.CVoid | t.CPtr | t.CExport:
|
||||
def realloc(ptr: t.CPtr, size: uint64) -> t.CPtr | t.CExport:
|
||||
if ptr is None: return malloc(size)
|
||||
if size == 0:
|
||||
free(ptr)
|
||||
return None
|
||||
new_ptr: t.CVoid | t.CPtr = malloc(size)
|
||||
new_ptr: t.CPtr = malloc(size)
|
||||
if not new_ptr: return None
|
||||
sp: slab_page | t.CPtr = _slab_find_page(ptr)
|
||||
if sp:
|
||||
old_size: t.CUInt64T = sp.obj_size
|
||||
elif (t.CUInt64T(ptr) & 0xFFF) == 0:
|
||||
real_hdr_r: t.CUInt64T = t.CUInt64T(ptr) - 8
|
||||
old_size: uint64 = sp.obj_size
|
||||
elif (uint64(ptr) & 0xFFF) == 0:
|
||||
real_hdr_r: uint64 = uint64(ptr) - 8
|
||||
block_r: memory_block | t.CPtr
|
||||
c.Asm(f"""mov rax, [{c.AsmInp(t.CVoid(real_hdr_r, t.CPtr), t.ASM_DESCR.REG_ANY)}]
|
||||
mov {c.AsmOut(block_r, t.ASM_DESCR.OUTPUT_REG)}, rax""",
|
||||
op=[t.ASM_DESCR.CLOBBER_MEMORY, t.ASM_DESCR.CLOBBER_RAX])
|
||||
old_size = block_r.size - 4096
|
||||
else:
|
||||
block2: memory_block | t.CPtr = t.CPtr(t.CUInt64T(ptr) - memory_block.__sizeof__())
|
||||
block2: memory_block | t.CPtr = t.CPtr(uint64(ptr) - memory_block.__sizeof__())
|
||||
old_size = block2.size - memory_block.__sizeof__()
|
||||
copy_size: t.CUInt64T = old_size if old_size < size else size
|
||||
copy_size: uint64 = old_size if old_size < size else size
|
||||
string.memcpy(new_ptr, ptr, copy_size)
|
||||
free(ptr)
|
||||
return new_ptr
|
||||
@@ -500,7 +500,7 @@ def free_memory_regions() -> t.CStatic | t.CVoid:
|
||||
memory_regions = None
|
||||
|
||||
# 初始化内存管理系统
|
||||
def init(MemmapAddr: t.CUInt64T, MemmapSize: t.CUInt64T, MemmapDescSize: t.CUInt64T, FbAddr: t.CUInt64T = 0, FbSize: t.CUInt64T = 0):
|
||||
def init(MemmapAddr: uint64, MemmapSize: uint64, MemmapDescSize: uint64, FbAddr: uint64 = 0, FbSize: uint64 = 0):
|
||||
global BuddySystemObject
|
||||
import drivers.serial.uart.serial as serial
|
||||
# [DBG] 无条件打印 memmap 三参数,判定分支未走的根因(用后移除)
|
||||
@@ -508,43 +508,43 @@ def init(MemmapAddr: t.CUInt64T, MemmapSize: t.CUInt64T, MemmapDescSize: t.CUInt
|
||||
viperlib.snprintf(c.Addr(_dk0), 100, "[mm] raw addr=0x%lx size=%lu desc=%lu\n",
|
||||
MemmapAddr, MemmapSize, MemmapDescSize)
|
||||
serial.puts(c.Addr(_dk0))
|
||||
start_addr: t.CVoid | t.CPtr = None
|
||||
size: t.CUInt64T = 0
|
||||
start_addr: t.CPtr = None
|
||||
size: uint64 = 0
|
||||
if MemmapAddr != 0:
|
||||
if MemmapSize > 0:
|
||||
if MemmapDescSize > 0:
|
||||
num_entries: t.CUInt64T = MemmapSize / MemmapDescSize
|
||||
num_entries: uint64 = MemmapSize / MemmapDescSize
|
||||
# [DBG] 关键数值:memmap 缓冲/步长/条目数(用后移除)
|
||||
_dk1: t.CArray[t.CChar, 100]
|
||||
viperlib.snprintf(c.Addr(_dk1), 100, "[mm] addr=0x%lx size=%lu desc=%lu entries=%lu\n",
|
||||
MemmapAddr, MemmapSize, MemmapDescSize, num_entries)
|
||||
serial.puts(c.Addr(_dk1))
|
||||
max_memory: t.CUInt64T = 0
|
||||
best_start: t.CUInt64T = 0
|
||||
best_avail_size: t.CUInt64T = 0
|
||||
best_avail_start: t.CUInt64T = 0
|
||||
best_bs_size: t.CUInt64T = 0
|
||||
best_bs_start: t.CUInt64T = 0
|
||||
best_ld_size: t.CUInt64T = 0
|
||||
best_ld_start: t.CUInt64T = 0
|
||||
i: t.CUInt64T
|
||||
max_memory: uint64 = 0
|
||||
best_start: uint64 = 0
|
||||
best_avail_size: uint64 = 0
|
||||
best_avail_start: uint64 = 0
|
||||
best_bs_size: uint64 = 0
|
||||
best_bs_start: uint64 = 0
|
||||
best_ld_size: uint64 = 0
|
||||
best_ld_start: uint64 = 0
|
||||
i: uint64
|
||||
# [DBG] 转储全部 memmap 描述符,定位 4GB 伪可用区的来源(用后移除)
|
||||
for i in range(num_entries):
|
||||
entry: bootinfo.memory_map_entry | t.CPtr = t.CVoid(MemmapAddr + i * MemmapDescSize, t.CPtr)
|
||||
_dbgd: t.CArray[t.CChar, 100]
|
||||
viperlib.snprintf(c.Addr(_dbgd), 100, "[mm] d[%lu] t=%lu start=0x%lx np=%lu\n",
|
||||
i, t.CUInt64T(entry.type), entry.physical_start, entry.num_pages)
|
||||
i, uint64(entry.type), entry.physical_start, entry.num_pages)
|
||||
serial.puts(c.Addr(_dbgd))
|
||||
for i in range(num_entries):
|
||||
entry: bootinfo.memory_map_entry | t.CPtr = t.CVoid(MemmapAddr + i * MemmapDescSize, t.CPtr)
|
||||
etype: t.CUInt64T = entry.type
|
||||
start: t.CUInt64T = align_4k(entry.physical_start)
|
||||
np: t.CUInt64T = entry.num_pages
|
||||
end: t.CUInt64T = entry.physical_start + np * 4096
|
||||
etype: uint64 = entry.type
|
||||
start: uint64 = align_4k(entry.physical_start)
|
||||
np: uint64 = entry.num_pages
|
||||
end: uint64 = entry.physical_start + np * 4096
|
||||
end = align_4k(end - 1)
|
||||
region_size: t.CUInt64T = end - start
|
||||
region_size: uint64 = end - start
|
||||
if FbAddr != 0 and FbSize != 0:
|
||||
fb_end: t.CUInt64T = FbAddr + FbSize
|
||||
fb_end: uint64 = FbAddr + FbSize
|
||||
if start < fb_end and end > FbAddr:
|
||||
continue
|
||||
if etype == MEMORY_TYPE_AVAILABLE:
|
||||
@@ -559,7 +559,7 @@ def init(MemmapAddr: t.CUInt64T, MemmapSize: t.CUInt64T, MemmapDescSize: t.CUInt
|
||||
if region_size > best_ld_size:
|
||||
best_ld_size = region_size
|
||||
best_ld_start = start
|
||||
min_blk: t.CUInt64T = MIN_BLOCK_SIZE
|
||||
min_blk: uint64 = MIN_BLOCK_SIZE
|
||||
if best_avail_size >= min_blk:
|
||||
best_start = best_avail_start
|
||||
max_memory = best_avail_size
|
||||
@@ -584,7 +584,7 @@ def init(MemmapAddr: t.CUInt64T, MemmapSize: t.CUInt64T, MemmapDescSize: t.CUInt
|
||||
viperlib.snprintf(c.Addr(_dc0), 100, "[mm] fallback cmos 0x%02x 0x%02x 0x%02x 0x%02x\n",
|
||||
cmos_read(0x15), cmos_read(0x16), cmos_read(0x17), cmos_read(0x18))
|
||||
serial.puts(c.Addr(_dc0))
|
||||
_dsz: t.CUInt64T = detect_memory_size()
|
||||
_dsz: uint64 = detect_memory_size()
|
||||
viperlib.snprintf(c.Addr(_dc0), 100, "[mm] fallback detect=%lu\n", _dsz)
|
||||
serial.puts(c.Addr(_dc0))
|
||||
size = detect_memory_size()
|
||||
@@ -595,13 +595,13 @@ def init(MemmapAddr: t.CUInt64T, MemmapSize: t.CUInt64T, MemmapDescSize: t.CUInt
|
||||
if size > 0x400000:
|
||||
size = size - 0x400000
|
||||
size = align_4k(size)
|
||||
min_blk2: t.CUInt64T = MIN_BLOCK_SIZE
|
||||
min_blk2: uint64 = MIN_BLOCK_SIZE
|
||||
if size < min_blk2:
|
||||
size = 33554432
|
||||
cr2: t.CArray[t.CChar, 128]
|
||||
string.memset(c.Addr(cr2), 0, 128)
|
||||
viperlib.snprintf(c.Addr(cr2), 128, "mm.init: start=0x%lx size=%lu bytes\n",
|
||||
t.CUInt64T(start_addr), size)
|
||||
uint64(start_addr), size)
|
||||
serial.puts(cr2)
|
||||
BuddySystemObject.__init__(start_addr, size)
|
||||
SlabAllocator.__init__()
|
||||
@@ -609,10 +609,10 @@ def init(MemmapAddr: t.CUInt64T, MemmapSize: t.CUInt64T, MemmapDescSize: t.CUInt
|
||||
|
||||
# 虚拟内存映射结构
|
||||
class vm_area(t.CStruct):
|
||||
VirtAddr: t.CUInt64T
|
||||
PhysAddr: t.CUInt64T
|
||||
size: t.CUInt64T
|
||||
flags: t.CUInt32T
|
||||
VirtAddr: uint64
|
||||
PhysAddr: uint64
|
||||
size: uint64
|
||||
flags: uint32
|
||||
next: 'vm_area' | t.CPtr
|
||||
|
||||
# 全局虚拟内存区域链表
|
||||
@@ -623,15 +623,15 @@ ALLOCATION_RETRIES: t.CDefine = 5 # 分配重试次数
|
||||
FRAGMENTATION_THRESHOLD: t.CDefine = 0.7 # 碎片率阈值
|
||||
|
||||
# 获取内存使用统计
|
||||
@c.CReturn(t.CUInt64T, t.CUInt64T, t.CUInt64T)
|
||||
@c.CReturn(uint64, uint64, uint64)
|
||||
def GetMemoryStats():
|
||||
return (BuddySystemObject.buddy.total_memory, BuddySystemObject.buddy.used_memory, BuddySystemObject.buddy.free_memory)
|
||||
|
||||
# 计算内存碎片率
|
||||
def calculate_fragmentation() -> t.CDouble:
|
||||
# 计算空闲块的数量和总大小
|
||||
free_blocks: t.CInt = 0
|
||||
free_size: t.CUInt64T = 0
|
||||
free_blocks: int = 0
|
||||
free_size: uint64 = 0
|
||||
|
||||
for i in range(MAX_ORDER + 1):
|
||||
block: memory_block | t.CPtr = BuddySystemObject.buddy.free_lists[i]
|
||||
@@ -646,7 +646,7 @@ def calculate_fragmentation() -> t.CDouble:
|
||||
|
||||
# 计算碎片率
|
||||
# 碎片率 = 1 - (最大空闲块大小 / 总空闲内存大小)
|
||||
max_free_block: t.CUInt64T = 0
|
||||
max_free_block: uint64 = 0
|
||||
for i in range(MAX_ORDER, -1, -1):
|
||||
if BuddySystemObject.buddy.free_lists[i]:
|
||||
max_free_block = get_block_size(i)
|
||||
@@ -658,8 +658,8 @@ def calculate_fragmentation() -> t.CDouble:
|
||||
return 1.0 - (t.CDouble(max_free_block) / t.CDouble(free_size))
|
||||
|
||||
# 内存整理函数
|
||||
def compact_memory() -> t.CStatic | t.CInt:
|
||||
freed_pages: t.CInt = 0
|
||||
def compact_memory() -> t.CStatic | int:
|
||||
freed_pages: int = 0
|
||||
for sc in range(SLAB_NUM_SIZES):
|
||||
page: slab_page | t.CPtr = SlabAllocator.caches[sc]
|
||||
while page:
|
||||
@@ -678,14 +678,14 @@ def compact_memory() -> t.CStatic | t.CInt:
|
||||
return freed_pages
|
||||
|
||||
# 虚拟内存分配函数
|
||||
def vm_alloc(size: t.CUInt64T, flags: t.CUInt32T) -> t.CUInt64T:
|
||||
def vm_alloc(size: uint64, flags: uint32) -> uint64:
|
||||
global vm_areas
|
||||
# 4K对齐
|
||||
size = align_4k(size)
|
||||
|
||||
# 尝试分配物理内存,使用博弈机制
|
||||
PhysAddr: t.CVoid | t.CPtr = None
|
||||
retries: t.CInt = 0
|
||||
PhysAddr: t.CPtr = None
|
||||
retries: int = 0
|
||||
|
||||
while retries < ALLOCATION_RETRIES:
|
||||
PhysAddr = malloc(size)
|
||||
@@ -703,7 +703,7 @@ def vm_alloc(size: t.CUInt64T, flags: t.CUInt32T) -> t.CUInt64T:
|
||||
|
||||
# 分配虚拟地址
|
||||
# 简单的虚拟地址分配策略:从0x100000000开始
|
||||
VirtAddr: t.CUInt64T = 0x100000000
|
||||
VirtAddr: uint64 = 0x100000000
|
||||
current: vm_area | t.CPtr = vm_areas
|
||||
|
||||
# 寻找合适的虚拟地址空间
|
||||
@@ -717,7 +717,7 @@ def vm_alloc(size: t.CUInt64T, flags: t.CUInt32T) -> t.CUInt64T:
|
||||
area: vm_area | t.CPtr = malloc(vm_area.__sizeof__())
|
||||
if area:
|
||||
area.VirtAddr = VirtAddr
|
||||
area.PhysAddr = t.CUInt64T(PhysAddr)
|
||||
area.PhysAddr = uint64(PhysAddr)
|
||||
area.size = size
|
||||
area.flags = flags
|
||||
area.next = vm_areas
|
||||
@@ -725,18 +725,18 @@ def vm_alloc(size: t.CUInt64T, flags: t.CUInt32T) -> t.CUInt64T:
|
||||
|
||||
# 映射虚拟地址到物理地址
|
||||
# 计算需要映射的页数
|
||||
pages: t.CUInt64T = size / 4096
|
||||
i: t.CUInt64T
|
||||
pages: uint64 = size / 4096
|
||||
i: uint64
|
||||
for i in range(pages):
|
||||
page_virt: t.CUInt64T = VirtAddr + (i * 4096)
|
||||
page_phys: t.CUInt64T = t.CUInt64T(PhysAddr) + (i * 4096)
|
||||
page_virt: uint64 = VirtAddr + (i * 4096)
|
||||
page_phys: uint64 = uint64(PhysAddr) + (i * 4096)
|
||||
# 调用paging模块的映射函数
|
||||
paging.MapPage(page_virt, page_phys, flags)
|
||||
|
||||
return VirtAddr
|
||||
|
||||
# 虚拟内存释放函数
|
||||
def vm_free(VirtAddr: t.CUInt64T):
|
||||
def vm_free(VirtAddr: uint64):
|
||||
global vm_areas
|
||||
# 查找虚拟内存区域
|
||||
current: vm_area | t.CPtr = vm_areas
|
||||
@@ -745,10 +745,10 @@ def vm_free(VirtAddr: t.CUInt64T):
|
||||
while current:
|
||||
if current.VirtAddr == VirtAddr:
|
||||
# 取消虚拟地址映射
|
||||
pages: t.CUInt64T = current.size / 4096
|
||||
i: t.CUInt64T
|
||||
pages: uint64 = current.size / 4096
|
||||
i: uint64
|
||||
for i in range(pages):
|
||||
page_virt: t.CUInt64T = current.VirtAddr + (i * 4096)
|
||||
page_virt: uint64 = current.VirtAddr + (i * 4096)
|
||||
paging.UnMapPage(page_virt)
|
||||
|
||||
# 释放物理内存
|
||||
@@ -763,42 +763,42 @@ def vm_free(VirtAddr: t.CUInt64T):
|
||||
current = current.next
|
||||
|
||||
# CMOS读取函数
|
||||
def cmos_read(reg: t.CUInt8T) -> t.CUInt8T:
|
||||
def cmos_read(reg: uint8) -> uint8:
|
||||
# in/out al 会改 EAX,必须 CLOBBER_RAX;显式 mov 到输出寄存器
|
||||
#(与 asm.inb/inw 修复同模式,避免调用方 EAX 被静默破坏)。
|
||||
c.Asm(f"""mov eax, {c.AsmInp(t.CUInt32T(reg), t.ASM_DESCR.REG_ANY)}
|
||||
c.Asm(f"""mov eax, {c.AsmInp(uint32(reg), t.ASM_DESCR.REG_ANY)}
|
||||
out 0x70, al""",
|
||||
op=[t.ASM_DESCR.CLOBBER_RAX])
|
||||
val32: t.CUInt32T
|
||||
val32: uint32
|
||||
c.Asm(f"""in al, 0x71
|
||||
movzx eax, al
|
||||
mov {c.AsmOut(val32, t.ASM_DESCR.OUTPUT_REG)}, eax""",
|
||||
out=[c.AsmOut(val32, t.ASM_DESCR.OUTPUT_REG)],
|
||||
op=[t.ASM_DESCR.CLOBBER_RAX])
|
||||
return t.CUInt8T(val32)
|
||||
return uint8(val32)
|
||||
|
||||
# 内存大小测试函数
|
||||
def detect_memory_size() -> t.CUInt64T:
|
||||
def detect_memory_size() -> uint64:
|
||||
# 读取 1MB-16MB 扩展内存(KB 单位)
|
||||
low: t.CUInt8T = cmos_read(0x15)
|
||||
high: t.CUInt8T = cmos_read(0x16)
|
||||
mem_kb: t.CUInt32T = (t.CUInt32T(high) << 8) | low
|
||||
low: uint8 = cmos_read(0x15)
|
||||
high: uint8 = cmos_read(0x16)
|
||||
mem_kb: uint32 = (uint32(high) << 8) | low
|
||||
|
||||
# 读取 16MB 以上扩展内存(64KB 块为单位)
|
||||
low2: t.CUInt8T = cmos_read(0x17)
|
||||
high2: t.CUInt8T = cmos_read(0x18)
|
||||
mem_above_16mb: t.CUInt32T = (t.CUInt32T(high2) << 8) | low2
|
||||
low2: uint8 = cmos_read(0x17)
|
||||
high2: uint8 = cmos_read(0x18)
|
||||
mem_above_16mb: uint32 = (uint32(high2) << 8) | low2
|
||||
|
||||
# 两个寄存器都为 0 时使用默认值
|
||||
if mem_kb == 0 and mem_above_16mb == 0:
|
||||
return 0x10000000 # 256MB
|
||||
|
||||
# 计算总内存:1MB 基础 + 1MB-16MB + 16MB 以上
|
||||
total_size: t.CUInt64T = 1048576 # 前 1MB
|
||||
total_size: uint64 = 1048576 # 前 1MB
|
||||
if mem_kb > 0:
|
||||
total_size = total_size + t.CUInt64T(mem_kb) * 1024
|
||||
total_size = total_size + uint64(mem_kb) * 1024
|
||||
if mem_above_16mb > 0:
|
||||
total_size = total_size + t.CUInt64T(mem_above_16mb) * 65536
|
||||
total_size = total_size + uint64(mem_above_16mb) * 65536
|
||||
|
||||
total_size = align_4k(total_size)
|
||||
|
||||
|
||||
+479
-479
@@ -1,479 +1,479 @@
|
||||
import drivers.serial.uart.serial as serial
|
||||
import viperlib
|
||||
import t, c
|
||||
|
||||
|
||||
PTE_PRESENT: t.CDefine = (1 << 0)
|
||||
PTE_WRITABLE: t.CDefine = (1 << 1)
|
||||
PTE_USER: t.CDefine = (1 << 2)
|
||||
PTE_PWT: t.CDefine = (1 << 3)
|
||||
PTE_PCD: t.CDefine = (1 << 4)
|
||||
PTE_ACCESSED: t.CDefine = (1 << 5)
|
||||
PTE_DIRTY: t.CDefine = (1 << 6)
|
||||
PTE_PS: t.CDefine = (1 << 7)
|
||||
PTE_GLOBAL: t.CDefine = (1 << 8)
|
||||
|
||||
class _p:
|
||||
entries: t.CArray[t.CUInt64T, 512]
|
||||
|
||||
PT_POOL_PAGES: t.CDefine = 512
|
||||
pt_pool_raw: t.CVoid | t.CPtr = None
|
||||
pt_pool_start: t.CUInt64T = 0
|
||||
pt_pool_used: t.CUInt64T = 0
|
||||
|
||||
AllocatedPages: t.CUInt64T = 0
|
||||
pml4: _p | t.CPtr = None
|
||||
pdp: _p | t.CPtr
|
||||
pd: _p | t.CPtr
|
||||
pt: _p | t.CPtr
|
||||
|
||||
def init(MemmapAddr: t.CUInt64T, MemmapSize: t.CUInt64T):
|
||||
global pml4
|
||||
pml4 = GetCurrentPml4()
|
||||
# bootloader/UEFI 的 CR0.WP 通常已是 1(原代码清 WP 正因此)。页表页
|
||||
# (pml4/pdp/pd/pt,0xf8xxxx)默认只读,而内核运行时 MapPage/clone 需
|
||||
# 修改页表。顺序:先清 WP(允许写只读页表页)→ MakePTWritable 放开
|
||||
# 全部页表页 → 再置 WP=1(此后写只读页即 #PF 暴露越界写源)。
|
||||
c.Asm(f"""
|
||||
mov rax, cr0
|
||||
and rax, ~0x10000
|
||||
mov cr0, rax
|
||||
""")
|
||||
MakePTWritable()
|
||||
c.Asm(f"""
|
||||
mov rax, cr0
|
||||
or rax, 0x10000
|
||||
mov cr0, rax
|
||||
""")
|
||||
|
||||
def init_pool(buf: t.CVoid | t.CPtr, buf_size: t.CUInt64T):
|
||||
global pt_pool_raw, pt_pool_start, pt_pool_used
|
||||
pt_pool_raw = buf
|
||||
if buf is None: return
|
||||
raw_addr: t.CUInt64T = t.CUInt64T(buf)
|
||||
aligned_addr: t.CUInt64T = (raw_addr + t.CUInt64T(0xFFF)) & ~t.CUInt64T(0xFFF)
|
||||
pt_pool_start = aligned_addr
|
||||
pt_pool_used = 0
|
||||
# [DIAG] 定位 clone 时 pt_pool_raw=0x0(init 后被覆盖?还是 init 收到 0)
|
||||
_dip: t.CArray[t.CChar, 80]
|
||||
viperlib.snprintf(c.Addr(_dip), 80, "[paging] init_pool raw=0x%lx start=0x%lx\n", t.CUInt64T(pt_pool_raw), pt_pool_start)
|
||||
serial.puts(c.Addr(_dip))
|
||||
|
||||
def AllocPage() -> t.CVoid | t.CPtr:
|
||||
global AllocatedPages, pt_pool_used, pml4, pdp, pd, pt
|
||||
if pt_pool_raw is None: return None
|
||||
if pt_pool_used >= t.CUInt64T(PT_POOL_PAGES): return None
|
||||
page: t.CVoid | t.CPtr = t.CVoid(pt_pool_start + pt_pool_used * t.CUInt64T(4096), t.CPtr)
|
||||
pt_pool_used = pt_pool_used + t.CUInt64T(1)
|
||||
c.Asm(f"""mov al, 0
|
||||
mov ecx, 4096
|
||||
mov rdi, {c.AsmInp(page, t.ASM_DESCR.REG_ANY)}
|
||||
rep stosb""",
|
||||
op = [t.ASM_DESCR.CLOBBER_AL, t.ASM_DESCR.CLOBBER_ECX, t.ASM_DESCR.CLOBBER_RDI])
|
||||
AllocatedPages = AllocatedPages + t.CUInt64T(1)
|
||||
return page
|
||||
|
||||
def FreePage(page: t.CVoid | t.CPtr):
|
||||
global AllocatedPages, pml4, pdp, pd, pt
|
||||
if page is None: return
|
||||
if AllocatedPages > 0: AllocatedPages = AllocatedPages - t.CUInt64T(1)
|
||||
|
||||
def MapPage(VirtAddr: t.CUInt64T, PhysAddr: t.CUInt64T, flags: t.CUInt64T):
|
||||
global pml4, pdp, pd, pt
|
||||
if VirtAddr == 0 or PhysAddr == 0: return
|
||||
VirtAddr = VirtAddr & ~t.CUInt64T(0xFFF)
|
||||
PhysAddr = PhysAddr & ~t.CUInt64T(0xFFF)
|
||||
Pml4Index: t.CUInt64T = (VirtAddr >> 39) & 0x1FF
|
||||
PdpIndex: t.CUInt64T = (VirtAddr >> 30) & 0x1FF
|
||||
PdIndex: t.CUInt64T = (VirtAddr >> 21) & 0x1FF
|
||||
PtIndex: t.CUInt64T = (VirtAddr >> 12) & 0x1FF
|
||||
|
||||
if not pml4:
|
||||
pml4 = AllocPage()
|
||||
if not pml4: return
|
||||
|
||||
if not (pml4.entries[Pml4Index] & PTE_PRESENT):
|
||||
pdp: _p | t.CPtr = AllocPage()
|
||||
if not pdp: return
|
||||
pml4.entries[Pml4Index] = (t.CUInt64T(pdp) & ~t.CUInt64T(0xFFF)) | PTE_PRESENT | PTE_WRITABLE | (flags & PTE_USER)
|
||||
else:
|
||||
if (flags & PTE_USER) and not (pml4.entries[Pml4Index] & PTE_USER):
|
||||
pml4.entries[Pml4Index] = pml4.entries[Pml4Index] | PTE_USER
|
||||
pdp: _p | t.CPtr = t.CType(pml4.entries[Pml4Index] & ~t.CUInt64T(0xFFF), _p, t.CPtr)
|
||||
|
||||
if not (pdp.entries[PdpIndex] & PTE_PRESENT):
|
||||
pd: _p | t.CPtr = AllocPage()
|
||||
if not pd: return
|
||||
pdp.entries[PdpIndex] = (t.CUInt64T(pd) & ~t.CUInt64T(0xFFF)) | PTE_PRESENT | PTE_WRITABLE | (flags & PTE_USER)
|
||||
else:
|
||||
if (flags & PTE_USER) and not (pdp.entries[PdpIndex] & PTE_USER):
|
||||
pdp.entries[PdpIndex] = pdp.entries[PdpIndex] | PTE_USER
|
||||
pd: _p | t.CPtr = t.CType(pdp.entries[PdpIndex] & ~t.CUInt64T(0xFFF), _p, t.CPtr)
|
||||
|
||||
if pd.entries[PdIndex] & 1:
|
||||
if pd.entries[PdIndex] & 0x80:
|
||||
big_phys: t.CUInt64T = pd.entries[PdIndex] & ~t.CUInt64T(0x1FFFFF)
|
||||
inherit_flags: t.CUInt64T = pd.entries[PdIndex] & (PTE_PCD | PTE_PWT)
|
||||
pt: _p | t.CPtr = AllocPage()
|
||||
if not pt: return
|
||||
split_i: t.CInt = 0
|
||||
while split_i < 512:
|
||||
pt.entries[split_i] = (big_phys + t.CUInt64T(split_i) * 0x1000) | PTE_PRESENT | PTE_WRITABLE | inherit_flags
|
||||
split_i += 1
|
||||
pd.entries[PdIndex] = (t.CUInt64T(pt) & ~t.CUInt64T(0xFFF)) | PTE_PRESENT | PTE_WRITABLE | (flags & PTE_USER)
|
||||
else:
|
||||
# PD entry exists as a regular PT (e.g. cloned identity mapping).
|
||||
# Must propagate PTE_USER to the PD entry so user-mode access is
|
||||
# allowed at all paging levels, otherwise #PF err=0x5.
|
||||
if (flags & PTE_USER) and not (pd.entries[PdIndex] & PTE_USER):
|
||||
pd.entries[PdIndex] = pd.entries[PdIndex] | PTE_USER
|
||||
else:
|
||||
pt: _p | t.CPtr = AllocPage()
|
||||
if not pt: return
|
||||
pd.entries[PdIndex] = (t.CUInt64T(pt) & ~t.CUInt64T(0xFFF)) | PTE_PRESENT | PTE_WRITABLE | (flags & PTE_USER)
|
||||
pt: _p | t.CPtr = t.CType(pd.entries[PdIndex] & ~t.CUInt64T(0xFFF), _p, t.CPtr)
|
||||
|
||||
pt.entries[PtIndex] = PhysAddr | flags | PTE_PRESENT
|
||||
c.Asm(f"invlpg [{c.AsmInp(VirtAddr, t.ASM_DESCR.REG_ANY)}]")
|
||||
|
||||
def MapLargePage(VirtAddr: t.CUInt64T, PhysAddr: t.CUInt64T, flags: t.CUInt64T) -> t.CVoid:
|
||||
global pml4, pdp, pd, pt
|
||||
VirtAddr = VirtAddr & ~t.CUInt64T(0x1FFFFF)
|
||||
PhysAddr = PhysAddr & ~t.CUInt64T(0x1FFFFF)
|
||||
Pml4Index: t.CUInt64T = (VirtAddr >> 39) & 0x1FF
|
||||
PdpIndex: t.CUInt64T = (VirtAddr >> 30) & 0x1FF
|
||||
PdIndex: t.CUInt64T = (VirtAddr >> 21) & 0x1FF
|
||||
|
||||
if not pml4:
|
||||
pml4 = AllocPage()
|
||||
if not pml4: return
|
||||
|
||||
if not pml4.entries[Pml4Index] & PTE_PRESENT:
|
||||
pdp: _p | t.CPtr = AllocPage()
|
||||
if not pdp: return
|
||||
pml4.entries[Pml4Index] = (t.CUInt64T(pdp) & ~t.CUInt64T(0xFFF)) | PTE_PRESENT | PTE_WRITABLE
|
||||
pdp: _p | t.CPtr = t.CType(pml4.entries[Pml4Index] & ~t.CUInt64T(0xFFF), _p, t.CPtr)
|
||||
|
||||
if not (pdp.entries[PdpIndex] & PTE_PRESENT):
|
||||
pd: _p | t.CPtr = AllocPage()
|
||||
if not pd: return
|
||||
pdp.entries[PdpIndex] = (t.CUInt64T(pd) & ~t.CUInt64T(0xFFF)) | PTE_PRESENT | PTE_WRITABLE
|
||||
pd: _p | t.CPtr = t.CType(pdp.entries[PdpIndex] & ~t.CUInt64T(0xFFF), _p, t.CPtr)
|
||||
|
||||
pd.entries[PdIndex] = PhysAddr | flags | PTE_PRESENT | PTE_PS
|
||||
c.Asm(f"invlpg [{c.AsmInp(VirtAddr, t.ASM_DESCR.REG_ANY)}]")
|
||||
|
||||
def UnMapPage(VirtAddr: t.CUInt64T):
|
||||
global pml4, pdp, pd, pt
|
||||
if VirtAddr == 0: return
|
||||
if not pml4: return
|
||||
Pml4Index: t.CUInt64T = (VirtAddr >> 39) & 0x1FF
|
||||
PdpIndex: t.CUInt64T = (VirtAddr >> 30) & 0x1FF
|
||||
PdIndex: t.CUInt64T = (VirtAddr >> 21) & 0x1FF
|
||||
PtIndex: t.CUInt64T = (VirtAddr >> 12) & 0x1FF
|
||||
|
||||
if not pml4.entries[Pml4Index] & PTE_PRESENT: return
|
||||
|
||||
pdp: _p | t.CPtr = t.CType(pml4.entries[Pml4Index] & ~t.CUInt64T(0xFFF), _p, t.CPtr)
|
||||
if not pdp.entries[PdpIndex] & PTE_PRESENT: return
|
||||
|
||||
pd: _p | t.CPtr = t.CType(pdp.entries[PdpIndex] & ~t.CUInt64T(0xFFF), _p, t.CPtr)
|
||||
|
||||
if not pd.entries[PdIndex] & PTE_PRESENT: return
|
||||
|
||||
if pd.entries[PdIndex] & PTE_PS:
|
||||
pd.entries[PdIndex] = 0
|
||||
else:
|
||||
pt: _p | t.CPtr = t.CType(pd.entries[PdIndex] & ~t.CUInt64T(0xFFF), _p, t.CPtr)
|
||||
pt.entries[PtIndex] = 0
|
||||
|
||||
c.Asm(f"invlpg [{c.AsmInp(VirtAddr, t.ASM_DESCR.REG_ANY)}]")
|
||||
|
||||
def EnablePaging():
|
||||
global pml4, pdp, pd, pt
|
||||
c.Asm(f"mov cr3, {c.AsmInp(t.CUInt64T(pml4), t.ASM_DESCR.REG_ANY)}")
|
||||
|
||||
def _set_page_writable(phys_addr: t.CUInt64T):
|
||||
"""把物理页 phys_addr(identity 映射,虚拟=物理)的 PTE 置 W 位
|
||||
|
||||
页表页(bootloader 建立的 pml4/pdp/pd/pt 位于 0xf8xxxx)默认只读,
|
||||
而内核运行时 MapPage/clone 需修改页表 → 必须先把这些页表页自身设为可写,
|
||||
否则 CR0.WP=1 下写页表触发 #PF(slog.so 映射 0x600000 新建页表项时
|
||||
cr2=0xf801000 err=0x3 根因)。
|
||||
"""
|
||||
global pml4
|
||||
if not pml4: return
|
||||
va: t.CUInt64T = phys_addr & ~t.CUInt64T(0xFFF)
|
||||
pml4_idx: t.CUInt64T = (va >> 39) & 0x1FF
|
||||
if not (pml4.entries[pml4_idx] & PTE_PRESENT): return
|
||||
pdp_s: _p | t.CPtr = t.CType(pml4.entries[pml4_idx] & ~t.CUInt64T(0xFFF), _p, t.CPtr)
|
||||
pdp_idx: t.CUInt64T = (va >> 30) & 0x1FF
|
||||
if not (pdp_s.entries[pdp_idx] & PTE_PRESENT): return
|
||||
pd_s: _p | t.CPtr = t.CType(pdp_s.entries[pdp_idx] & ~t.CUInt64T(0xFFF), _p, t.CPtr)
|
||||
pd_idx: t.CUInt64T = (va >> 21) & 0x1FF
|
||||
if not (pd_s.entries[pd_idx] & PTE_PRESENT): return
|
||||
if pd_s.entries[pd_idx] & PTE_PS:
|
||||
# 2MB 大页:W 位在 PD 条目自身(无下层 PT),直接置位
|
||||
pd_s.entries[pd_idx] = pd_s.entries[pd_idx] | t.CUInt64T(PTE_WRITABLE)
|
||||
c.Asm(f"invlpg [{c.AsmInp(va, t.ASM_DESCR.REG_ANY)}]")
|
||||
return
|
||||
pt_s: _p | t.CPtr = t.CType(pd_s.entries[pd_idx] & ~t.CUInt64T(0xFFF), _p, t.CPtr)
|
||||
pt_idx: t.CUInt64T = (va >> 12) & 0x1FF
|
||||
pt_s.entries[pt_idx] = pt_s.entries[pt_idx] | t.CUInt64T(PTE_WRITABLE)
|
||||
c.Asm(f"invlpg [{c.AsmInp(va, t.ASM_DESCR.REG_ANY)}]")
|
||||
|
||||
def MakePTWritable():
|
||||
"""把当前页表层次所有页表页(pml4 自身 + pdp/pd/pt)设为可写
|
||||
|
||||
内核运行时需修改页表(MapPage/clone_for_process),而 bootloader 建立的
|
||||
页表页映射为只读——CR0.WP=1 下必须先放开页表页自身,否则写页表即 #PF。
|
||||
"""
|
||||
global pml4
|
||||
if not pml4: return
|
||||
_set_page_writable(t.CUInt64T(pml4))
|
||||
pi: t.CUInt64T
|
||||
for pi in range(512):
|
||||
if not (pml4.entries[pi] & PTE_PRESENT): continue
|
||||
pdp_m: _p | t.CPtr = t.CType(pml4.entries[pi] & ~t.CUInt64T(0xFFF), _p, t.CPtr)
|
||||
_set_page_writable(t.CUInt64T(pdp_m))
|
||||
pj: t.CUInt64T
|
||||
for pj in range(512):
|
||||
if not (pdp_m.entries[pj] & PTE_PRESENT): continue
|
||||
pd_m: _p | t.CPtr = t.CType(pdp_m.entries[pj] & ~t.CUInt64T(0xFFF), _p, t.CPtr)
|
||||
_set_page_writable(t.CUInt64T(pd_m))
|
||||
pk: t.CUInt64T
|
||||
for pk in range(512):
|
||||
if not (pd_m.entries[pk] & PTE_PRESENT): continue
|
||||
if pd_m.entries[pk] & PTE_PS: continue
|
||||
pt_m: _p | t.CPtr = t.CType(pd_m.entries[pk] & ~t.CUInt64T(0xFFF), _p, t.CPtr)
|
||||
_set_page_writable(t.CUInt64T(pt_m))
|
||||
|
||||
def MakeRangeRO(vaddr_start: t.CUInt64T, vaddr_end: t.CUInt64T):
|
||||
"""把 [vaddr_start, vaddr_end) 范围内所有页的 PTE 清 W 位(只读)
|
||||
|
||||
定位越界写源:内核态写只读页在 CR0.WP=1 下触发 #PF(int=14),
|
||||
isrCommonhandler 打印 cr2/rip → 写源立即暴露,不再静默破坏 .rodata。
|
||||
"""
|
||||
global pml4
|
||||
if not pml4: return
|
||||
va: t.CUInt64T = vaddr_start & ~t.CUInt64T(0xFFF)
|
||||
# ro_end 下取整到页:不保护含 ro_end 的未对齐尾页。链接脚本输出段未页对齐,
|
||||
# .data 紧跟 .rodata(__rodata_end 未对齐时 .data 起始落在 rodata 尾页内),
|
||||
# 整页置只读会把 .data 全局(如 devfs @DevFSObject=0x141630)误保护 →
|
||||
# devfs_init 写全局 #PF(cr2=0x141630 rip=0x101aaa mov [r15],rax 根因)。
|
||||
# 尾页含少量 rodata 尾部(对齐填充),保持可写可容忍。
|
||||
ro_end_align: t.CUInt64T = vaddr_end & ~t.CUInt64T(0xFFF)
|
||||
while va < ro_end_align:
|
||||
pml4_idx: t.CUInt64T = (va >> 39) & 0x1FF
|
||||
if not (pml4.entries[pml4_idx] & PTE_PRESENT): va += 0x1000; continue
|
||||
pdp_r: _p | t.CPtr = t.CType(pml4.entries[pml4_idx] & ~t.CUInt64T(0xFFF), _p, t.CPtr)
|
||||
pdp_idx: t.CUInt64T = (va >> 30) & 0x1FF
|
||||
if not (pdp_r.entries[pdp_idx] & PTE_PRESENT): va += 0x1000; continue
|
||||
pd_r: _p | t.CPtr = t.CType(pdp_r.entries[pdp_idx] & ~t.CUInt64T(0xFFF), _p, t.CPtr)
|
||||
pd_idx: t.CUInt64T = (va >> 21) & 0x1FF
|
||||
if not (pd_r.entries[pd_idx] & PTE_PRESENT): va += 0x1000; continue
|
||||
if pd_r.entries[pd_idx] & PTE_PS:
|
||||
# 2MB 大页:直接跳过会让 .rodata 保持可写——越界写被静默吞掉
|
||||
# (perf 格式串 win=%lu/work=%lu 被逐步破坏的根因)。拆分为 512
|
||||
# 个 4KB 页(复用 MapPage 的分裂逻辑),再走下方常规路径清 W 位。
|
||||
# WP=1 后内核态写只读页即 #PF → isrCommonhandler 打印 cr2/rip 暴露写源。
|
||||
big_phys: t.CUInt64T = pd_r.entries[pd_idx] & ~t.CUInt64T(0x1FFFFF)
|
||||
inherit_flags: t.CUInt64T = pd_r.entries[pd_idx] & (PTE_PCD | PTE_PWT | PTE_USER | t.CUInt64T(0x8000000000000000))
|
||||
pt_split: _p | t.CPtr = AllocPage()
|
||||
if not pt_split:
|
||||
va += 0x1000
|
||||
continue
|
||||
split_i: t.CInt = 0
|
||||
while split_i < 512:
|
||||
pt_split.entries[split_i] = (big_phys + t.CUInt64T(split_i) * t.CUInt64T(0x1000)) \
|
||||
| PTE_PRESENT | PTE_WRITABLE | inherit_flags
|
||||
split_i += 1
|
||||
pd_r.entries[pd_idx] = (t.CUInt64T(pt_split) & ~t.CUInt64T(0xFFF)) \
|
||||
| PTE_PRESENT | PTE_WRITABLE | (pd_r.entries[pd_idx] & PTE_USER)
|
||||
c.Asm(f"invlpg [{c.AsmInp(va, t.ASM_DESCR.REG_ANY)}]")
|
||||
# 分裂后落入下方 4KB 常规路径,继续清当前页 W 位
|
||||
pt_r: _p | t.CPtr = t.CType(pd_r.entries[pd_idx] & ~t.CUInt64T(0xFFF), _p, t.CPtr)
|
||||
pt_idx: t.CUInt64T = (va >> 12) & 0x1FF
|
||||
pt_r.entries[pt_idx] = pt_r.entries[pt_idx] & ~t.CUInt64T(PTE_WRITABLE)
|
||||
c.Asm(f"invlpg [{c.AsmInp(va, t.ASM_DESCR.REG_ANY)}]")
|
||||
va += 0x1000
|
||||
|
||||
def ProtectKernelRO():
|
||||
"""把内核镜像 .rodata 段(字符串常量/vtable 等)映射为只读
|
||||
|
||||
地址经 c.Asm 内联引用链接器符号 __rodata_start/__rodata_end
|
||||
(linker.ld 定义,TPV 不声明 extern——避免生成定义与链接器符号冲突)。
|
||||
"""
|
||||
global pml4
|
||||
if not pml4: return
|
||||
# 页表页可写已在 paging.init(WP=0 阶段)由 MakePTWritable 完成,
|
||||
# 此处只保护 .rodata 内容页(WP=1 后写只读页即 #PF 暴露写源)。
|
||||
ro_start: t.CUInt64T = 0
|
||||
ro_end: t.CUInt64T = 0
|
||||
c.Asm(f"""lea rax, [rip + __rodata_start]
|
||||
mov {c.AsmOut(ro_start, t.ASM_DESCR.OUTPUT_REG)}, rax
|
||||
lea rax, [rip + __rodata_end]
|
||||
mov {c.AsmOut(ro_end, t.ASM_DESCR.OUTPUT_REG)}, rax""",
|
||||
op=[t.ASM_DESCR.CLOBBER_RAX])
|
||||
MakeRangeRO(ro_start, ro_end)
|
||||
# [PG] 打印 .rodata 起始页映射:确认只读真正生效。
|
||||
# ps=1 说明仍在 2MB 大页(分裂失败)→ .rodata 保持可写 → 越界写继续被静默吞掉。
|
||||
DumpMapping(ro_start, "ro_s")
|
||||
|
||||
def DumpMapping(va: t.CUInt64T, tag: t.CConst | str):
|
||||
"""[PG] 打印指定 VA 的 pml4/pdp/pd/pt 条目,定位大页(PS)与权限位
|
||||
|
||||
内核区域若为 UEFI 2MB 大页,MakeRangeRO 无法只读 .rodata(越界写静默破坏
|
||||
格式串);1GB 页同理(PS 位在 pdpe)。W=1 且 PS=1 → 该页可写且是大页。
|
||||
"""
|
||||
global pml4
|
||||
if not pml4: return
|
||||
pml4_i: t.CUInt64T = (va >> 39) & 0x1FF
|
||||
pdp_i: t.CUInt64T = (va >> 30) & 0x1FF
|
||||
pd_i: t.CUInt64T = (va >> 21) & 0x1FF
|
||||
pt_i: t.CUInt64T = (va >> 12) & 0x1FF
|
||||
pml4_e: t.CUInt64T = pml4.entries[pml4_i]
|
||||
pdp_e: t.CUInt64T = 0
|
||||
pd_e: t.CUInt64T = 0
|
||||
pt_e: t.CUInt64T = 0
|
||||
if pml4_e & PTE_PRESENT:
|
||||
pdp_r: _p | t.CPtr = t.CType(pml4_e & ~t.CUInt64T(0xFFF), _p, t.CPtr)
|
||||
pdp_e = pdp_r.entries[pdp_i]
|
||||
if pdp_e & PTE_PRESENT:
|
||||
if pdp_e & PTE_PS:
|
||||
pd_e = pdp_e
|
||||
else:
|
||||
pd_r: _p | t.CPtr = t.CType(pdp_e & ~t.CUInt64T(0xFFF), _p, t.CPtr)
|
||||
pd_e = pd_r.entries[pd_i]
|
||||
if (pd_e & PTE_PRESENT) and not (pd_e & PTE_PS):
|
||||
pt_r: _p | t.CPtr = t.CType(pd_e & ~t.CUInt64T(0xFFF), _p, t.CPtr)
|
||||
pt_e = pt_r.entries[pt_i]
|
||||
buf_d: t.CArray[t.CChar, 200]
|
||||
viperlib.snprintf(c.Addr(buf_d), 200, "[PG] %s va=0x%lx pdpe=0x%lx pde=0x%lx pte=0x%lx (ps=%d W=%d)\n",
|
||||
tag, va, pdp_e, pd_e, pt_e,
|
||||
1 if (pd_e & PTE_PS) else 0,
|
||||
1 if (pt_e & PTE_WRITABLE) or (pd_e & PTE_WRITABLE) or (pdp_e & PTE_WRITABLE) else 0)
|
||||
serial.puts(c.Addr(buf_d))
|
||||
|
||||
def GetCurrentPml4() -> _p | t.CPtr:
|
||||
global pml4, pdp, pd, pt
|
||||
cr3: t.CUInt64T
|
||||
c.Asm(f"mov {c.AsmOut(cr3, t.ASM_DESCR.OUTPUT_REG)}, cr3")
|
||||
return (_p | t.CPtr)(cr3 & ~t.CUInt64T(0xFFF))
|
||||
|
||||
def create_process_page_table() -> t.CUInt64T:
|
||||
global pml4
|
||||
if not pml4: return 0
|
||||
new_pml4: _p | t.CPtr = AllocPage()
|
||||
if not new_pml4: return 0
|
||||
i: t.CUInt64T
|
||||
for i in range(512):
|
||||
entry: t.CUInt64T = pml4.entries[i]
|
||||
if entry & PTE_PRESENT:
|
||||
new_pml4.entries[i] = entry
|
||||
return t.CUInt64T(new_pml4)
|
||||
|
||||
def clone_for_process(isolate_vaddr: t.CUInt64T) -> t.CUInt64T:
|
||||
global pml4
|
||||
_dbg: t.CArray[t.CChar, 120]
|
||||
viperlib.snprintf(c.Addr(_dbg), 120, "[clone] pml4=0x%lx pool_used=%lu iso_va=0x%lx\n", t.CUInt64T(pml4), pt_pool_used, isolate_vaddr)
|
||||
serial.puts(_dbg)
|
||||
if not pml4: return 0
|
||||
new_pml4_page: _p | t.CPtr = AllocPage()
|
||||
if not new_pml4_page:
|
||||
# [DIAG] 定位 AllocPage 失败:pool_used 打印 0 但分配失败 → BSS 全局
|
||||
# (pt_pool_raw/pt_pool_used)疑似被内存越界写覆盖。
|
||||
_dbgf: t.CArray[t.CChar, 120]
|
||||
viperlib.snprintf(c.Addr(_dbgf), 120, "[clone] AllocPage FAIL raw=0x%lx used=%lu PP=%d\n",
|
||||
t.CUInt64T(pt_pool_raw), pt_pool_used, PT_POOL_PAGES)
|
||||
serial.puts(c.Addr(_dbgf))
|
||||
serial.puts("[clone] AllocPage pml4 failed\n")
|
||||
return 0
|
||||
_dbg2: t.CArray[t.CChar, 120]
|
||||
viperlib.snprintf(c.Addr(_dbg2), 120, "[clone] new_pml4=0x%lx\n", t.CUInt64T(new_pml4_page))
|
||||
serial.puts(_dbg2)
|
||||
i: t.CUInt64T
|
||||
for i in range(512):
|
||||
new_pml4_page.entries[i] = pml4.entries[i]
|
||||
pml4_idx: t.CUInt64T = (isolate_vaddr >> 39) & 0x1FF
|
||||
_dbg3: t.CArray[t.CChar, 120]
|
||||
viperlib.snprintf(c.Addr(_dbg3), 120, "[clone] pml4_idx=%lu entry0=0x%lx\n", pml4_idx, pml4.entries[pml4_idx])
|
||||
serial.puts(_dbg3)
|
||||
if not (pml4.entries[pml4_idx] & PTE_PRESENT): return t.CUInt64T(new_pml4_page)
|
||||
kernel_pdp: _p | t.CPtr = t.CType(pml4.entries[pml4_idx] & ~t.CUInt64T(0xFFF), _p, t.CPtr)
|
||||
new_pdp_page: _p | t.CPtr = AllocPage()
|
||||
if not new_pdp_page: return t.CUInt64T(new_pml4_page)
|
||||
for i in range(512):
|
||||
new_pdp_page.entries[i] = kernel_pdp.entries[i]
|
||||
new_pml4_page.entries[pml4_idx] = (t.CUInt64T(new_pdp_page) & ~t.CUInt64T(0xFFF)) | (pml4.entries[pml4_idx] & t.CUInt64T(0xFFF))
|
||||
pdp_idx: t.CUInt64T = (isolate_vaddr >> 30) & 0x1FF
|
||||
if not (kernel_pdp.entries[pdp_idx] & PTE_PRESENT): return t.CUInt64T(new_pml4_page)
|
||||
kernel_pd: _p | t.CPtr = t.CType(kernel_pdp.entries[pdp_idx] & ~t.CUInt64T(0xFFF), _p, t.CPtr)
|
||||
new_pd_page: _p | t.CPtr = AllocPage()
|
||||
if not new_pd_page: return t.CUInt64T(new_pml4_page)
|
||||
for i in range(512):
|
||||
new_pd_page.entries[i] = kernel_pd.entries[i]
|
||||
new_pdp_page.entries[pdp_idx] = (t.CUInt64T(new_pd_page) & ~t.CUInt64T(0xFFF)) | (kernel_pdp.entries[pdp_idx] & t.CUInt64T(0xFFF))
|
||||
pd_idx: t.CUInt64T = (isolate_vaddr >> 21) & 0x1FF
|
||||
if not (kernel_pd.entries[pd_idx] & PTE_PRESENT): return t.CUInt64T(new_pml4_page)
|
||||
if kernel_pd.entries[pd_idx] & PTE_PS: return t.CUInt64T(new_pml4_page)
|
||||
kernel_pt: _p | t.CPtr = t.CType(kernel_pd.entries[pd_idx] & ~t.CUInt64T(0xFFF), _p, t.CPtr)
|
||||
new_pt_page: _p | t.CPtr = AllocPage()
|
||||
if not new_pt_page: return t.CUInt64T(new_pml4_page)
|
||||
for i in range(512):
|
||||
new_pt_page.entries[i] = kernel_pt.entries[i]
|
||||
new_pd_page.entries[pd_idx] = (t.CUInt64T(new_pt_page) & ~t.CUInt64T(0xFFF)) | (kernel_pd.entries[pd_idx] & t.CUInt64T(0xFFF))
|
||||
return t.CUInt64T(new_pml4_page)
|
||||
|
||||
def save_pt_range(vaddr_start: t.CUInt64T, vaddr_end: t.CUInt64T, save_buf: t.CUInt64T | t.CPtr, save_count: t.CUInt32T | t.CPtr) -> t.CInt:
|
||||
global pml4
|
||||
if not pml4: return -1
|
||||
# c.Set(a,b)=a=b(改指针变量本身);写所指地址必须 c.Set(c.Deref(a),b)
|
||||
c.Set(c.Deref(save_count), t.CUInt32T(0))
|
||||
va: t.CUInt64T = vaddr_start & ~t.CUInt64T(0xFFF)
|
||||
while va < vaddr_end:
|
||||
pml4_idx: t.CUInt64T = (va >> 39) & 0x1FF
|
||||
if not (pml4.entries[pml4_idx] & PTE_PRESENT): va += 0x1000; continue
|
||||
pdp_: _p | t.CPtr = t.CType(pml4.entries[pml4_idx] & ~t.CUInt64T(0xFFF), _p, t.CPtr)
|
||||
pdp_idx: t.CUInt64T = (va >> 30) & 0x1FF
|
||||
if not (pdp_.entries[pdp_idx] & PTE_PRESENT): va += 0x1000; continue
|
||||
pd_: _p | t.CPtr = t.CType(pdp_.entries[pdp_idx] & ~t.CUInt64T(0xFFF), _p, t.CPtr)
|
||||
pd_idx: t.CUInt64T = (va >> 21) & 0x1FF
|
||||
if not (pd_.entries[pd_idx] & PTE_PRESENT): va += 0x1000; continue
|
||||
if pd_.entries[pd_idx] & PTE_PS: va += 0x200000; continue
|
||||
pt_: _p | t.CPtr = t.CType(pd_.entries[pd_idx] & ~t.CUInt64T(0xFFF), _p, t.CPtr)
|
||||
pt_idx: t.CUInt64T = (va >> 12) & 0x1FF
|
||||
saved: t.CUInt32T = c.DerefAs(save_count)
|
||||
entry_ptr: t.CUInt64T | t.CPtr = save_buf + t.CUInt64T(saved) * 16
|
||||
c.DerefAs(entry_ptr, va)
|
||||
c.DerefAs(entry_ptr + 8, pt_.entries[pt_idx])
|
||||
c.Set(c.Deref(save_count), t.CUInt32T(saved + 1))
|
||||
va += 0x1000
|
||||
return 0
|
||||
|
||||
def restore_pt_range(save_buf: t.CUInt64T | t.CPtr, save_count: t.CUInt32T):
|
||||
global pml4
|
||||
if not pml4: return
|
||||
i: t.CUInt32T = 0
|
||||
while i < save_count:
|
||||
entry_ptr: t.CUInt64T | t.CPtr = save_buf + t.CUInt64T(i) * 16
|
||||
va: t.CUInt64T = c.DerefAs(entry_ptr)
|
||||
orig_pte: t.CUInt64T = c.DerefAs(entry_ptr + 8)
|
||||
pml4_idx: t.CUInt64T = (va >> 39) & 0x1FF
|
||||
if not (pml4.entries[pml4_idx] & PTE_PRESENT): i += 1; continue
|
||||
pdp_: _p | t.CPtr = t.CType(pml4.entries[pml4_idx] & ~t.CUInt64T(0xFFF), _p, t.CPtr)
|
||||
pdp_idx: t.CUInt64T = (va >> 30) & 0x1FF
|
||||
if not (pdp_.entries[pdp_idx] & PTE_PRESENT): i += 1; continue
|
||||
pd_: _p | t.CPtr = t.CType(pdp_.entries[pdp_idx] & ~t.CUInt64T(0xFFF), _p, t.CPtr)
|
||||
pd_idx: t.CUInt64T = (va >> 21) & 0x1FF
|
||||
if not (pd_.entries[pd_idx] & PTE_PRESENT): i += 1; continue
|
||||
if pd_.entries[pd_idx] & PTE_PS: i += 1; continue
|
||||
pt_: _p | t.CPtr = t.CType(pd_.entries[pd_idx] & ~t.CUInt64T(0xFFF), _p, t.CPtr)
|
||||
pt_idx: t.CUInt64T = (va >> 12) & 0x1FF
|
||||
pt_.entries[pt_idx] = orig_pte
|
||||
c.Asm(f"invlpg [{c.AsmInp(va, t.ASM_DESCR.REG_ANY)}]", op=[t.ASM_DESCR.CLOBBER_MEMORY])
|
||||
i += 1
|
||||
|
||||
def set_active_pml4(cr3_val: t.CUInt64T):
|
||||
global pml4
|
||||
pml4 = (_p | t.CPtr)(cr3_val & ~t.CUInt64T(0xFFF))
|
||||
import drivers.serial.uart.serial as serial
|
||||
import viperlib
|
||||
import t, c
|
||||
|
||||
|
||||
PTE_PRESENT: t.CDefine = (1 << 0)
|
||||
PTE_WRITABLE: t.CDefine = (1 << 1)
|
||||
PTE_USER: t.CDefine = (1 << 2)
|
||||
PTE_PWT: t.CDefine = (1 << 3)
|
||||
PTE_PCD: t.CDefine = (1 << 4)
|
||||
PTE_ACCESSED: t.CDefine = (1 << 5)
|
||||
PTE_DIRTY: t.CDefine = (1 << 6)
|
||||
PTE_PS: t.CDefine = (1 << 7)
|
||||
PTE_GLOBAL: t.CDefine = (1 << 8)
|
||||
|
||||
class _p:
|
||||
entries: t.CArray[uint64, 512]
|
||||
|
||||
PT_POOL_PAGES: t.CDefine = 512
|
||||
pt_pool_raw: t.CPtr = None
|
||||
pt_pool_start: uint64 = 0
|
||||
pt_pool_used: uint64 = 0
|
||||
|
||||
AllocatedPages: uint64 = 0
|
||||
pml4: _p | t.CPtr = None
|
||||
pdp: _p | t.CPtr
|
||||
pd: _p | t.CPtr
|
||||
pt: _p | t.CPtr
|
||||
|
||||
def init(MemmapAddr: uint64, MemmapSize: uint64):
|
||||
global pml4
|
||||
pml4 = GetCurrentPml4()
|
||||
# bootloader/UEFI 的 CR0.WP 通常已是 1(原代码清 WP 正因此)。页表页
|
||||
# (pml4/pdp/pd/pt,0xf8xxxx)默认只读,而内核运行时 MapPage/clone 需
|
||||
# 修改页表。顺序:先清 WP(允许写只读页表页)→ MakePTWritable 放开
|
||||
# 全部页表页 → 再置 WP=1(此后写只读页即 #PF 暴露越界写源)。
|
||||
c.Asm(f"""
|
||||
mov rax, cr0
|
||||
and rax, ~0x10000
|
||||
mov cr0, rax
|
||||
""")
|
||||
MakePTWritable()
|
||||
c.Asm(f"""
|
||||
mov rax, cr0
|
||||
or rax, 0x10000
|
||||
mov cr0, rax
|
||||
""")
|
||||
|
||||
def init_pool(buf: t.CPtr, buf_size: uint64):
|
||||
global pt_pool_raw, pt_pool_start, pt_pool_used
|
||||
pt_pool_raw = buf
|
||||
if buf is None: return
|
||||
raw_addr: uint64 = uint64(buf)
|
||||
aligned_addr: uint64 = (raw_addr + uint64(0xFFF)) & ~uint64(0xFFF)
|
||||
pt_pool_start = aligned_addr
|
||||
pt_pool_used = 0
|
||||
# [DIAG] 定位 clone 时 pt_pool_raw=0x0(init 后被覆盖?还是 init 收到 0)
|
||||
_dip: t.CArray[t.CChar, 80]
|
||||
viperlib.snprintf(c.Addr(_dip), 80, "[paging] init_pool raw=0x%lx start=0x%lx\n", uint64(pt_pool_raw), pt_pool_start)
|
||||
serial.puts(c.Addr(_dip))
|
||||
|
||||
def AllocPage() -> t.CPtr:
|
||||
global AllocatedPages, pt_pool_used, pml4, pdp, pd, pt
|
||||
if pt_pool_raw is None: return None
|
||||
if pt_pool_used >= uint64(PT_POOL_PAGES): return None
|
||||
page: t.CPtr = t.CVoid(pt_pool_start + pt_pool_used * uint64(4096), t.CPtr)
|
||||
pt_pool_used = pt_pool_used + uint64(1)
|
||||
c.Asm(f"""mov al, 0
|
||||
mov ecx, 4096
|
||||
mov rdi, {c.AsmInp(page, t.ASM_DESCR.REG_ANY)}
|
||||
rep stosb""",
|
||||
op = [t.ASM_DESCR.CLOBBER_AL, t.ASM_DESCR.CLOBBER_ECX, t.ASM_DESCR.CLOBBER_RDI])
|
||||
AllocatedPages = AllocatedPages + uint64(1)
|
||||
return page
|
||||
|
||||
def FreePage(page: t.CPtr):
|
||||
global AllocatedPages, pml4, pdp, pd, pt
|
||||
if page is None: return
|
||||
if AllocatedPages > 0: AllocatedPages = AllocatedPages - uint64(1)
|
||||
|
||||
def MapPage(VirtAddr: uint64, PhysAddr: uint64, flags: uint64):
|
||||
global pml4, pdp, pd, pt
|
||||
if VirtAddr == 0 or PhysAddr == 0: return
|
||||
VirtAddr = VirtAddr & ~uint64(0xFFF)
|
||||
PhysAddr = PhysAddr & ~uint64(0xFFF)
|
||||
Pml4Index: uint64 = (VirtAddr >> 39) & 0x1FF
|
||||
PdpIndex: uint64 = (VirtAddr >> 30) & 0x1FF
|
||||
PdIndex: uint64 = (VirtAddr >> 21) & 0x1FF
|
||||
PtIndex: uint64 = (VirtAddr >> 12) & 0x1FF
|
||||
|
||||
if not pml4:
|
||||
pml4 = AllocPage()
|
||||
if not pml4: return
|
||||
|
||||
if not (pml4.entries[Pml4Index] & PTE_PRESENT):
|
||||
pdp: _p | t.CPtr = AllocPage()
|
||||
if not pdp: return
|
||||
pml4.entries[Pml4Index] = (uint64(pdp) & ~uint64(0xFFF)) | PTE_PRESENT | PTE_WRITABLE | (flags & PTE_USER)
|
||||
else:
|
||||
if (flags & PTE_USER) and not (pml4.entries[Pml4Index] & PTE_USER):
|
||||
pml4.entries[Pml4Index] = pml4.entries[Pml4Index] | PTE_USER
|
||||
pdp: _p | t.CPtr = t.CType(pml4.entries[Pml4Index] & ~uint64(0xFFF), _p, t.CPtr)
|
||||
|
||||
if not (pdp.entries[PdpIndex] & PTE_PRESENT):
|
||||
pd: _p | t.CPtr = AllocPage()
|
||||
if not pd: return
|
||||
pdp.entries[PdpIndex] = (uint64(pd) & ~uint64(0xFFF)) | PTE_PRESENT | PTE_WRITABLE | (flags & PTE_USER)
|
||||
else:
|
||||
if (flags & PTE_USER) and not (pdp.entries[PdpIndex] & PTE_USER):
|
||||
pdp.entries[PdpIndex] = pdp.entries[PdpIndex] | PTE_USER
|
||||
pd: _p | t.CPtr = t.CType(pdp.entries[PdpIndex] & ~uint64(0xFFF), _p, t.CPtr)
|
||||
|
||||
if pd.entries[PdIndex] & 1:
|
||||
if pd.entries[PdIndex] & 0x80:
|
||||
big_phys: uint64 = pd.entries[PdIndex] & ~uint64(0x1FFFFF)
|
||||
inherit_flags: uint64 = pd.entries[PdIndex] & (PTE_PCD | PTE_PWT)
|
||||
pt: _p | t.CPtr = AllocPage()
|
||||
if not pt: return
|
||||
split_i: int = 0
|
||||
while split_i < 512:
|
||||
pt.entries[split_i] = (big_phys + uint64(split_i) * 0x1000) | PTE_PRESENT | PTE_WRITABLE | inherit_flags
|
||||
split_i += 1
|
||||
pd.entries[PdIndex] = (uint64(pt) & ~uint64(0xFFF)) | PTE_PRESENT | PTE_WRITABLE | (flags & PTE_USER)
|
||||
else:
|
||||
# PD entry exists as a regular PT (e.g. cloned identity mapping).
|
||||
# Must propagate PTE_USER to the PD entry so user-mode access is
|
||||
# allowed at all paging levels, otherwise #PF err=0x5.
|
||||
if (flags & PTE_USER) and not (pd.entries[PdIndex] & PTE_USER):
|
||||
pd.entries[PdIndex] = pd.entries[PdIndex] | PTE_USER
|
||||
else:
|
||||
pt: _p | t.CPtr = AllocPage()
|
||||
if not pt: return
|
||||
pd.entries[PdIndex] = (uint64(pt) & ~uint64(0xFFF)) | PTE_PRESENT | PTE_WRITABLE | (flags & PTE_USER)
|
||||
pt: _p | t.CPtr = t.CType(pd.entries[PdIndex] & ~uint64(0xFFF), _p, t.CPtr)
|
||||
|
||||
pt.entries[PtIndex] = PhysAddr | flags | PTE_PRESENT
|
||||
c.Asm(f"invlpg [{c.AsmInp(VirtAddr, t.ASM_DESCR.REG_ANY)}]")
|
||||
|
||||
def MapLargePage(VirtAddr: uint64, PhysAddr: uint64, flags: uint64) -> t.CVoid:
|
||||
global pml4, pdp, pd, pt
|
||||
VirtAddr = VirtAddr & ~uint64(0x1FFFFF)
|
||||
PhysAddr = PhysAddr & ~uint64(0x1FFFFF)
|
||||
Pml4Index: uint64 = (VirtAddr >> 39) & 0x1FF
|
||||
PdpIndex: uint64 = (VirtAddr >> 30) & 0x1FF
|
||||
PdIndex: uint64 = (VirtAddr >> 21) & 0x1FF
|
||||
|
||||
if not pml4:
|
||||
pml4 = AllocPage()
|
||||
if not pml4: return
|
||||
|
||||
if not pml4.entries[Pml4Index] & PTE_PRESENT:
|
||||
pdp: _p | t.CPtr = AllocPage()
|
||||
if not pdp: return
|
||||
pml4.entries[Pml4Index] = (uint64(pdp) & ~uint64(0xFFF)) | PTE_PRESENT | PTE_WRITABLE
|
||||
pdp: _p | t.CPtr = t.CType(pml4.entries[Pml4Index] & ~uint64(0xFFF), _p, t.CPtr)
|
||||
|
||||
if not (pdp.entries[PdpIndex] & PTE_PRESENT):
|
||||
pd: _p | t.CPtr = AllocPage()
|
||||
if not pd: return
|
||||
pdp.entries[PdpIndex] = (uint64(pd) & ~uint64(0xFFF)) | PTE_PRESENT | PTE_WRITABLE
|
||||
pd: _p | t.CPtr = t.CType(pdp.entries[PdpIndex] & ~uint64(0xFFF), _p, t.CPtr)
|
||||
|
||||
pd.entries[PdIndex] = PhysAddr | flags | PTE_PRESENT | PTE_PS
|
||||
c.Asm(f"invlpg [{c.AsmInp(VirtAddr, t.ASM_DESCR.REG_ANY)}]")
|
||||
|
||||
def UnMapPage(VirtAddr: uint64):
|
||||
global pml4, pdp, pd, pt
|
||||
if VirtAddr == 0: return
|
||||
if not pml4: return
|
||||
Pml4Index: uint64 = (VirtAddr >> 39) & 0x1FF
|
||||
PdpIndex: uint64 = (VirtAddr >> 30) & 0x1FF
|
||||
PdIndex: uint64 = (VirtAddr >> 21) & 0x1FF
|
||||
PtIndex: uint64 = (VirtAddr >> 12) & 0x1FF
|
||||
|
||||
if not pml4.entries[Pml4Index] & PTE_PRESENT: return
|
||||
|
||||
pdp: _p | t.CPtr = t.CType(pml4.entries[Pml4Index] & ~uint64(0xFFF), _p, t.CPtr)
|
||||
if not pdp.entries[PdpIndex] & PTE_PRESENT: return
|
||||
|
||||
pd: _p | t.CPtr = t.CType(pdp.entries[PdpIndex] & ~uint64(0xFFF), _p, t.CPtr)
|
||||
|
||||
if not pd.entries[PdIndex] & PTE_PRESENT: return
|
||||
|
||||
if pd.entries[PdIndex] & PTE_PS:
|
||||
pd.entries[PdIndex] = 0
|
||||
else:
|
||||
pt: _p | t.CPtr = t.CType(pd.entries[PdIndex] & ~uint64(0xFFF), _p, t.CPtr)
|
||||
pt.entries[PtIndex] = 0
|
||||
|
||||
c.Asm(f"invlpg [{c.AsmInp(VirtAddr, t.ASM_DESCR.REG_ANY)}]")
|
||||
|
||||
def EnablePaging():
|
||||
global pml4, pdp, pd, pt
|
||||
c.Asm(f"mov cr3, {c.AsmInp(uint64(pml4), t.ASM_DESCR.REG_ANY)}")
|
||||
|
||||
def _set_page_writable(phys_addr: uint64):
|
||||
"""把物理页 phys_addr(identity 映射,虚拟=物理)的 PTE 置 W 位
|
||||
|
||||
页表页(bootloader 建立的 pml4/pdp/pd/pt 位于 0xf8xxxx)默认只读,
|
||||
而内核运行时 MapPage/clone 需修改页表 → 必须先把这些页表页自身设为可写,
|
||||
否则 CR0.WP=1 下写页表触发 #PF(slog.so 映射 0x600000 新建页表项时
|
||||
cr2=0xf801000 err=0x3 根因)。
|
||||
"""
|
||||
global pml4
|
||||
if not pml4: return
|
||||
va: uint64 = phys_addr & ~uint64(0xFFF)
|
||||
pml4_idx: uint64 = (va >> 39) & 0x1FF
|
||||
if not (pml4.entries[pml4_idx] & PTE_PRESENT): return
|
||||
pdp_s: _p | t.CPtr = t.CType(pml4.entries[pml4_idx] & ~uint64(0xFFF), _p, t.CPtr)
|
||||
pdp_idx: uint64 = (va >> 30) & 0x1FF
|
||||
if not (pdp_s.entries[pdp_idx] & PTE_PRESENT): return
|
||||
pd_s: _p | t.CPtr = t.CType(pdp_s.entries[pdp_idx] & ~uint64(0xFFF), _p, t.CPtr)
|
||||
pd_idx: uint64 = (va >> 21) & 0x1FF
|
||||
if not (pd_s.entries[pd_idx] & PTE_PRESENT): return
|
||||
if pd_s.entries[pd_idx] & PTE_PS:
|
||||
# 2MB 大页:W 位在 PD 条目自身(无下层 PT),直接置位
|
||||
pd_s.entries[pd_idx] = pd_s.entries[pd_idx] | uint64(PTE_WRITABLE)
|
||||
c.Asm(f"invlpg [{c.AsmInp(va, t.ASM_DESCR.REG_ANY)}]")
|
||||
return
|
||||
pt_s: _p | t.CPtr = t.CType(pd_s.entries[pd_idx] & ~uint64(0xFFF), _p, t.CPtr)
|
||||
pt_idx: uint64 = (va >> 12) & 0x1FF
|
||||
pt_s.entries[pt_idx] = pt_s.entries[pt_idx] | uint64(PTE_WRITABLE)
|
||||
c.Asm(f"invlpg [{c.AsmInp(va, t.ASM_DESCR.REG_ANY)}]")
|
||||
|
||||
def MakePTWritable():
|
||||
"""把当前页表层次所有页表页(pml4 自身 + pdp/pd/pt)设为可写
|
||||
|
||||
内核运行时需修改页表(MapPage/clone_for_process),而 bootloader 建立的
|
||||
页表页映射为只读——CR0.WP=1 下必须先放开页表页自身,否则写页表即 #PF。
|
||||
"""
|
||||
global pml4
|
||||
if not pml4: return
|
||||
_set_page_writable(uint64(pml4))
|
||||
pi: uint64
|
||||
for pi in range(512):
|
||||
if not (pml4.entries[pi] & PTE_PRESENT): continue
|
||||
pdp_m: _p | t.CPtr = t.CType(pml4.entries[pi] & ~uint64(0xFFF), _p, t.CPtr)
|
||||
_set_page_writable(uint64(pdp_m))
|
||||
pj: uint64
|
||||
for pj in range(512):
|
||||
if not (pdp_m.entries[pj] & PTE_PRESENT): continue
|
||||
pd_m: _p | t.CPtr = t.CType(pdp_m.entries[pj] & ~uint64(0xFFF), _p, t.CPtr)
|
||||
_set_page_writable(uint64(pd_m))
|
||||
pk: uint64
|
||||
for pk in range(512):
|
||||
if not (pd_m.entries[pk] & PTE_PRESENT): continue
|
||||
if pd_m.entries[pk] & PTE_PS: continue
|
||||
pt_m: _p | t.CPtr = t.CType(pd_m.entries[pk] & ~uint64(0xFFF), _p, t.CPtr)
|
||||
_set_page_writable(uint64(pt_m))
|
||||
|
||||
def MakeRangeRO(vaddr_start: uint64, vaddr_end: uint64):
|
||||
"""把 [vaddr_start, vaddr_end) 范围内所有页的 PTE 清 W 位(只读)
|
||||
|
||||
定位越界写源:内核态写只读页在 CR0.WP=1 下触发 #PF(int=14),
|
||||
isrCommonhandler 打印 cr2/rip → 写源立即暴露,不再静默破坏 .rodata。
|
||||
"""
|
||||
global pml4
|
||||
if not pml4: return
|
||||
va: uint64 = vaddr_start & ~uint64(0xFFF)
|
||||
# ro_end 下取整到页:不保护含 ro_end 的未对齐尾页。链接脚本输出段未页对齐,
|
||||
# .data 紧跟 .rodata(__rodata_end 未对齐时 .data 起始落在 rodata 尾页内),
|
||||
# 整页置只读会把 .data 全局(如 devfs @DevFSObject=0x141630)误保护 →
|
||||
# devfs_init 写全局 #PF(cr2=0x141630 rip=0x101aaa mov [r15],rax 根因)。
|
||||
# 尾页含少量 rodata 尾部(对齐填充),保持可写可容忍。
|
||||
ro_end_align: uint64 = vaddr_end & ~uint64(0xFFF)
|
||||
while va < ro_end_align:
|
||||
pml4_idx: uint64 = (va >> 39) & 0x1FF
|
||||
if not (pml4.entries[pml4_idx] & PTE_PRESENT): va += 0x1000; continue
|
||||
pdp_r: _p | t.CPtr = t.CType(pml4.entries[pml4_idx] & ~uint64(0xFFF), _p, t.CPtr)
|
||||
pdp_idx: uint64 = (va >> 30) & 0x1FF
|
||||
if not (pdp_r.entries[pdp_idx] & PTE_PRESENT): va += 0x1000; continue
|
||||
pd_r: _p | t.CPtr = t.CType(pdp_r.entries[pdp_idx] & ~uint64(0xFFF), _p, t.CPtr)
|
||||
pd_idx: uint64 = (va >> 21) & 0x1FF
|
||||
if not (pd_r.entries[pd_idx] & PTE_PRESENT): va += 0x1000; continue
|
||||
if pd_r.entries[pd_idx] & PTE_PS:
|
||||
# 2MB 大页:直接跳过会让 .rodata 保持可写——越界写被静默吞掉
|
||||
# (perf 格式串 win=%lu/work=%lu 被逐步破坏的根因)。拆分为 512
|
||||
# 个 4KB 页(复用 MapPage 的分裂逻辑),再走下方常规路径清 W 位。
|
||||
# WP=1 后内核态写只读页即 #PF → isrCommonhandler 打印 cr2/rip 暴露写源。
|
||||
big_phys: uint64 = pd_r.entries[pd_idx] & ~uint64(0x1FFFFF)
|
||||
inherit_flags: uint64 = pd_r.entries[pd_idx] & (PTE_PCD | PTE_PWT | PTE_USER | uint64(0x8000000000000000))
|
||||
pt_split: _p | t.CPtr = AllocPage()
|
||||
if not pt_split:
|
||||
va += 0x1000
|
||||
continue
|
||||
split_i: int = 0
|
||||
while split_i < 512:
|
||||
pt_split.entries[split_i] = (big_phys + uint64(split_i) * uint64(0x1000)) \
|
||||
| PTE_PRESENT | PTE_WRITABLE | inherit_flags
|
||||
split_i += 1
|
||||
pd_r.entries[pd_idx] = (uint64(pt_split) & ~uint64(0xFFF)) \
|
||||
| PTE_PRESENT | PTE_WRITABLE | (pd_r.entries[pd_idx] & PTE_USER)
|
||||
c.Asm(f"invlpg [{c.AsmInp(va, t.ASM_DESCR.REG_ANY)}]")
|
||||
# 分裂后落入下方 4KB 常规路径,继续清当前页 W 位
|
||||
pt_r: _p | t.CPtr = t.CType(pd_r.entries[pd_idx] & ~uint64(0xFFF), _p, t.CPtr)
|
||||
pt_idx: uint64 = (va >> 12) & 0x1FF
|
||||
pt_r.entries[pt_idx] = pt_r.entries[pt_idx] & ~uint64(PTE_WRITABLE)
|
||||
c.Asm(f"invlpg [{c.AsmInp(va, t.ASM_DESCR.REG_ANY)}]")
|
||||
va += 0x1000
|
||||
|
||||
def ProtectKernelRO():
|
||||
"""把内核镜像 .rodata 段(字符串常量/vtable 等)映射为只读
|
||||
|
||||
地址经 c.Asm 内联引用链接器符号 __rodata_start/__rodata_end
|
||||
(linker.ld 定义,TPV 不声明 extern——避免生成定义与链接器符号冲突)。
|
||||
"""
|
||||
global pml4
|
||||
if not pml4: return
|
||||
# 页表页可写已在 paging.init(WP=0 阶段)由 MakePTWritable 完成,
|
||||
# 此处只保护 .rodata 内容页(WP=1 后写只读页即 #PF 暴露写源)。
|
||||
ro_start: uint64 = 0
|
||||
ro_end: uint64 = 0
|
||||
c.Asm(f"""lea rax, [rip + __rodata_start]
|
||||
mov {c.AsmOut(ro_start, t.ASM_DESCR.OUTPUT_REG)}, rax
|
||||
lea rax, [rip + __rodata_end]
|
||||
mov {c.AsmOut(ro_end, t.ASM_DESCR.OUTPUT_REG)}, rax""",
|
||||
op=[t.ASM_DESCR.CLOBBER_RAX])
|
||||
MakeRangeRO(ro_start, ro_end)
|
||||
# [PG] 打印 .rodata 起始页映射:确认只读真正生效。
|
||||
# ps=1 说明仍在 2MB 大页(分裂失败)→ .rodata 保持可写 → 越界写继续被静默吞掉。
|
||||
DumpMapping(ro_start, "ro_s")
|
||||
|
||||
def DumpMapping(va: uint64, tag: t.CConst | str):
|
||||
"""[PG] 打印指定 VA 的 pml4/pdp/pd/pt 条目,定位大页(PS)与权限位
|
||||
|
||||
内核区域若为 UEFI 2MB 大页,MakeRangeRO 无法只读 .rodata(越界写静默破坏
|
||||
格式串);1GB 页同理(PS 位在 pdpe)。W=1 且 PS=1 → 该页可写且是大页。
|
||||
"""
|
||||
global pml4
|
||||
if not pml4: return
|
||||
pml4_i: uint64 = (va >> 39) & 0x1FF
|
||||
pdp_i: uint64 = (va >> 30) & 0x1FF
|
||||
pd_i: uint64 = (va >> 21) & 0x1FF
|
||||
pt_i: uint64 = (va >> 12) & 0x1FF
|
||||
pml4_e: uint64 = pml4.entries[pml4_i]
|
||||
pdp_e: uint64 = 0
|
||||
pd_e: uint64 = 0
|
||||
pt_e: uint64 = 0
|
||||
if pml4_e & PTE_PRESENT:
|
||||
pdp_r: _p | t.CPtr = t.CType(pml4_e & ~uint64(0xFFF), _p, t.CPtr)
|
||||
pdp_e = pdp_r.entries[pdp_i]
|
||||
if pdp_e & PTE_PRESENT:
|
||||
if pdp_e & PTE_PS:
|
||||
pd_e = pdp_e
|
||||
else:
|
||||
pd_r: _p | t.CPtr = t.CType(pdp_e & ~uint64(0xFFF), _p, t.CPtr)
|
||||
pd_e = pd_r.entries[pd_i]
|
||||
if (pd_e & PTE_PRESENT) and not (pd_e & PTE_PS):
|
||||
pt_r: _p | t.CPtr = t.CType(pd_e & ~uint64(0xFFF), _p, t.CPtr)
|
||||
pt_e = pt_r.entries[pt_i]
|
||||
buf_d: t.CArray[t.CChar, 200]
|
||||
viperlib.snprintf(c.Addr(buf_d), 200, "[PG] %s va=0x%lx pdpe=0x%lx pde=0x%lx pte=0x%lx (ps=%d W=%d)\n",
|
||||
tag, va, pdp_e, pd_e, pt_e,
|
||||
1 if (pd_e & PTE_PS) else 0,
|
||||
1 if (pt_e & PTE_WRITABLE) or (pd_e & PTE_WRITABLE) or (pdp_e & PTE_WRITABLE) else 0)
|
||||
serial.puts(c.Addr(buf_d))
|
||||
|
||||
def GetCurrentPml4() -> _p | t.CPtr:
|
||||
global pml4, pdp, pd, pt
|
||||
cr3: uint64
|
||||
c.Asm(f"mov {c.AsmOut(cr3, t.ASM_DESCR.OUTPUT_REG)}, cr3")
|
||||
return (_p | t.CPtr)(cr3 & ~uint64(0xFFF))
|
||||
|
||||
def create_process_page_table() -> uint64:
|
||||
global pml4
|
||||
if not pml4: return 0
|
||||
new_pml4: _p | t.CPtr = AllocPage()
|
||||
if not new_pml4: return 0
|
||||
i: uint64
|
||||
for i in range(512):
|
||||
entry: uint64 = pml4.entries[i]
|
||||
if entry & PTE_PRESENT:
|
||||
new_pml4.entries[i] = entry
|
||||
return uint64(new_pml4)
|
||||
|
||||
def clone_for_process(isolate_vaddr: uint64) -> uint64:
|
||||
global pml4
|
||||
_dbg: t.CArray[t.CChar, 120]
|
||||
viperlib.snprintf(c.Addr(_dbg), 120, "[clone] pml4=0x%lx pool_used=%lu iso_va=0x%lx\n", uint64(pml4), pt_pool_used, isolate_vaddr)
|
||||
serial.puts(_dbg)
|
||||
if not pml4: return 0
|
||||
new_pml4_page: _p | t.CPtr = AllocPage()
|
||||
if not new_pml4_page:
|
||||
# [DIAG] 定位 AllocPage 失败:pool_used 打印 0 但分配失败 → BSS 全局
|
||||
# (pt_pool_raw/pt_pool_used)疑似被内存越界写覆盖。
|
||||
_dbgf: t.CArray[t.CChar, 120]
|
||||
viperlib.snprintf(c.Addr(_dbgf), 120, "[clone] AllocPage FAIL raw=0x%lx used=%lu PP=%d\n",
|
||||
uint64(pt_pool_raw), pt_pool_used, PT_POOL_PAGES)
|
||||
serial.puts(c.Addr(_dbgf))
|
||||
serial.puts("[clone] AllocPage pml4 failed\n")
|
||||
return 0
|
||||
_dbg2: t.CArray[t.CChar, 120]
|
||||
viperlib.snprintf(c.Addr(_dbg2), 120, "[clone] new_pml4=0x%lx\n", uint64(new_pml4_page))
|
||||
serial.puts(_dbg2)
|
||||
i: uint64
|
||||
for i in range(512):
|
||||
new_pml4_page.entries[i] = pml4.entries[i]
|
||||
pml4_idx: uint64 = (isolate_vaddr >> 39) & 0x1FF
|
||||
_dbg3: t.CArray[t.CChar, 120]
|
||||
viperlib.snprintf(c.Addr(_dbg3), 120, "[clone] pml4_idx=%lu entry0=0x%lx\n", pml4_idx, pml4.entries[pml4_idx])
|
||||
serial.puts(_dbg3)
|
||||
if not (pml4.entries[pml4_idx] & PTE_PRESENT): return uint64(new_pml4_page)
|
||||
kernel_pdp: _p | t.CPtr = t.CType(pml4.entries[pml4_idx] & ~uint64(0xFFF), _p, t.CPtr)
|
||||
new_pdp_page: _p | t.CPtr = AllocPage()
|
||||
if not new_pdp_page: return uint64(new_pml4_page)
|
||||
for i in range(512):
|
||||
new_pdp_page.entries[i] = kernel_pdp.entries[i]
|
||||
new_pml4_page.entries[pml4_idx] = (uint64(new_pdp_page) & ~uint64(0xFFF)) | (pml4.entries[pml4_idx] & uint64(0xFFF))
|
||||
pdp_idx: uint64 = (isolate_vaddr >> 30) & 0x1FF
|
||||
if not (kernel_pdp.entries[pdp_idx] & PTE_PRESENT): return uint64(new_pml4_page)
|
||||
kernel_pd: _p | t.CPtr = t.CType(kernel_pdp.entries[pdp_idx] & ~uint64(0xFFF), _p, t.CPtr)
|
||||
new_pd_page: _p | t.CPtr = AllocPage()
|
||||
if not new_pd_page: return uint64(new_pml4_page)
|
||||
for i in range(512):
|
||||
new_pd_page.entries[i] = kernel_pd.entries[i]
|
||||
new_pdp_page.entries[pdp_idx] = (uint64(new_pd_page) & ~uint64(0xFFF)) | (kernel_pdp.entries[pdp_idx] & uint64(0xFFF))
|
||||
pd_idx: uint64 = (isolate_vaddr >> 21) & 0x1FF
|
||||
if not (kernel_pd.entries[pd_idx] & PTE_PRESENT): return uint64(new_pml4_page)
|
||||
if kernel_pd.entries[pd_idx] & PTE_PS: return uint64(new_pml4_page)
|
||||
kernel_pt: _p | t.CPtr = t.CType(kernel_pd.entries[pd_idx] & ~uint64(0xFFF), _p, t.CPtr)
|
||||
new_pt_page: _p | t.CPtr = AllocPage()
|
||||
if not new_pt_page: return uint64(new_pml4_page)
|
||||
for i in range(512):
|
||||
new_pt_page.entries[i] = kernel_pt.entries[i]
|
||||
new_pd_page.entries[pd_idx] = (uint64(new_pt_page) & ~uint64(0xFFF)) | (kernel_pd.entries[pd_idx] & uint64(0xFFF))
|
||||
return uint64(new_pml4_page)
|
||||
|
||||
def save_pt_range(vaddr_start: uint64, vaddr_end: uint64, save_buf: uint64 | t.CPtr, save_count: uint32 | t.CPtr) -> int:
|
||||
global pml4
|
||||
if not pml4: return -1
|
||||
# c.Set(a,b)=a=b(改指针变量本身);写所指地址必须 c.Set(c.Deref(a),b)
|
||||
c.Set(c.Deref(save_count), uint32(0))
|
||||
va: uint64 = vaddr_start & ~uint64(0xFFF)
|
||||
while va < vaddr_end:
|
||||
pml4_idx: uint64 = (va >> 39) & 0x1FF
|
||||
if not (pml4.entries[pml4_idx] & PTE_PRESENT): va += 0x1000; continue
|
||||
pdp_: _p | t.CPtr = t.CType(pml4.entries[pml4_idx] & ~uint64(0xFFF), _p, t.CPtr)
|
||||
pdp_idx: uint64 = (va >> 30) & 0x1FF
|
||||
if not (pdp_.entries[pdp_idx] & PTE_PRESENT): va += 0x1000; continue
|
||||
pd_: _p | t.CPtr = t.CType(pdp_.entries[pdp_idx] & ~uint64(0xFFF), _p, t.CPtr)
|
||||
pd_idx: uint64 = (va >> 21) & 0x1FF
|
||||
if not (pd_.entries[pd_idx] & PTE_PRESENT): va += 0x1000; continue
|
||||
if pd_.entries[pd_idx] & PTE_PS: va += 0x200000; continue
|
||||
pt_: _p | t.CPtr = t.CType(pd_.entries[pd_idx] & ~uint64(0xFFF), _p, t.CPtr)
|
||||
pt_idx: uint64 = (va >> 12) & 0x1FF
|
||||
saved: uint32 = c.DerefAs(save_count)
|
||||
entry_ptr: uint64 | t.CPtr = save_buf + uint64(saved) * 16
|
||||
c.DerefAs(entry_ptr, va)
|
||||
c.DerefAs(entry_ptr + 8, pt_.entries[pt_idx])
|
||||
c.Set(c.Deref(save_count), uint32(saved + 1))
|
||||
va += 0x1000
|
||||
return 0
|
||||
|
||||
def restore_pt_range(save_buf: uint64 | t.CPtr, save_count: uint32):
|
||||
global pml4
|
||||
if not pml4: return
|
||||
i: uint32 = 0
|
||||
while i < save_count:
|
||||
entry_ptr: uint64 | t.CPtr = save_buf + uint64(i) * 16
|
||||
va: uint64 = c.DerefAs(entry_ptr)
|
||||
orig_pte: uint64 = c.DerefAs(entry_ptr + 8)
|
||||
pml4_idx: uint64 = (va >> 39) & 0x1FF
|
||||
if not (pml4.entries[pml4_idx] & PTE_PRESENT): i += 1; continue
|
||||
pdp_: _p | t.CPtr = t.CType(pml4.entries[pml4_idx] & ~uint64(0xFFF), _p, t.CPtr)
|
||||
pdp_idx: uint64 = (va >> 30) & 0x1FF
|
||||
if not (pdp_.entries[pdp_idx] & PTE_PRESENT): i += 1; continue
|
||||
pd_: _p | t.CPtr = t.CType(pdp_.entries[pdp_idx] & ~uint64(0xFFF), _p, t.CPtr)
|
||||
pd_idx: uint64 = (va >> 21) & 0x1FF
|
||||
if not (pd_.entries[pd_idx] & PTE_PRESENT): i += 1; continue
|
||||
if pd_.entries[pd_idx] & PTE_PS: i += 1; continue
|
||||
pt_: _p | t.CPtr = t.CType(pd_.entries[pd_idx] & ~uint64(0xFFF), _p, t.CPtr)
|
||||
pt_idx: uint64 = (va >> 12) & 0x1FF
|
||||
pt_.entries[pt_idx] = orig_pte
|
||||
c.Asm(f"invlpg [{c.AsmInp(va, t.ASM_DESCR.REG_ANY)}]", op=[t.ASM_DESCR.CLOBBER_MEMORY])
|
||||
i += 1
|
||||
|
||||
def set_active_pml4(cr3_val: uint64):
|
||||
global pml4
|
||||
pml4 = (_p | t.CPtr)(cr3_val & ~uint64(0xFFF))
|
||||
+120
-120
@@ -1,120 +1,120 @@
|
||||
import asm
|
||||
import t, c
|
||||
|
||||
|
||||
# PIC端口定义
|
||||
PIC1_COMMAND: t.CDefine = 0x20
|
||||
PIC1_DATA: t.CDefine = 0x21
|
||||
PIC2_COMMAND: t.CDefine = 0xA0
|
||||
PIC2_DATA: t.CDefine = 0xA1
|
||||
|
||||
# ICW1 - 初始化命令字1
|
||||
ICW1_ICW4: t.CDefine = 0x01 # 需要ICW4
|
||||
ICW1_SINGLE: t.CDefine = 0x02 # 单级模式
|
||||
ICW1_INTERVAL4: t.CDefine = 0x04 # 间隔4字节
|
||||
ICW1_LEVEL: t.CDefine = 0x08 # 电平触发模式
|
||||
ICW1_INIT: t.CDefine = 0x10 # 初始化
|
||||
|
||||
# ICW4 - 初始化命令字4
|
||||
ICW4_8086: t.CDefine = 0x01 # 8086/88模式
|
||||
ICW4_AUTO: t.CDefine = 0x02 # 自动EOI
|
||||
ICW4_BUF_SLAVE: t.CDefine = 0x08 # 缓冲模式(从片)
|
||||
ICW4_BUF_MASTER: t.CDefine = 0x0C # 缓冲模式(主片)
|
||||
ICW4_SFNM: t.CDefine = 0x10 # 特殊全嵌套模式
|
||||
|
||||
# OCW2 - 操作命令字2
|
||||
OCW2_EOI: t.CDefine = 0x20 # 结束中断
|
||||
|
||||
# OCW3 - 操作命令字3
|
||||
OCW3_READ_ISR: t.CDefine = 0x0B # 读取中断服务寄存器(ISR)
|
||||
|
||||
# 初始化PIC
|
||||
def init():
|
||||
# 发送ICW1:开始初始化,需要ICW4
|
||||
asm.outb(PIC1_COMMAND, ICW1_INIT | ICW1_ICW4)
|
||||
asm.io_wait()
|
||||
asm.outb(PIC2_COMMAND, ICW1_INIT | ICW1_ICW4)
|
||||
asm.io_wait()
|
||||
|
||||
# 发送ICW2:中断向量偏移
|
||||
asm.outb(PIC1_DATA, 0x20) # IRQ0-7映射到0x20-0x27
|
||||
asm.io_wait()
|
||||
asm.outb(PIC2_DATA, 0x28) # IRQ8-15映射到0x28-0x2F
|
||||
asm.io_wait()
|
||||
|
||||
# 发送ICW3:级联信息
|
||||
asm.outb(PIC1_DATA, 0x04) # 主PIC的IRQ2连接从PIC
|
||||
asm.io_wait()
|
||||
asm.outb(PIC2_DATA, 0x02) # 从PIC连接到主PIC的IRQ2
|
||||
asm.io_wait()
|
||||
|
||||
# 发送ICW4:8086模式
|
||||
asm.outb(PIC1_DATA, ICW4_8086)
|
||||
asm.io_wait()
|
||||
asm.outb(PIC2_DATA, ICW4_8086)
|
||||
asm.io_wait()
|
||||
|
||||
# 设置初始屏蔽字:只启用IRQ0(定时器)、IRQ1(键盘)、IRQ2(级联)
|
||||
# 主PIC: 屏蔽所有除了IRQ0, IRQ1, IRQ2 (0xF8 = 11111000)
|
||||
# 从PIC: 屏蔽所有 (0xFF = 11111111),鼠标中断由驱动程序自己启用
|
||||
asm.outb(PIC1_DATA, 0xF8) # 启用IRQ0, IRQ1, IRQ2
|
||||
asm.io_wait()
|
||||
asm.outb(PIC2_DATA, 0xFF) # 屏蔽所有从PIC中断
|
||||
asm.io_wait()
|
||||
|
||||
# 发送EOI信号
|
||||
def eoi(irq: t.CUInt8T):
|
||||
if irq >= 8: asm.outb(PIC2_COMMAND, OCW2_EOI)
|
||||
asm.outb(PIC1_COMMAND, OCW2_EOI)
|
||||
|
||||
|
||||
# 检查是否是虚假中断(spurious interrupt)
|
||||
# 返回 1 表示是虚假中断,0 表示是真实中断
|
||||
def isSpurious(irq: t.CInt) -> t.CInt:
|
||||
# 边界检查
|
||||
if irq < 0 or irq > 15: return 0
|
||||
isr: t.CUInt8T
|
||||
if irq < 8:
|
||||
# 发送OCW3,读取ISR(Interrupt Service Register)
|
||||
asm.outb(PIC1_COMMAND, OCW3_READ_ISR)
|
||||
asm.io_wait()
|
||||
isr = asm.inb(PIC1_COMMAND)
|
||||
# 如果ISR中对应位为0,说明是虚假中断
|
||||
return not (isr & (1 << irq))
|
||||
else:
|
||||
# 发送OCW3,读取从PIC的ISR
|
||||
asm.outb(PIC2_COMMAND, OCW3_READ_ISR)
|
||||
asm.io_wait()
|
||||
isr = asm.inb(PIC2_COMMAND)
|
||||
# 如果ISR中对应位为0,说明是虚假中断
|
||||
return not (isr & (1 << (irq - 8)))
|
||||
|
||||
# 设置IRQ屏蔽
|
||||
def setMask(irq: t.CUInt8T):
|
||||
# 边界检查
|
||||
if irq > 15: return
|
||||
port: t.CUInt16T
|
||||
value: t.CUInt8T
|
||||
if irq < 8:
|
||||
port = PIC1_DATA
|
||||
else:
|
||||
port = PIC2_DATA
|
||||
irq -= 8
|
||||
value = asm.inb(port) | (1 << irq)
|
||||
asm.outb(port, value)
|
||||
asm.io_wait() # 确保命令生效
|
||||
|
||||
# 清除IRQ屏蔽
|
||||
def clearMask(irq: t.CUInt8T):
|
||||
# 边界检查
|
||||
if irq > 15: return
|
||||
port: t.CUInt16T
|
||||
value: t.CUInt8T
|
||||
if irq < 8:
|
||||
port = PIC1_DATA
|
||||
else:
|
||||
port = PIC2_DATA
|
||||
irq -= 8
|
||||
value = asm.inb(port) & ~(1 << irq)
|
||||
asm.outb(port, value)
|
||||
asm.io_wait() # 确保命令生效
|
||||
import asm
|
||||
import t, c
|
||||
|
||||
|
||||
# PIC端口定义
|
||||
PIC1_COMMAND: t.CDefine = 0x20
|
||||
PIC1_DATA: t.CDefine = 0x21
|
||||
PIC2_COMMAND: t.CDefine = 0xA0
|
||||
PIC2_DATA: t.CDefine = 0xA1
|
||||
|
||||
# ICW1 - 初始化命令字1
|
||||
ICW1_ICW4: t.CDefine = 0x01 # 需要ICW4
|
||||
ICW1_SINGLE: t.CDefine = 0x02 # 单级模式
|
||||
ICW1_INTERVAL4: t.CDefine = 0x04 # 间隔4字节
|
||||
ICW1_LEVEL: t.CDefine = 0x08 # 电平触发模式
|
||||
ICW1_INIT: t.CDefine = 0x10 # 初始化
|
||||
|
||||
# ICW4 - 初始化命令字4
|
||||
ICW4_8086: t.CDefine = 0x01 # 8086/88模式
|
||||
ICW4_AUTO: t.CDefine = 0x02 # 自动EOI
|
||||
ICW4_BUF_SLAVE: t.CDefine = 0x08 # 缓冲模式(从片)
|
||||
ICW4_BUF_MASTER: t.CDefine = 0x0C # 缓冲模式(主片)
|
||||
ICW4_SFNM: t.CDefine = 0x10 # 特殊全嵌套模式
|
||||
|
||||
# OCW2 - 操作命令字2
|
||||
OCW2_EOI: t.CDefine = 0x20 # 结束中断
|
||||
|
||||
# OCW3 - 操作命令字3
|
||||
OCW3_READ_ISR: t.CDefine = 0x0B # 读取中断服务寄存器(ISR)
|
||||
|
||||
# 初始化PIC
|
||||
def init():
|
||||
# 发送ICW1:开始初始化,需要ICW4
|
||||
asm.outb(PIC1_COMMAND, ICW1_INIT | ICW1_ICW4)
|
||||
asm.io_wait()
|
||||
asm.outb(PIC2_COMMAND, ICW1_INIT | ICW1_ICW4)
|
||||
asm.io_wait()
|
||||
|
||||
# 发送ICW2:中断向量偏移
|
||||
asm.outb(PIC1_DATA, 0x20) # IRQ0-7映射到0x20-0x27
|
||||
asm.io_wait()
|
||||
asm.outb(PIC2_DATA, 0x28) # IRQ8-15映射到0x28-0x2F
|
||||
asm.io_wait()
|
||||
|
||||
# 发送ICW3:级联信息
|
||||
asm.outb(PIC1_DATA, 0x04) # 主PIC的IRQ2连接从PIC
|
||||
asm.io_wait()
|
||||
asm.outb(PIC2_DATA, 0x02) # 从PIC连接到主PIC的IRQ2
|
||||
asm.io_wait()
|
||||
|
||||
# 发送ICW4:8086模式
|
||||
asm.outb(PIC1_DATA, ICW4_8086)
|
||||
asm.io_wait()
|
||||
asm.outb(PIC2_DATA, ICW4_8086)
|
||||
asm.io_wait()
|
||||
|
||||
# 设置初始屏蔽字:只启用IRQ0(定时器)、IRQ1(键盘)、IRQ2(级联)
|
||||
# 主PIC: 屏蔽所有除了IRQ0, IRQ1, IRQ2 (0xF8 = 11111000)
|
||||
# 从PIC: 屏蔽所有 (0xFF = 11111111),鼠标中断由驱动程序自己启用
|
||||
asm.outb(PIC1_DATA, 0xF8) # 启用IRQ0, IRQ1, IRQ2
|
||||
asm.io_wait()
|
||||
asm.outb(PIC2_DATA, 0xFF) # 屏蔽所有从PIC中断
|
||||
asm.io_wait()
|
||||
|
||||
# 发送EOI信号
|
||||
def eoi(irq: uint8):
|
||||
if irq >= 8: asm.outb(PIC2_COMMAND, OCW2_EOI)
|
||||
asm.outb(PIC1_COMMAND, OCW2_EOI)
|
||||
|
||||
|
||||
# 检查是否是虚假中断(spurious interrupt)
|
||||
# 返回 1 表示是虚假中断,0 表示是真实中断
|
||||
def isSpurious(irq: int) -> int:
|
||||
# 边界检查
|
||||
if irq < 0 or irq > 15: return 0
|
||||
isr: uint8
|
||||
if irq < 8:
|
||||
# 发送OCW3,读取ISR(Interrupt Service Register)
|
||||
asm.outb(PIC1_COMMAND, OCW3_READ_ISR)
|
||||
asm.io_wait()
|
||||
isr = asm.inb(PIC1_COMMAND)
|
||||
# 如果ISR中对应位为0,说明是虚假中断
|
||||
return not (isr & (1 << irq))
|
||||
else:
|
||||
# 发送OCW3,读取从PIC的ISR
|
||||
asm.outb(PIC2_COMMAND, OCW3_READ_ISR)
|
||||
asm.io_wait()
|
||||
isr = asm.inb(PIC2_COMMAND)
|
||||
# 如果ISR中对应位为0,说明是虚假中断
|
||||
return not (isr & (1 << (irq - 8)))
|
||||
|
||||
# 设置IRQ屏蔽
|
||||
def setMask(irq: uint8):
|
||||
# 边界检查
|
||||
if irq > 15: return
|
||||
port: uint16
|
||||
value: uint8
|
||||
if irq < 8:
|
||||
port = PIC1_DATA
|
||||
else:
|
||||
port = PIC2_DATA
|
||||
irq -= 8
|
||||
value = asm.inb(port) | (1 << irq)
|
||||
asm.outb(port, value)
|
||||
asm.io_wait() # 确保命令生效
|
||||
|
||||
# 清除IRQ屏蔽
|
||||
def clearMask(irq: uint8):
|
||||
# 边界检查
|
||||
if irq > 15: return
|
||||
port: uint16
|
||||
value: uint8
|
||||
if irq < 8:
|
||||
port = PIC1_DATA
|
||||
else:
|
||||
port = PIC2_DATA
|
||||
irq -= 8
|
||||
value = asm.inb(port) & ~(1 << irq)
|
||||
asm.outb(port, value)
|
||||
asm.io_wait() # 确保命令生效
|
||||
@@ -1,26 +1,26 @@
|
||||
import asm
|
||||
import t, c
|
||||
|
||||
PIT_CHANNEL0: t.CDefine = 0x40
|
||||
PIT_CHANNEL1: t.CDefine = 0x41
|
||||
PIT_CHANNEL2: t.CDefine = 0x42
|
||||
PIT_COMMAND: t.CDefine = 0x43
|
||||
|
||||
def pit_init(frequency: t.CInt):
|
||||
# 参数验证:确保频率为正数
|
||||
if frequency <= 0: return
|
||||
|
||||
# 计算除数,使用16位无符号整数
|
||||
divisor: t.CUInt32T = 1193180 / frequency
|
||||
|
||||
# 发送命令字:通道0,先低后高,模式3(方波),二进制计数
|
||||
asm.outb(PIT_COMMAND, 0x36)
|
||||
asm.io_wait()
|
||||
|
||||
# 写入低字节
|
||||
asm.outb(PIT_CHANNEL0, divisor & 0xFF)
|
||||
asm.io_wait()
|
||||
|
||||
# 写入高字节
|
||||
asm.outb(PIT_CHANNEL0, (divisor >> 8) & 0xFF)
|
||||
asm.io_wait()
|
||||
import asm
|
||||
import t, c
|
||||
|
||||
PIT_CHANNEL0: t.CDefine = 0x40
|
||||
PIT_CHANNEL1: t.CDefine = 0x41
|
||||
PIT_CHANNEL2: t.CDefine = 0x42
|
||||
PIT_COMMAND: t.CDefine = 0x43
|
||||
|
||||
def pit_init(frequency: int):
|
||||
# 参数验证:确保频率为正数
|
||||
if frequency <= 0: return
|
||||
|
||||
# 计算除数,使用16位无符号整数
|
||||
divisor: uint32 = 1193180 / frequency
|
||||
|
||||
# 发送命令字:通道0,先低后高,模式3(方波),二进制计数
|
||||
asm.outb(PIT_COMMAND, 0x36)
|
||||
asm.io_wait()
|
||||
|
||||
# 写入低字节
|
||||
asm.outb(PIT_CHANNEL0, divisor & 0xFF)
|
||||
asm.io_wait()
|
||||
|
||||
# 写入高字节
|
||||
asm.outb(PIT_CHANNEL0, (divisor >> 8) & 0xFF)
|
||||
asm.io_wait()
|
||||
@@ -1,97 +1,97 @@
|
||||
from stdint import *
|
||||
import t, c
|
||||
import asm
|
||||
|
||||
|
||||
RTC_CMOS_ADDR: t.CUInt16T = 0x70
|
||||
RTC_CMOS_DATA: t.CUInt16T = 0x71
|
||||
|
||||
RTC_REG_SECONDS: t.CDefine = 0x00
|
||||
RTC_REG_MINUTES: t.CDefine = 0x02
|
||||
RTC_REG_HOURS: t.CDefine = 0x04
|
||||
RTC_REG_DAY: t.CDefine = 0x07
|
||||
RTC_REG_MONTH: t.CDefine = 0x08
|
||||
RTC_REG_YEAR: t.CDefine = 0x09
|
||||
RTC_REG_STATUS_A: t.CDefine = 0x0A
|
||||
RTC_REG_STATUS_B: t.CDefine = 0x0B
|
||||
|
||||
RTC_TZ_OFFSET: t.CDefine = 8
|
||||
|
||||
rtc_seconds: t.CStatic | t.CVolatile | t.CUInt8T = 0
|
||||
rtc_minutes: t.CStatic | t.CVolatile | t.CUInt8T = 0
|
||||
rtc_hours: t.CStatic | t.CVolatile | t.CUInt8T = 0
|
||||
rtc_day: t.CStatic | t.CVolatile | t.CUInt8T = 0
|
||||
rtc_month: t.CStatic | t.CVolatile | t.CUInt8T = 0
|
||||
rtc_year: t.CStatic | t.CVolatile | t.CUInt16T = 0
|
||||
|
||||
def cmos_read(reg: t.CUInt8T) -> t.CUInt8T:
|
||||
asm.outb(RTC_CMOS_ADDR, reg)
|
||||
return asm.inb(RTC_CMOS_DATA)
|
||||
|
||||
def bcd_to_bin(bcd: t.CUInt8T) -> t.CUInt8T:
|
||||
return (bcd >> 4) * 10 + (bcd & 0x0F)
|
||||
|
||||
def rtc_read_time():
|
||||
while cmos_read(RTC_REG_STATUS_A) & 0x80: pass
|
||||
sec: t.CUInt8T = cmos_read(RTC_REG_SECONDS)
|
||||
min_: t.CUInt8T = cmos_read(RTC_REG_MINUTES)
|
||||
hour: t.CUInt8T = cmos_read(RTC_REG_HOURS)
|
||||
day: t.CUInt8T = cmos_read(RTC_REG_DAY)
|
||||
mon: t.CUInt8T = cmos_read(RTC_REG_MONTH)
|
||||
year: t.CUInt8T = cmos_read(RTC_REG_YEAR)
|
||||
reg_b: t.CUInt8T = cmos_read(RTC_REG_STATUS_B)
|
||||
if not (reg_b & 0x04):
|
||||
sec = bcd_to_bin(sec)
|
||||
min_ = bcd_to_bin(min_)
|
||||
hour = bcd_to_bin(hour)
|
||||
day = bcd_to_bin(day)
|
||||
mon = bcd_to_bin(mon)
|
||||
year = bcd_to_bin(year)
|
||||
if not (reg_b & 0x02) and (hour & 0x80):
|
||||
hour = ((hour & 0x7F) + 12) % 24
|
||||
hour = hour + RTC_TZ_OFFSET
|
||||
if hour >= 24:
|
||||
hour = hour - 24
|
||||
day = day + 1
|
||||
max_day: t.CUInt8T = 31
|
||||
if mon == 4 or mon == 6 or mon == 9 or mon == 11:
|
||||
max_day = 30
|
||||
elif mon == 2:
|
||||
max_day = 28
|
||||
y4: t.CUInt16T = t.CUInt16T(year) + 2000
|
||||
if (y4 % 4 == 0 and y4 % 100 != 0) or (y4 % 400 == 0):
|
||||
max_day = 29
|
||||
if day > max_day:
|
||||
day = 1
|
||||
mon = mon + 1
|
||||
if mon > 12:
|
||||
mon = 1
|
||||
year = year + 1
|
||||
global rtc_seconds, rtc_minutes, rtc_hours, rtc_day, rtc_month, rtc_year
|
||||
rtc_seconds = sec
|
||||
rtc_minutes = min_
|
||||
rtc_hours = hour
|
||||
rtc_day = day
|
||||
rtc_month = mon
|
||||
rtc_year = t.CUInt16T(year) + 2000
|
||||
|
||||
def rtc_init():
|
||||
rtc_read_time()
|
||||
|
||||
def rtc_get_hours() -> t.CUInt8T:
|
||||
return rtc_hours
|
||||
|
||||
def rtc_get_minutes() -> t.CUInt8T:
|
||||
return rtc_minutes
|
||||
|
||||
def rtc_get_seconds() -> t.CUInt8T:
|
||||
return rtc_seconds
|
||||
|
||||
def rtc_get_day() -> t.CUInt8T:
|
||||
return rtc_day
|
||||
|
||||
def rtc_get_month() -> t.CUInt8T:
|
||||
return rtc_month
|
||||
|
||||
def rtc_get_year() -> t.CUInt16T:
|
||||
return rtc_year
|
||||
from stdint import *
|
||||
import t, c
|
||||
import asm
|
||||
|
||||
|
||||
RTC_CMOS_ADDR: uint16 = 0x70
|
||||
RTC_CMOS_DATA: uint16 = 0x71
|
||||
|
||||
RTC_REG_SECONDS: t.CDefine = 0x00
|
||||
RTC_REG_MINUTES: t.CDefine = 0x02
|
||||
RTC_REG_HOURS: t.CDefine = 0x04
|
||||
RTC_REG_DAY: t.CDefine = 0x07
|
||||
RTC_REG_MONTH: t.CDefine = 0x08
|
||||
RTC_REG_YEAR: t.CDefine = 0x09
|
||||
RTC_REG_STATUS_A: t.CDefine = 0x0A
|
||||
RTC_REG_STATUS_B: t.CDefine = 0x0B
|
||||
|
||||
RTC_TZ_OFFSET: t.CDefine = 8
|
||||
|
||||
rtc_seconds: t.CStatic | t.CVolatile | uint8 = 0
|
||||
rtc_minutes: t.CStatic | t.CVolatile | uint8 = 0
|
||||
rtc_hours: t.CStatic | t.CVolatile | uint8 = 0
|
||||
rtc_day: t.CStatic | t.CVolatile | uint8 = 0
|
||||
rtc_month: t.CStatic | t.CVolatile | uint8 = 0
|
||||
rtc_year: t.CStatic | t.CVolatile | uint16 = 0
|
||||
|
||||
def cmos_read(reg: uint8) -> uint8:
|
||||
asm.outb(RTC_CMOS_ADDR, reg)
|
||||
return asm.inb(RTC_CMOS_DATA)
|
||||
|
||||
def bcd_to_bin(bcd: uint8) -> uint8:
|
||||
return (bcd >> 4) * 10 + (bcd & 0x0F)
|
||||
|
||||
def rtc_read_time():
|
||||
while cmos_read(RTC_REG_STATUS_A) & 0x80: pass
|
||||
sec: uint8 = cmos_read(RTC_REG_SECONDS)
|
||||
min_: uint8 = cmos_read(RTC_REG_MINUTES)
|
||||
hour: uint8 = cmos_read(RTC_REG_HOURS)
|
||||
day: uint8 = cmos_read(RTC_REG_DAY)
|
||||
mon: uint8 = cmos_read(RTC_REG_MONTH)
|
||||
year: uint8 = cmos_read(RTC_REG_YEAR)
|
||||
reg_b: uint8 = cmos_read(RTC_REG_STATUS_B)
|
||||
if not (reg_b & 0x04):
|
||||
sec = bcd_to_bin(sec)
|
||||
min_ = bcd_to_bin(min_)
|
||||
hour = bcd_to_bin(hour)
|
||||
day = bcd_to_bin(day)
|
||||
mon = bcd_to_bin(mon)
|
||||
year = bcd_to_bin(year)
|
||||
if not (reg_b & 0x02) and (hour & 0x80):
|
||||
hour = ((hour & 0x7F) + 12) % 24
|
||||
hour = hour + RTC_TZ_OFFSET
|
||||
if hour >= 24:
|
||||
hour = hour - 24
|
||||
day = day + 1
|
||||
max_day: uint8 = 31
|
||||
if mon == 4 or mon == 6 or mon == 9 or mon == 11:
|
||||
max_day = 30
|
||||
elif mon == 2:
|
||||
max_day = 28
|
||||
y4: uint16 = uint16(year) + 2000
|
||||
if (y4 % 4 == 0 and y4 % 100 != 0) or (y4 % 400 == 0):
|
||||
max_day = 29
|
||||
if day > max_day:
|
||||
day = 1
|
||||
mon = mon + 1
|
||||
if mon > 12:
|
||||
mon = 1
|
||||
year = year + 1
|
||||
global rtc_seconds, rtc_minutes, rtc_hours, rtc_day, rtc_month, rtc_year
|
||||
rtc_seconds = sec
|
||||
rtc_minutes = min_
|
||||
rtc_hours = hour
|
||||
rtc_day = day
|
||||
rtc_month = mon
|
||||
rtc_year = uint16(year) + 2000
|
||||
|
||||
def rtc_init():
|
||||
rtc_read_time()
|
||||
|
||||
def rtc_get_hours() -> uint8:
|
||||
return rtc_hours
|
||||
|
||||
def rtc_get_minutes() -> uint8:
|
||||
return rtc_minutes
|
||||
|
||||
def rtc_get_seconds() -> uint8:
|
||||
return rtc_seconds
|
||||
|
||||
def rtc_get_day() -> uint8:
|
||||
return rtc_day
|
||||
|
||||
def rtc_get_month() -> uint8:
|
||||
return rtc_month
|
||||
|
||||
def rtc_get_year() -> uint16:
|
||||
return rtc_year
|
||||
@@ -1,129 +1,129 @@
|
||||
import platform.pch.pic as pic
|
||||
import platform.pch.pit as pit
|
||||
import sched.sched as sched
|
||||
import drivers.core.cpu.apic as apic
|
||||
import drivers.serial.uart.serial as serial
|
||||
import viperlib
|
||||
import asm
|
||||
import t, c
|
||||
|
||||
TIMER_FREQUENCY: t.CDefine = 1000
|
||||
TICKS_PER_SECOND: t.CDefine = TIMER_FREQUENCY
|
||||
MILLISECONDS_PER_TICK: t.CDefine = (1000 / TIMER_FREQUENCY)
|
||||
|
||||
ticks: t.CStatic | t.CVolatile | t.CUInt64T = 0
|
||||
seconds: t.CStatic | t.CVolatile | t.CUInt32T = 0
|
||||
milliseconds: t.CStatic | t.CVolatile | t.CUInt32T = 0
|
||||
timer_running: t.CStatic | t.CVolatile | bool = False
|
||||
_dbg_once: t.CInt = 0
|
||||
|
||||
def timer_init():
|
||||
global ticks, seconds, milliseconds, timer_running
|
||||
c.Asm("mfence", op=[t.ASM_DESCR.CLOBBER_MEMORY])
|
||||
ticks = 0
|
||||
seconds = 0
|
||||
milliseconds = 0
|
||||
timer_running = True
|
||||
c.Asm("mfence", op=[t.ASM_DESCR.CLOBBER_MEMORY])
|
||||
pit.pit_init(TIMER_FREQUENCY)
|
||||
# [DBG] 读 PIT 计数器验证是否在走(用后移除)
|
||||
asm.outb(0x43, 0x00) # latch channel 0
|
||||
_lo: t.CUInt8T = asm.inb(0x40)
|
||||
_hi: t.CUInt8T = asm.inb(0x40)
|
||||
_cnt: t.CInt = t.CInt(_lo) | (t.CInt(_hi) << 8)
|
||||
_cb: t.CArray[t.CChar, 40]
|
||||
viperlib.snprintf(c.Addr(_cb), 40, "[PIT] cnt=%d\n", _cnt)
|
||||
serial.puts(c.Addr(_cb))
|
||||
|
||||
def timer_handler():
|
||||
global ticks, seconds, milliseconds, timer_running, _dbg_once
|
||||
# [DBG] 一次性打印:'H' 出现说明定时 ISR 被调用(用后移除)
|
||||
if _dbg_once == 0:
|
||||
_dbg_once = 1
|
||||
serial.puts("H")
|
||||
if not timer_running:
|
||||
pic.eoi(0)
|
||||
apic.eoi()
|
||||
return
|
||||
c.Asm("mfence", op=[t.ASM_DESCR.CLOBBER_MEMORY])
|
||||
ticks = ticks + 1
|
||||
milliseconds = milliseconds + MILLISECONDS_PER_TICK
|
||||
if milliseconds >= 1000:
|
||||
seconds = seconds + 1
|
||||
milliseconds = milliseconds - 1000
|
||||
c.Asm("mfence", op=[t.ASM_DESCR.CLOBBER_MEMORY])
|
||||
sched.Scheduler.sched_tick()
|
||||
pic.eoi(0)
|
||||
# LAPIC EOI:APIC 启用后中断经 LINT0(EXTINT) 送达会置 LAPIC ISR,
|
||||
# 只发 PIC EOI 不清 LAPIC ISR → 首个定时中断后后续中断被屏蔽 →
|
||||
# ticks 不推进 → msleep 永久挂起(QEMU/OVMF 下 APIC 必启用)。
|
||||
apic.eoi()
|
||||
|
||||
def timer_start():
|
||||
global timer_running
|
||||
c.Asm("mfence", op=[t.ASM_DESCR.CLOBBER_MEMORY])
|
||||
timer_running = True
|
||||
c.Asm("mfence", op=[t.ASM_DESCR.CLOBBER_MEMORY])
|
||||
|
||||
def timer_stop():
|
||||
global timer_running
|
||||
c.Asm("mfence", op=[t.ASM_DESCR.CLOBBER_MEMORY])
|
||||
timer_running = False
|
||||
c.Asm("mfence", op=[t.ASM_DESCR.CLOBBER_MEMORY])
|
||||
|
||||
def timer_reset():
|
||||
global ticks, seconds, milliseconds
|
||||
c.Asm("mfence", op=[t.ASM_DESCR.CLOBBER_MEMORY])
|
||||
ticks = 0
|
||||
seconds = 0
|
||||
milliseconds = 0
|
||||
c.Asm("mfence", op=[t.ASM_DESCR.CLOBBER_MEMORY])
|
||||
|
||||
def timer_get_ticks() -> t.CUInt64T:
|
||||
current_ticks: t.CUInt64T
|
||||
c.Asm("mfence", op=[t.ASM_DESCR.CLOBBER_MEMORY])
|
||||
current_ticks = ticks
|
||||
c.Asm("mfence", op=[t.ASM_DESCR.CLOBBER_MEMORY])
|
||||
return current_ticks
|
||||
|
||||
def timer_get_seconds() -> t.CUInt32T:
|
||||
current_seconds: t.CUInt32T
|
||||
c.Asm("mfence", op=[t.ASM_DESCR.CLOBBER_MEMORY])
|
||||
current_seconds = seconds
|
||||
c.Asm("mfence", op=[t.ASM_DESCR.CLOBBER_MEMORY])
|
||||
return current_seconds
|
||||
|
||||
def timer_get_milliseconds() -> t.CUInt32T:
|
||||
current_milliseconds: t.CUInt32T
|
||||
c.Asm("mfence", op=[t.ASM_DESCR.CLOBBER_MEMORY])
|
||||
current_milliseconds = milliseconds
|
||||
c.Asm("mfence", op=[t.ASM_DESCR.CLOBBER_MEMORY])
|
||||
return current_milliseconds
|
||||
|
||||
def timer_get_time(out_seconds: t.CUInt32T | t.CPtr, out_milliseconds: t.CUInt32T | t.CPtr):
|
||||
c.Asm("mfence", op=[t.ASM_DESCR.CLOBBER_MEMORY])
|
||||
if out_seconds:
|
||||
c.Set(c.Deref(out_seconds), seconds)
|
||||
if out_milliseconds:
|
||||
c.Set(c.Deref(out_milliseconds), milliseconds)
|
||||
c.Asm("mfence", op=[t.ASM_DESCR.CLOBBER_MEMORY])
|
||||
|
||||
def timer_msleep(ms: t.CUInt32T):
|
||||
target: t.CUInt64T = ticks + (ms + MILLISECONDS_PER_TICK - 1) / MILLISECONDS_PER_TICK
|
||||
_spin: t.CUInt64T = 0
|
||||
while ticks < target:
|
||||
# [DBG] 自旋计数:每 1M 次迭代打印 s——hlt 能唤醒说明中断触发
|
||||
# (用后移除)
|
||||
_spin += 1
|
||||
if (_spin & 0xFFFFF) == 0:
|
||||
serial.puts("s")
|
||||
asm.sti()
|
||||
asm.hlt()
|
||||
sched.Scheduler._yield()
|
||||
|
||||
def timer_sleep(sec: t.CUInt32T):
|
||||
target: t.CUInt64T = ticks + sec * TICKS_PER_SECOND
|
||||
while ticks < target:
|
||||
asm.sti()
|
||||
asm.hlt()
|
||||
sched.Scheduler._yield()
|
||||
import platform.pch.pic as pic
|
||||
import platform.pch.pit as pit
|
||||
import sched.sched as sched
|
||||
import drivers.core.cpu.apic as apic
|
||||
import drivers.serial.uart.serial as serial
|
||||
import viperlib
|
||||
import asm
|
||||
import t, c
|
||||
|
||||
TIMER_FREQUENCY: t.CDefine = 1000
|
||||
TICKS_PER_SECOND: t.CDefine = TIMER_FREQUENCY
|
||||
MILLISECONDS_PER_TICK: t.CDefine = (1000 / TIMER_FREQUENCY)
|
||||
|
||||
ticks: t.CStatic | t.CVolatile | uint64 = 0
|
||||
seconds: t.CStatic | t.CVolatile | uint32 = 0
|
||||
milliseconds: t.CStatic | t.CVolatile | uint32 = 0
|
||||
timer_running: t.CStatic | t.CVolatile | bool = False
|
||||
_dbg_once: int = 0
|
||||
|
||||
def timer_init():
|
||||
global ticks, seconds, milliseconds, timer_running
|
||||
c.Asm("mfence", op=[t.ASM_DESCR.CLOBBER_MEMORY])
|
||||
ticks = 0
|
||||
seconds = 0
|
||||
milliseconds = 0
|
||||
timer_running = True
|
||||
c.Asm("mfence", op=[t.ASM_DESCR.CLOBBER_MEMORY])
|
||||
pit.pit_init(TIMER_FREQUENCY)
|
||||
# [DBG] 读 PIT 计数器验证是否在走(用后移除)
|
||||
asm.outb(0x43, 0x00) # latch channel 0
|
||||
_lo: uint8 = asm.inb(0x40)
|
||||
_hi: uint8 = asm.inb(0x40)
|
||||
_cnt: int = int(_lo) | (int(_hi) << 8)
|
||||
_cb: t.CArray[t.CChar, 40]
|
||||
viperlib.snprintf(c.Addr(_cb), 40, "[PIT] cnt=%d\n", _cnt)
|
||||
serial.puts(c.Addr(_cb))
|
||||
|
||||
def timer_handler():
|
||||
global ticks, seconds, milliseconds, timer_running, _dbg_once
|
||||
# [DBG] 一次性打印:'H' 出现说明定时 ISR 被调用(用后移除)
|
||||
if _dbg_once == 0:
|
||||
_dbg_once = 1
|
||||
serial.puts("H")
|
||||
if not timer_running:
|
||||
pic.eoi(0)
|
||||
apic.eoi()
|
||||
return
|
||||
c.Asm("mfence", op=[t.ASM_DESCR.CLOBBER_MEMORY])
|
||||
ticks = ticks + 1
|
||||
milliseconds = milliseconds + MILLISECONDS_PER_TICK
|
||||
if milliseconds >= 1000:
|
||||
seconds = seconds + 1
|
||||
milliseconds = milliseconds - 1000
|
||||
c.Asm("mfence", op=[t.ASM_DESCR.CLOBBER_MEMORY])
|
||||
sched.Scheduler.sched_tick()
|
||||
pic.eoi(0)
|
||||
# LAPIC EOI:APIC 启用后中断经 LINT0(EXTINT) 送达会置 LAPIC ISR,
|
||||
# 只发 PIC EOI 不清 LAPIC ISR → 首个定时中断后后续中断被屏蔽 →
|
||||
# ticks 不推进 → msleep 永久挂起(QEMU/OVMF 下 APIC 必启用)。
|
||||
apic.eoi()
|
||||
|
||||
def timer_start():
|
||||
global timer_running
|
||||
c.Asm("mfence", op=[t.ASM_DESCR.CLOBBER_MEMORY])
|
||||
timer_running = True
|
||||
c.Asm("mfence", op=[t.ASM_DESCR.CLOBBER_MEMORY])
|
||||
|
||||
def timer_stop():
|
||||
global timer_running
|
||||
c.Asm("mfence", op=[t.ASM_DESCR.CLOBBER_MEMORY])
|
||||
timer_running = False
|
||||
c.Asm("mfence", op=[t.ASM_DESCR.CLOBBER_MEMORY])
|
||||
|
||||
def timer_reset():
|
||||
global ticks, seconds, milliseconds
|
||||
c.Asm("mfence", op=[t.ASM_DESCR.CLOBBER_MEMORY])
|
||||
ticks = 0
|
||||
seconds = 0
|
||||
milliseconds = 0
|
||||
c.Asm("mfence", op=[t.ASM_DESCR.CLOBBER_MEMORY])
|
||||
|
||||
def timer_get_ticks() -> uint64:
|
||||
current_ticks: uint64
|
||||
c.Asm("mfence", op=[t.ASM_DESCR.CLOBBER_MEMORY])
|
||||
current_ticks = ticks
|
||||
c.Asm("mfence", op=[t.ASM_DESCR.CLOBBER_MEMORY])
|
||||
return current_ticks
|
||||
|
||||
def timer_get_seconds() -> uint32:
|
||||
current_seconds: uint32
|
||||
c.Asm("mfence", op=[t.ASM_DESCR.CLOBBER_MEMORY])
|
||||
current_seconds = seconds
|
||||
c.Asm("mfence", op=[t.ASM_DESCR.CLOBBER_MEMORY])
|
||||
return current_seconds
|
||||
|
||||
def timer_get_milliseconds() -> uint32:
|
||||
current_milliseconds: uint32
|
||||
c.Asm("mfence", op=[t.ASM_DESCR.CLOBBER_MEMORY])
|
||||
current_milliseconds = milliseconds
|
||||
c.Asm("mfence", op=[t.ASM_DESCR.CLOBBER_MEMORY])
|
||||
return current_milliseconds
|
||||
|
||||
def timer_get_time(out_seconds: uint32 | t.CPtr, out_milliseconds: uint32 | t.CPtr):
|
||||
c.Asm("mfence", op=[t.ASM_DESCR.CLOBBER_MEMORY])
|
||||
if out_seconds:
|
||||
c.Set(c.Deref(out_seconds), seconds)
|
||||
if out_milliseconds:
|
||||
c.Set(c.Deref(out_milliseconds), milliseconds)
|
||||
c.Asm("mfence", op=[t.ASM_DESCR.CLOBBER_MEMORY])
|
||||
|
||||
def timer_msleep(ms: uint32):
|
||||
target: uint64 = ticks + (ms + MILLISECONDS_PER_TICK - 1) / MILLISECONDS_PER_TICK
|
||||
_spin: uint64 = 0
|
||||
while ticks < target:
|
||||
# [DBG] 自旋计数:每 1M 次迭代打印 s——hlt 能唤醒说明中断触发
|
||||
# (用后移除)
|
||||
_spin += 1
|
||||
if (_spin & 0xFFFFF) == 0:
|
||||
serial.puts("s")
|
||||
asm.sti()
|
||||
asm.hlt()
|
||||
sched.Scheduler._yield()
|
||||
|
||||
def timer_sleep(sec: uint32):
|
||||
target: uint64 = ticks + sec * TICKS_PER_SECOND
|
||||
while ticks < target:
|
||||
asm.sti()
|
||||
asm.hlt()
|
||||
sched.Scheduler._yield()
|
||||
@@ -13,27 +13,27 @@ CORO_STACK_SIZE: t.CDefine = 8192
|
||||
|
||||
@t.Object
|
||||
class Coroutine:
|
||||
rsp: t.CUInt64T
|
||||
stack: t.CVoid | t.CPtr
|
||||
stack_size: t.CUInt64T
|
||||
func: t.CVoid | t.CPtr
|
||||
arg: t.CVoid | t.CPtr
|
||||
state: t.CInt
|
||||
cid: t.CInt
|
||||
caller_rsp: t.CUInt64T
|
||||
ret_val: t.CInt
|
||||
rsp: uint64
|
||||
stack: t.CPtr
|
||||
stack_size: uint64
|
||||
func: t.CPtr
|
||||
arg: t.CPtr
|
||||
state: int
|
||||
cid: int
|
||||
caller_rsp: uint64
|
||||
ret_val: int
|
||||
|
||||
def resume(self) -> t.CInt:
|
||||
def resume(self) -> int:
|
||||
global _coro_old_rsp, _coro_new_rsp
|
||||
m: CoroutineManager | t.CPtr = _coro_mgr_ptr
|
||||
if self.state == CORO_DONE: return self.ret_val
|
||||
if self.state != CORO_READY and self.state != CORO_YIELDED: return -1
|
||||
prev_cid: t.CInt = m.current_cid
|
||||
prev_cid: int = m.current_cid
|
||||
m.current_cid = self.cid
|
||||
self.state = CORO_RUNNING
|
||||
_coro_old_rsp = c.Addr(m.coroutines[prev_cid].rsp)
|
||||
_coro_new_rsp = c.Addr(self.rsp)
|
||||
self.caller_rsp = t.CUInt64T(_coro_old_rsp)
|
||||
self.caller_rsp = uint64(_coro_old_rsp)
|
||||
_coro_switch()
|
||||
if self.state == CORO_DONE:
|
||||
return self.ret_val
|
||||
@@ -43,11 +43,11 @@ class Coroutine:
|
||||
def _yield():
|
||||
global _coro_old_rsp, _coro_new_rsp
|
||||
m: CoroutineManager | t.CPtr = _coro_mgr_ptr
|
||||
cid: t.CInt = m.current_cid
|
||||
cid: int = m.current_cid
|
||||
if cid < 0: return
|
||||
m.coroutines[cid].state = CORO_YIELDED
|
||||
prev_cid: t.CInt = -1
|
||||
i: t.CInt
|
||||
prev_cid: int = -1
|
||||
i: int
|
||||
for i in range(m.count):
|
||||
if m.coroutines[i].state == CORO_RUNNING and m.coroutines[i].caller_rsp != 0:
|
||||
prev_cid = i
|
||||
@@ -59,27 +59,27 @@ class Coroutine:
|
||||
_coro_switch()
|
||||
|
||||
@property
|
||||
def is_done(self) -> t.CInt:
|
||||
def is_done(self) -> int:
|
||||
if self.state == CORO_DONE:
|
||||
return 1
|
||||
return 0
|
||||
|
||||
@property
|
||||
def is_yielded(self) -> t.CInt:
|
||||
def is_yielded(self) -> int:
|
||||
if self.state == CORO_YIELDED:
|
||||
return 1
|
||||
return 0
|
||||
|
||||
@property
|
||||
def retval(self) -> t.CInt:
|
||||
def retval(self) -> int:
|
||||
return self.ret_val
|
||||
|
||||
|
||||
@t.Object
|
||||
class CoroutineManager:
|
||||
coroutines: t.CArray[Coroutine, MAX_COROUTINES]
|
||||
current_cid: t.CInt
|
||||
count: t.CInt
|
||||
current_cid: int
|
||||
count: int
|
||||
|
||||
def __init__(self):
|
||||
global _coro_mgr_ptr
|
||||
@@ -96,7 +96,7 @@ class CoroutineManager:
|
||||
m.coroutines[0].stack_size = 0
|
||||
m.coroutines[0].func = None
|
||||
m.coroutines[0].arg = None
|
||||
main_rsp_ptr: t.CVoid | t.CPtr = c.Addr(m.coroutines[0].rsp)
|
||||
main_rsp_ptr: t.CPtr = c.Addr(m.coroutines[0].rsp)
|
||||
c.Asm(f"""mov qword ptr [{c.AsmInp(main_rsp_ptr, t.ASM_DESCR.REG_ANY)}], rsp""",
|
||||
op=[t.ASM_DESCR.CLOBBER_MEMORY])
|
||||
|
||||
@@ -106,16 +106,16 @@ class CoroutineManager:
|
||||
return c.Addr(m.coroutines[m.current_cid])
|
||||
|
||||
@staticmethod
|
||||
def get_coroutine(cid: t.CInt) -> Coroutine | t.CPtr:
|
||||
def get_coroutine(cid: int) -> Coroutine | t.CPtr:
|
||||
m: CoroutineManager | t.CPtr = _coro_mgr_ptr
|
||||
if cid < 0 or cid >= m.count: return None
|
||||
return c.Addr(m.coroutines[cid])
|
||||
|
||||
@staticmethod
|
||||
def create(func: t.CVoid | t.CPtr, arg: t.CVoid | t.CPtr) -> Coroutine | t.CPtr:
|
||||
def create(func: t.CPtr, arg: t.CPtr) -> Coroutine | t.CPtr:
|
||||
m: CoroutineManager | t.CPtr = _coro_mgr_ptr
|
||||
if m.count >= MAX_COROUTINES: return None
|
||||
cid: t.CInt = m.count
|
||||
cid: int = m.count
|
||||
m.count += 1
|
||||
co: Coroutine | t.CPtr = c.Addr(m.coroutines[cid])
|
||||
co.state = CORO_READY
|
||||
@@ -124,13 +124,13 @@ class CoroutineManager:
|
||||
co.arg = arg
|
||||
co.caller_rsp = 0
|
||||
co.ret_val = 0
|
||||
stack_ptr: t.CVoid | t.CPtr = mm.malloc(CORO_STACK_SIZE)
|
||||
stack_ptr: t.CPtr = mm.malloc(CORO_STACK_SIZE)
|
||||
if not stack_ptr: return None
|
||||
co.stack = stack_ptr
|
||||
co.stack_size = CORO_STACK_SIZE
|
||||
stack_top: t.CUInt64T = t.CUInt64T(stack_ptr) + CORO_STACK_SIZE - 16
|
||||
stack_top = stack_top & ~t.CUInt64T(0xF)
|
||||
entry_addr: t.CUInt64T = t.CUInt64T(c.Addr(_coro_entry))
|
||||
stack_top: uint64 = uint64(stack_ptr) + CORO_STACK_SIZE - 16
|
||||
stack_top = stack_top & ~uint64(0xF)
|
||||
entry_addr: uint64 = uint64(c.Addr(_coro_entry))
|
||||
sp: t.CPtr = t.CPtr(stack_top)
|
||||
c.Asm(f"""mov rax, {c.AsmInp(sp, t.ASM_DESCR.REG_ANY)}
|
||||
mov qword ptr [rax - 56], 0
|
||||
@@ -149,8 +149,8 @@ class CoroutineManager:
|
||||
|
||||
_coro_mgr: CoroutineManager = CoroutineManager()
|
||||
_coro_mgr_ptr: CoroutineManager | t.CPtr | t.CExport = c.Addr(_coro_mgr)
|
||||
_coro_old_rsp: t.CVoid | t.CPtr | t.CExport
|
||||
_coro_new_rsp: t.CVoid | t.CPtr | t.CExport
|
||||
_coro_old_rsp: t.CPtr | t.CExport
|
||||
_coro_new_rsp: t.CPtr | t.CExport
|
||||
|
||||
@c.Attribute(t.attr.naked)
|
||||
def _coro_switch():
|
||||
@@ -177,20 +177,25 @@ def _coro_switch():
|
||||
|
||||
@c.Attribute(t.attr.naked)
|
||||
def _coro_entry():
|
||||
# 结构体布局(以 stub.ll 为权威):
|
||||
# Coroutine = {rsp@0, stack@8, stack_size@16, func@24, arg@32,
|
||||
# state@40, cid@44, caller_rsp@48, ret_val@56}, sizeof=64
|
||||
# CoroutineManager= {coroutines[32]@0 (32*64=2048), current_cid@2048, count@2052}
|
||||
# 取 func/arg 入口,写 state=CORO_DONE(3)、ret_val。
|
||||
c.Asm(f"""sub rsp, 8
|
||||
mov rax, qword ptr [rip + _coro_mgr_ptr]
|
||||
mov ecx, dword ptr [rax + 1056]
|
||||
mov ecx, dword ptr [rax + 2048]
|
||||
movsxd rcx, ecx
|
||||
shl rcx, 5
|
||||
mov rdi, qword ptr [rax + rcx + 24]
|
||||
mov rax, qword ptr [rax + rcx + 16]
|
||||
shl rcx, 6
|
||||
mov rdi, qword ptr [rax + rcx + 32]
|
||||
mov rax, qword ptr [rax + rcx + 24]
|
||||
call rax
|
||||
mov rax, qword ptr [rip + _coro_mgr_ptr]
|
||||
mov ecx, dword ptr [rax + 1056]
|
||||
mov ecx, dword ptr [rax + 2048]
|
||||
movsxd rcx, ecx
|
||||
shl rcx, 5
|
||||
mov dword ptr [rax + rcx + 32], 3
|
||||
mov dword ptr [rax + rcx + 48], eax
|
||||
shl rcx, 6
|
||||
mov dword ptr [rax + rcx + 40], 3
|
||||
mov dword ptr [rax + rcx + 56], eax
|
||||
add rsp, 8""",
|
||||
op=[t.ASM_DESCR.CLOBBER_MEMORY, t.ASM_DESCR.CLOBBER_RAX,
|
||||
t.ASM_DESCR.CLOBBER_RCX, t.ASM_DESCR.CLOBBER_RDX,
|
||||
|
||||
@@ -23,25 +23,25 @@ USER_STACK_SIZE: t.CDefine = 65536
|
||||
|
||||
@t.Object
|
||||
class Process:
|
||||
pid: t.CInt
|
||||
pml4_root: t.CUInt64T
|
||||
threads: t.CArray[t.CInt, 8]
|
||||
thread_count: t.CInt
|
||||
state: t.CInt
|
||||
entry: t.CVoid | t.CPtr
|
||||
elf_base: t.CUInt64T
|
||||
heap_start: t.CUInt64T
|
||||
heap_size: t.CUInt64T
|
||||
pid: int
|
||||
pml4_root: uint64
|
||||
threads: t.CArray[int, 8]
|
||||
thread_count: int
|
||||
state: int
|
||||
entry: t.CPtr
|
||||
elf_base: uint64
|
||||
heap_start: uint64
|
||||
heap_size: uint64
|
||||
name: t.CArray[t.CChar, 32]
|
||||
fd_table: t.CArray[t.CVoid | t.CPtr, PROC_MAX_FDS]
|
||||
fd_used: t.CArray[t.CUInt8T, PROC_MAX_FDS]
|
||||
dir_table: t.CArray[t.CVoid | t.CPtr, PROC_MAX_DIRS]
|
||||
dir_used: t.CArray[t.CUInt8T, PROC_MAX_DIRS]
|
||||
fd_table: t.CArray[t.CPtr, PROC_MAX_FDS]
|
||||
fd_used: t.CArray[uint8, PROC_MAX_FDS]
|
||||
dir_table: t.CArray[t.CPtr, PROC_MAX_DIRS]
|
||||
dir_used: t.CArray[uint8, PROC_MAX_DIRS]
|
||||
dir_pool: t.CArray[fat32_types.dirobj, PROC_MAX_DIRS]
|
||||
kern_stack: t.CUInt64T
|
||||
user_stack: t.CUInt64T
|
||||
kern_stack: uint64
|
||||
user_stack: uint64
|
||||
|
||||
def addThread(self, tid: t.CInt) -> t.CInt:
|
||||
def addThread(self, tid: int) -> int:
|
||||
if self.thread_count >= MAX_PROC_THREADS: return -1
|
||||
self.threads[self.thread_count] = tid
|
||||
self.thread_count += 1
|
||||
@@ -51,14 +51,14 @@ class Process:
|
||||
self.state = PROC_DONE
|
||||
for i in range(PROC_MAX_FDS):
|
||||
if self.fd_used[i]:
|
||||
fp: t.CVoid | t.CPtr = self.fd_table[i]
|
||||
fp: t.CPtr = self.fd_table[i]
|
||||
if fp:
|
||||
fat32.close(fp)
|
||||
self.fd_used[i] = 0
|
||||
self.fd_table[i] = t.CVoid(0, t.CPtr)
|
||||
for i in range(PROC_MAX_DIRS):
|
||||
if self.dir_used[i]:
|
||||
dp: t.CVoid | t.CPtr = self.dir_table[i]
|
||||
dp: t.CPtr = self.dir_table[i]
|
||||
if dp:
|
||||
fat32.closedir(dp)
|
||||
self.dir_used[i] = 0
|
||||
@@ -68,20 +68,20 @@ class Process:
|
||||
m.current_pid = 0
|
||||
m.processes[0].state = PROC_RUNNING
|
||||
if self.pml4_root != 0:
|
||||
kernel_cr3: t.CUInt64T = m.processes[0].pml4_root
|
||||
kernel_cr3: uint64 = m.processes[0].pml4_root
|
||||
if kernel_cr3 != 0:
|
||||
c.Asm(f"mov cr3, {c.AsmInp(kernel_cr3, t.ASM_DESCR.REG_ANY)}",
|
||||
op=[t.ASM_DESCR.CLOBBER_MEMORY])
|
||||
paging.set_active_pml4(kernel_cr3)
|
||||
|
||||
@property
|
||||
def is_running(self) -> t.CInt:
|
||||
def is_running(self) -> int:
|
||||
if self.state == PROC_RUNNING:
|
||||
return 1
|
||||
return 0
|
||||
|
||||
@property
|
||||
def is_done(self) -> t.CInt:
|
||||
def is_done(self) -> int:
|
||||
if self.state == PROC_DONE:
|
||||
return 1
|
||||
return 0
|
||||
@@ -90,8 +90,8 @@ class Process:
|
||||
@t.Object
|
||||
class ProcessManager:
|
||||
processes: t.CArray[Process, MAX_PROCESSES]
|
||||
current_pid: t.CInt
|
||||
count: t.CInt
|
||||
current_pid: int
|
||||
count: int
|
||||
|
||||
def __init__(self):
|
||||
global _proc_mgr_ptr
|
||||
@@ -109,13 +109,13 @@ class ProcessManager:
|
||||
p.heap_start = 0
|
||||
p.heap_size = 0
|
||||
name_str: str = "kernel"
|
||||
i: t.CInt = 0
|
||||
i: int = 0
|
||||
for ch in name_str:
|
||||
if i >= 31: break
|
||||
p.name[i] = ch
|
||||
i += 1
|
||||
p.name[i] = 0
|
||||
j: t.CInt
|
||||
j: int
|
||||
for j in range(MAX_PROC_THREADS):
|
||||
p.threads[j] = -1
|
||||
for j in range(PROC_MAX_FDS):
|
||||
@@ -128,13 +128,13 @@ class ProcessManager:
|
||||
op=[t.ASM_DESCR.CLOBBER_MEMORY])
|
||||
|
||||
@staticmethod
|
||||
def _switch(pid: t.CInt) -> t.CInt:
|
||||
def _switch(pid: int) -> int:
|
||||
global _saved_cr3
|
||||
m: ProcessManager | t.CPtr = _proc_mgr_ptr
|
||||
if pid < 0 or pid >= m.count: return -1
|
||||
p: Process | t.CPtr = c.Addr(m.processes[pid])
|
||||
if p.state == PROC_DONE: return -1
|
||||
old_pid: t.CInt = m.current_pid
|
||||
old_pid: int = m.current_pid
|
||||
if old_pid == pid: return 0
|
||||
if old_pid >= 0 and old_pid < m.count:
|
||||
m.processes[old_pid].state = PROC_READY
|
||||
@@ -152,19 +152,19 @@ class ProcessManager:
|
||||
return c.Addr(m.processes[m.current_pid])
|
||||
|
||||
@staticmethod
|
||||
def get_process(pid: t.CInt) -> Process | t.CPtr:
|
||||
def get_process(pid: int) -> Process | t.CPtr:
|
||||
m: ProcessManager | t.CPtr = _proc_mgr_ptr
|
||||
if pid < 0 or pid >= m.count: return None
|
||||
return c.Addr(m.processes[pid])
|
||||
|
||||
@staticmethod
|
||||
def create_process(name: str, entry: t.CVoid | t.CPtr) -> Process | t.CPtr:
|
||||
def create_process(name: str, entry: t.CPtr) -> Process | t.CPtr:
|
||||
m: ProcessManager | t.CPtr = _proc_mgr_ptr
|
||||
_dbp: t.CArray[t.CChar, 80]
|
||||
viperlib.snprintf(c.Addr(_dbp), 80, "[process] create_process count=%d MAX=%d\n", m.count, MAX_PROCESSES)
|
||||
serial.puts(_dbp)
|
||||
if m.count >= MAX_PROCESSES: return None
|
||||
pid: t.CInt = m.count
|
||||
pid: int = m.count
|
||||
m.count += 1
|
||||
p: Process | t.CPtr = c.Addr(m.processes[pid])
|
||||
p.pid = pid
|
||||
@@ -175,13 +175,13 @@ class ProcessManager:
|
||||
p.heap_start = 0
|
||||
p.heap_size = 0
|
||||
string.memset(c.Addr(p.name), 0, 32)
|
||||
i: t.CInt = 0
|
||||
i: int = 0
|
||||
for ch in name:
|
||||
if i >= 31: break
|
||||
p.name[i] = ch
|
||||
i += 1
|
||||
p.name[i] = 0
|
||||
j: t.CInt
|
||||
j: int
|
||||
for j in range(MAX_PROC_THREADS):
|
||||
p.threads[j] = -1
|
||||
for j in range(PROC_MAX_FDS):
|
||||
@@ -190,29 +190,29 @@ class ProcessManager:
|
||||
for j in range(PROC_MAX_DIRS):
|
||||
p.dir_used[j] = 0
|
||||
p.dir_table[j] = t.CVoid(0, t.CPtr)
|
||||
ks: t.CVoid | t.CPtr = mm_mm.malloc(KERN_STACK_SIZE)
|
||||
ks: t.CPtr = mm_mm.malloc(KERN_STACK_SIZE)
|
||||
# [DIAG] 定位跨模块 malloc 返回值(mm 成功但调用方收到 None)
|
||||
_dbg_ks: t.CArray[t.CChar, 64]
|
||||
viperlib.snprintf(c.Addr(_dbg_ks), 64, "[proc] ks=0x%lx\n", t.CUInt64T(ks))
|
||||
viperlib.snprintf(c.Addr(_dbg_ks), 64, "[proc] ks=0x%lx\n", uint64(ks))
|
||||
serial.puts(c.Addr(_dbg_ks))
|
||||
if ks is None:
|
||||
serial.puts("[process] kernel stack alloc failed\n")
|
||||
m.count = m.count - 1
|
||||
return None
|
||||
ks_size: t.CUInt64T = KERN_STACK_SIZE
|
||||
p.kern_stack = t.CUInt64T(ks) + ks_size
|
||||
us: t.CVoid | t.CPtr = mm_mm.malloc(USER_STACK_SIZE)
|
||||
ks_size: uint64 = KERN_STACK_SIZE
|
||||
p.kern_stack = uint64(ks) + ks_size
|
||||
us: t.CPtr = mm_mm.malloc(USER_STACK_SIZE)
|
||||
# [DIAG] 定位 user_stack 收到 None(mm 内部打印成功但此处收 0x0)
|
||||
_dbg_us: t.CArray[t.CChar, 64]
|
||||
viperlib.snprintf(c.Addr(_dbg_us), 64, "[proc] us=0x%lx\n", t.CUInt64T(us))
|
||||
viperlib.snprintf(c.Addr(_dbg_us), 64, "[proc] us=0x%lx\n", uint64(us))
|
||||
serial.puts(c.Addr(_dbg_us))
|
||||
if us is None:
|
||||
serial.puts("[process] user stack alloc failed\n")
|
||||
mm_mm.free(ks)
|
||||
m.count = m.count - 1
|
||||
return None
|
||||
us_size: t.CUInt64T = USER_STACK_SIZE
|
||||
p.user_stack = t.CUInt64T(us) + us_size
|
||||
us_size: uint64 = USER_STACK_SIZE
|
||||
p.user_stack = uint64(us) + us_size
|
||||
c.Asm(f"""mov {c.AsmOut(p.pml4_root, t.ASM_DESCR.OUTPUT_REG)}, cr3""",
|
||||
op=[t.ASM_DESCR.CLOBBER_MEMORY, t.ASM_DESCR.CLOBBER_RAX])
|
||||
return p
|
||||
@@ -220,13 +220,13 @@ class ProcessManager:
|
||||
|
||||
_proc_mgr: ProcessManager = ProcessManager()
|
||||
_proc_mgr_ptr: ProcessManager | t.CPtr = c.Addr(_proc_mgr)
|
||||
_saved_cr3: t.CUInt64T | t.CExport
|
||||
_saved_cr3: uint64 | t.CExport
|
||||
|
||||
def current() -> t.CInt:
|
||||
def current() -> int:
|
||||
m: ProcessManager | t.CPtr = _proc_mgr_ptr
|
||||
return m.current_pid
|
||||
|
||||
def switch_pid(new_pid: t.CInt):
|
||||
def switch_pid(new_pid: int):
|
||||
m: ProcessManager | t.CPtr = _proc_mgr_ptr
|
||||
if m.current_pid == new_pid: return
|
||||
if m.current_pid >= 0 and m.current_pid < m.count:
|
||||
@@ -236,7 +236,7 @@ def switch_pid(new_pid: t.CInt):
|
||||
if new_pid >= 0 and new_pid < m.count:
|
||||
new_p: Process | t.CPtr = c.Addr(m.processes[new_pid])
|
||||
new_p.state = PROC_RUNNING
|
||||
new_cr3: t.CUInt64T = new_p.pml4_root
|
||||
new_cr3: uint64 = new_p.pml4_root
|
||||
if new_cr3 != 0:
|
||||
c.Asm(f"mov cr3, {c.AsmInp(new_cr3, t.ASM_DESCR.REG_ANY)}",
|
||||
op=[t.ASM_DESCR.CLOBBER_MEMORY])
|
||||
@@ -248,18 +248,18 @@ def switch_pid(new_pid: t.CInt):
|
||||
cpu.set_kernel_rsp0(new_p.kern_stack)
|
||||
m.current_pid = new_pid
|
||||
|
||||
def get_pid(tid: t.CInt) -> t.CInt:
|
||||
def get_pid(tid: int) -> int:
|
||||
m: ProcessManager | t.CPtr = _proc_mgr_ptr
|
||||
i: t.CInt
|
||||
i: int
|
||||
for i in range(m.count):
|
||||
p: Process | t.CPtr = c.Addr(m.processes[i])
|
||||
j: t.CInt
|
||||
j: int
|
||||
for j in range(p.thread_count):
|
||||
if p.threads[j] == tid:
|
||||
return p.pid
|
||||
return -1
|
||||
|
||||
def drop_to_user_mode(entry: t.CVoid | t.CPtr, user_rsp: t.CUInt64T, kern_rsp: t.CUInt64T):
|
||||
def drop_to_user_mode(entry: t.CPtr, user_rsp: uint64, kern_rsp: uint64):
|
||||
# NOTE: Do NOT swapgs here. This OS uses reverse GS convention:
|
||||
# GS_BASE = 0 (kernel & user), KERNEL_GS_BASE = &_per_cpu
|
||||
# syscall/ISR entry does swapgs to get GS_BASE = &_per_cpu
|
||||
|
||||
@@ -14,20 +14,20 @@ MAX_THREADS: t.CDefine = 16
|
||||
THREAD_STACK_SIZE: t.CDefine = 65536
|
||||
SCHED_QUANTUM: t.CDefine = 10
|
||||
|
||||
_yield_cnt: t.CUInt32T = 0
|
||||
_yield_lock: t.CInt = 0
|
||||
_yield_cnt: uint32 = 0
|
||||
_yield_lock: int = 0
|
||||
|
||||
|
||||
@t.Object
|
||||
class Thread:
|
||||
rsp: t.CUInt64T
|
||||
stack: t.CVoid | t.CPtr
|
||||
stack_size: t.CUInt64T
|
||||
func: t.CVoid | t.CPtr
|
||||
arg: t.CVoid | t.CPtr
|
||||
state: t.CInt
|
||||
rsp: uint64
|
||||
stack: t.CPtr
|
||||
stack_size: uint64
|
||||
func: t.CPtr
|
||||
arg: t.CPtr
|
||||
state: int
|
||||
tid: int
|
||||
pid: t.CInt
|
||||
pid: int
|
||||
|
||||
def block(self):
|
||||
self.state = THREAD_BLOCKED
|
||||
@@ -38,19 +38,19 @@ class Thread:
|
||||
self.state = THREAD_READY
|
||||
|
||||
@property
|
||||
def is_running(self) -> t.CInt:
|
||||
def is_running(self) -> int:
|
||||
if self.state == THREAD_RUNNING:
|
||||
return 1
|
||||
return 0
|
||||
|
||||
@property
|
||||
def is_blocked(self) -> t.CInt:
|
||||
def is_blocked(self) -> int:
|
||||
if self.state == THREAD_BLOCKED:
|
||||
return 1
|
||||
return 0
|
||||
|
||||
@property
|
||||
def is_done(self) -> t.CInt:
|
||||
def is_done(self) -> int:
|
||||
if self.state == THREAD_DONE:
|
||||
return 1
|
||||
return 0
|
||||
@@ -59,11 +59,11 @@ class Thread:
|
||||
@t.Object
|
||||
class Scheduler:
|
||||
threads: t.CArray[Thread, MAX_THREADS]
|
||||
current_tid: t.CInt
|
||||
thread_count: t.CInt
|
||||
enabled: t.CInt
|
||||
needs_reschedule: t.CInt
|
||||
tick_count: t.CInt
|
||||
current_tid: int
|
||||
thread_count: int
|
||||
enabled: int
|
||||
needs_reschedule: int
|
||||
tick_count: int
|
||||
|
||||
def __init__(self):
|
||||
global _sched_ptr
|
||||
@@ -87,14 +87,14 @@ class Scheduler:
|
||||
s.enabled = 1
|
||||
s.threads[0].state = THREAD_RUNNING
|
||||
s.threads[0].tid = 0
|
||||
main_rsp_ptr: t.CVoid | t.CPtr = c.Addr(s.threads[0].rsp)
|
||||
main_rsp_ptr: t.CPtr = c.Addr(s.threads[0].rsp)
|
||||
c.Asm(f"""mov qword ptr [{c.AsmInp(main_rsp_ptr, t.ASM_DESCR.REG_ANY)}], rsp""",
|
||||
op=[t.ASM_DESCR.CLOBBER_MEMORY])
|
||||
|
||||
@staticmethod
|
||||
def _yield():
|
||||
global _switch_old_rsp, _switch_new_rsp, _yield_cnt, _yield_lock
|
||||
_if_saved: t.CInt = 0
|
||||
_if_saved: int = 0
|
||||
c.Asm(f"""pushfq
|
||||
pop rax
|
||||
shr rax, 9
|
||||
@@ -110,14 +110,14 @@ class Scheduler:
|
||||
s: Scheduler | t.CPtr = _sched_ptr
|
||||
s.needs_reschedule = 0
|
||||
s.tick_count = 0
|
||||
old_tid: t.CInt = s.current_tid
|
||||
next_tid: t.CInt = old_tid + 1
|
||||
old_tid: int = s.current_tid
|
||||
next_tid: int = old_tid + 1
|
||||
if next_tid >= s.thread_count:
|
||||
next_tid = 0
|
||||
found: t.CInt = 0
|
||||
count: t.CInt = 0
|
||||
found: int = 0
|
||||
count: int = 0
|
||||
while count < s.thread_count:
|
||||
st: t.CInt = s.threads[next_tid].state
|
||||
st: int = s.threads[next_tid].state
|
||||
if st == THREAD_READY or st == THREAD_RUNNING:
|
||||
found = 1
|
||||
break
|
||||
@@ -141,7 +141,7 @@ class Scheduler:
|
||||
_switch_old_rsp = c.Addr(s.threads[old_tid].rsp)
|
||||
_switch_new_rsp = c.Addr(s.threads[next_tid].rsp)
|
||||
s.current_tid = next_tid
|
||||
next_pid: t.CInt = s.threads[next_tid].pid
|
||||
next_pid: int = s.threads[next_tid].pid
|
||||
_yield_cnt += 1
|
||||
proc.switch_pid(next_pid)
|
||||
_yield_lock = 0
|
||||
@@ -182,13 +182,13 @@ class Scheduler:
|
||||
return c.Addr(s.threads[s.current_tid])
|
||||
|
||||
@staticmethod
|
||||
def get_thread(tid: t.CInt) -> Thread | t.CPtr:
|
||||
def get_thread(tid: int) -> Thread | t.CPtr:
|
||||
s: Scheduler | t.CPtr = _sched_ptr
|
||||
if tid < 0 or tid >= s.thread_count: return None
|
||||
return c.Addr(s.threads[tid])
|
||||
|
||||
@staticmethod
|
||||
def create_thread(func: t.CVoid | t.CPtr, arg: t.CVoid | t.CPtr, thread_pid: t.CInt = 0) -> Thread | t.CPtr:
|
||||
def create_thread(func: t.CPtr, arg: t.CPtr, thread_pid: int = 0) -> Thread | t.CPtr:
|
||||
s: Scheduler | t.CPtr = _sched_ptr
|
||||
if s.thread_count >= MAX_THREADS: return None
|
||||
tid: int = s.thread_count
|
||||
@@ -199,11 +199,11 @@ class Scheduler:
|
||||
th.pid = thread_pid
|
||||
th.func = func
|
||||
th.arg = arg
|
||||
stack_size: t.CUInt64T = THREAD_STACK_SIZE
|
||||
stack_ptr: t.CVoid | t.CPtr = mm.malloc(stack_size)
|
||||
stack_size: uint64 = THREAD_STACK_SIZE
|
||||
stack_ptr: t.CPtr = mm.malloc(stack_size)
|
||||
_dbg_ct: t.CArray[t.CChar, 96]
|
||||
viperlib.snprintf(c.Addr(_dbg_ct), 96, "[sched] ct t%d func=0x%lx stack=0x%lx\n",
|
||||
tid, t.CUInt64T(th.func), t.CUInt64T(stack_ptr))
|
||||
tid, uint64(th.func), uint64(stack_ptr))
|
||||
serial.puts(c.Addr(_dbg_ct))
|
||||
if not stack_ptr:
|
||||
# B4:栈分配失败回退槽位计数(对齐 process.vp create_process 失败路径),
|
||||
@@ -212,9 +212,9 @@ class Scheduler:
|
||||
return None
|
||||
th.stack = stack_ptr
|
||||
th.stack_size = stack_size
|
||||
stack_top: t.CUInt64T = t.CUInt64T(stack_ptr) + stack_size - 16
|
||||
stack_top = stack_top & ~t.CUInt64T(0xF)
|
||||
entry_addr: t.CUInt64T = t.CUInt64T(c.Addr(_thread_entry))
|
||||
stack_top: uint64 = uint64(stack_ptr) + stack_size - 16
|
||||
stack_top = stack_top & ~uint64(0xF)
|
||||
entry_addr: uint64 = uint64(c.Addr(_thread_entry))
|
||||
sp: t.CPtr = t.CPtr(stack_top)
|
||||
c.Asm(f"""mov rax, {c.AsmInp(sp, t.ASM_DESCR.REG_ANY)}
|
||||
mov qword ptr [rax - 64], 0x202
|
||||
@@ -234,8 +234,8 @@ class Scheduler:
|
||||
|
||||
_sched_storage: Scheduler = Scheduler()
|
||||
_sched_ptr: Scheduler | t.CPtr | t.CExport = c.Addr(_sched_storage)
|
||||
_switch_old_rsp: t.CVoid | t.CPtr | t.CExport
|
||||
_switch_new_rsp: t.CVoid | t.CPtr | t.CExport
|
||||
_switch_old_rsp: t.CPtr | t.CExport
|
||||
_switch_new_rsp: t.CPtr | t.CExport
|
||||
|
||||
@c.Attribute(t.attr.naked)
|
||||
def _do_switch():
|
||||
@@ -288,11 +288,11 @@ def _thread_entry():
|
||||
asm.hlt()
|
||||
Scheduler._yield()
|
||||
|
||||
def thread_current() -> t.CInt:
|
||||
def thread_current() -> int:
|
||||
s: Scheduler | t.CPtr = _sched_ptr
|
||||
return s.current_tid
|
||||
|
||||
def needs_reschedule() -> t.CInt:
|
||||
def needs_reschedule() -> int:
|
||||
s: Scheduler | t.CPtr = _sched_ptr
|
||||
return s.needs_reschedule
|
||||
|
||||
|
||||
+624
-624
File diff suppressed because it is too large.
Load diff
@@ -10,7 +10,7 @@ SERVICE_KEYBOARD: t.CDefine = 1
|
||||
@t.Object
|
||||
class KeyboardService:
|
||||
th: sched.Thread | t.CPtr
|
||||
running: t.CInt
|
||||
running: int
|
||||
usb_kbd_th: sched.Thread | t.CPtr
|
||||
|
||||
def __init__(self):
|
||||
@@ -21,16 +21,16 @@ class KeyboardService:
|
||||
kbd_svc: KeyboardService
|
||||
|
||||
|
||||
def kbd_thread(arg: t.CVoid | t.CPtr) -> t.CInt:
|
||||
def kbd_thread(arg: t.CPtr) -> int:
|
||||
serial.puts("[kbd_svc] started\n")
|
||||
while True:
|
||||
if keyboard.has_data():
|
||||
sc: t.CUInt8T = keyboard.read_scancode()
|
||||
sc: uint8 = keyboard.read_scancode()
|
||||
else:
|
||||
sched.Scheduler._yield()
|
||||
return 0
|
||||
|
||||
def usb_kbd_thread(arg: t.CVoid | t.CPtr) -> t.CInt:
|
||||
def usb_kbd_thread(arg: t.CPtr) -> int:
|
||||
serial.puts("[usb_kbd_svc] started\n")
|
||||
evt: usb_kbd.usb_kbd_event
|
||||
while True:
|
||||
@@ -40,7 +40,7 @@ def usb_kbd_thread(arg: t.CVoid | t.CPtr) -> t.CInt:
|
||||
sched.Scheduler._yield()
|
||||
return 0
|
||||
|
||||
def start() -> t.CInt:
|
||||
def start() -> int:
|
||||
global kbd_svc
|
||||
kbd_svc = KeyboardService()
|
||||
keyboard.init()
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
import t, c
|
||||
import drivers.input.mouse.mouse as mouse
|
||||
import drivers.usb.hid.usb_mouse as usb_mouse
|
||||
import drivers.serial.uart.serial as serial
|
||||
import sched.sched as sched
|
||||
|
||||
SERVICE_MOUSE: t.CDefine = 2
|
||||
|
||||
def start() -> t.CInt:
|
||||
serial.puts("[mse_svc] mouse initialized\n")
|
||||
if usb_mouse.init() == 0:
|
||||
serial.puts("[mse_svc] usb mouse initialized\n")
|
||||
return 0
|
||||
import t, c
|
||||
import drivers.input.mouse.mouse as mouse
|
||||
import drivers.usb.hid.usb_mouse as usb_mouse
|
||||
import drivers.serial.uart.serial as serial
|
||||
import sched.sched as sched
|
||||
|
||||
SERVICE_MOUSE: t.CDefine = 2
|
||||
|
||||
def start() -> int:
|
||||
serial.puts("[mse_svc] mouse initialized\n")
|
||||
if usb_mouse.init() == 0:
|
||||
serial.puts("[mse_svc] usb mouse initialized\n")
|
||||
return 0
|
||||
+8
-8
@@ -1,8 +1,8 @@
|
||||
import t, c
|
||||
from . import syscall as syscall
|
||||
|
||||
def load_so(path: t.CConst | t.CChar | t.CPtr) -> t.CUInt64T:
|
||||
return syscall._syscall1(t.CUInt64T(syscall.LOAD_SO), t.CUInt64T(path))
|
||||
|
||||
def so_call1(sym_name: t.CConst | t.CChar | t.CPtr, arg1: t.CVoid | t.CPtr) -> t.CInt:
|
||||
return t.CInt(syscall._syscall2(t.CUInt64T(syscall.SO_CALL1), t.CUInt64T(sym_name), t.CUInt64T(arg1)))
|
||||
import t, c
|
||||
from . import syscall as syscall
|
||||
|
||||
def load_so(path: t.CConst | t.CChar | t.CPtr) -> uint64:
|
||||
return syscall._syscall1(uint64(syscall.LOAD_SO), uint64(path))
|
||||
|
||||
def so_call1(sym_name: t.CConst | t.CChar | t.CPtr, arg1: t.CPtr) -> int:
|
||||
return int(syscall._syscall2(uint64(syscall.SO_CALL1), uint64(sym_name), uint64(arg1)))
|
||||
+53
-53
@@ -16,126 +16,126 @@ DT_UNKNOWN: t.CDefine = 0
|
||||
DT_FILE: t.CDefine = 1
|
||||
DT_DIR: t.CDefine = 2
|
||||
|
||||
def open(path: t.CConst | t.CChar | t.CPtr, flags: t.CUInt32T) -> t.CInt:
|
||||
return t.CInt(syscall._syscall3(t.CUInt64T(syscall.OPEN), t.CUInt64T(path), t.CUInt64T(flags), 0))
|
||||
def open(path: t.CConst | t.CChar | t.CPtr, flags: uint32) -> int:
|
||||
return int(syscall._syscall3(uint64(syscall.OPEN), uint64(path), uint64(flags), 0))
|
||||
|
||||
def close(fd: t.CInt) -> t.CInt:
|
||||
return t.CInt(syscall._syscall1(t.CUInt64T(syscall.CLOSE), t.CUInt64T(fd)))
|
||||
def close(fd: int) -> int:
|
||||
return int(syscall._syscall1(uint64(syscall.CLOSE), uint64(fd)))
|
||||
|
||||
def read(fd: t.CInt, buf: t.CVoid | t.CPtr, count: t.CUInt32T) -> t.CInt:
|
||||
return t.CInt(syscall._syscall3(t.CUInt64T(syscall.READ), t.CUInt64T(fd), t.CUInt64T(buf), t.CUInt64T(count)))
|
||||
def read(fd: int, buf: t.CPtr, count: uint32) -> int:
|
||||
return int(syscall._syscall3(uint64(syscall.READ), uint64(fd), uint64(buf), uint64(count)))
|
||||
|
||||
def write(fd: t.CInt, buf: t.CVoid | t.CPtr, count: t.CUInt32T) -> t.CInt:
|
||||
return t.CInt(syscall._syscall3(t.CUInt64T(syscall.WRITE), t.CUInt64T(fd), t.CUInt64T(buf), t.CUInt64T(count)))
|
||||
def write(fd: int, buf: t.CPtr, count: uint32) -> int:
|
||||
return int(syscall._syscall3(uint64(syscall.WRITE), uint64(fd), uint64(buf), uint64(count)))
|
||||
|
||||
def seek(fd: t.CInt, offset: t.CUInt32T) -> t.CInt:
|
||||
return t.CInt(syscall._syscall3(t.CUInt64T(syscall.SEEK), t.CUInt64T(fd), t.CUInt64T(offset), 0))
|
||||
def seek(fd: int, offset: uint32) -> int:
|
||||
return int(syscall._syscall3(uint64(syscall.SEEK), uint64(fd), uint64(offset), 0))
|
||||
|
||||
def tell(fd: t.CInt) -> t.CUInt32T:
|
||||
return t.CUInt32T(syscall._syscall1(t.CUInt64T(syscall.TELL), t.CUInt64T(fd)))
|
||||
def tell(fd: int) -> uint32:
|
||||
return uint32(syscall._syscall1(uint64(syscall.TELL), uint64(fd)))
|
||||
|
||||
def fsize(fd: t.CInt) -> t.CUInt32T:
|
||||
return t.CUInt32T(syscall._syscall1(t.CUInt64T(syscall.SIZE), t.CUInt64T(fd)))
|
||||
def fsize(fd: int) -> uint32:
|
||||
return uint32(syscall._syscall1(uint64(syscall.SIZE), uint64(fd)))
|
||||
|
||||
def mkdir(path: t.CConst | t.CChar | t.CPtr) -> t.CInt:
|
||||
return t.CInt(syscall._syscall3(t.CUInt64T(syscall.MKDIR), t.CUInt64T(path), 0, 0))
|
||||
def mkdir(path: t.CConst | t.CChar | t.CPtr) -> int:
|
||||
return int(syscall._syscall3(uint64(syscall.MKDIR), uint64(path), 0, 0))
|
||||
|
||||
def remove(path: t.CConst | t.CChar | t.CPtr) -> t.CInt:
|
||||
return t.CInt(syscall._syscall3(t.CUInt64T(syscall.REMOVE), t.CUInt64T(path), 0, 0))
|
||||
def remove(path: t.CConst | t.CChar | t.CPtr) -> int:
|
||||
return int(syscall._syscall3(uint64(syscall.REMOVE), uint64(path), 0, 0))
|
||||
|
||||
def opendir(path: t.CConst | t.CChar | t.CPtr) -> t.CInt:
|
||||
return t.CInt(syscall._syscall3(t.CUInt64T(syscall.OPENDIR), t.CUInt64T(path), 0, 0))
|
||||
def opendir(path: t.CConst | t.CChar | t.CPtr) -> int:
|
||||
return int(syscall._syscall3(uint64(syscall.OPENDIR), uint64(path), 0, 0))
|
||||
|
||||
def readdir(dd: t.CInt, info: t.CVoid | t.CPtr) -> t.CInt:
|
||||
return t.CInt(syscall._syscall3(t.CUInt64T(syscall.READDIR), t.CUInt64T(dd), t.CUInt64T(info), 0))
|
||||
def readdir(dd: int, info: t.CPtr) -> int:
|
||||
return int(syscall._syscall3(uint64(syscall.READDIR), uint64(dd), uint64(info), 0))
|
||||
|
||||
def closedir(dd: t.CInt) -> t.CInt:
|
||||
return t.CInt(syscall._syscall1(t.CUInt64T(syscall.CLOSEDIR), t.CUInt64T(dd)))
|
||||
def closedir(dd: int) -> int:
|
||||
return int(syscall._syscall1(uint64(syscall.CLOSEDIR), uint64(dd)))
|
||||
|
||||
def stat(path: t.CConst | t.CChar | t.CPtr, info: t.CVoid | t.CPtr) -> t.CInt:
|
||||
return t.CInt(syscall._syscall3(t.CUInt64T(syscall.STAT), t.CUInt64T(path), t.CUInt64T(info), 0))
|
||||
def stat(path: t.CConst | t.CChar | t.CPtr, info: t.CPtr) -> int:
|
||||
return int(syscall._syscall3(uint64(syscall.STAT), uint64(path), uint64(info), 0))
|
||||
|
||||
@t.Object
|
||||
class FileIO:
|
||||
_fd: t.CInt
|
||||
_pos: t.CUInt32T
|
||||
_size: t.CUInt32T
|
||||
_flags: t.CUInt32T
|
||||
_closed: t.CInt
|
||||
_fd: int
|
||||
_pos: uint32
|
||||
_size: uint32
|
||||
_flags: uint32
|
||||
_closed: int
|
||||
|
||||
def __init__(self, fd: t.CInt, flags: t.CUInt32T):
|
||||
def __init__(self, fd: int, flags: uint32):
|
||||
self._fd = fd
|
||||
self._flags = flags
|
||||
self._pos = 0
|
||||
self._size = fsize(fd)
|
||||
self._closed = 0
|
||||
|
||||
def read(self, buf: t.CVoid | t.CPtr, count: t.CUInt32T) -> t.CInt:
|
||||
def read(self, buf: t.CPtr, count: uint32) -> int:
|
||||
if self._closed: return -1
|
||||
n: t.CInt = read(self._fd, buf, count)
|
||||
n: int = read(self._fd, buf, count)
|
||||
if n > 0:
|
||||
self._pos = self._pos + t.CUInt32T(n)
|
||||
self._pos = self._pos + uint32(n)
|
||||
return n
|
||||
|
||||
def write(self, buf: t.CVoid | t.CPtr, count: t.CUInt32T) -> t.CInt:
|
||||
def write(self, buf: t.CPtr, count: uint32) -> int:
|
||||
if self._closed: return -1
|
||||
n: t.CInt = write(self._fd, buf, count)
|
||||
n: int = write(self._fd, buf, count)
|
||||
if n > 0:
|
||||
self._pos = self._pos + t.CUInt32T(n)
|
||||
self._pos = self._pos + uint32(n)
|
||||
if self._pos > self._size:
|
||||
self._size = self._pos
|
||||
return n
|
||||
|
||||
def seek(self, offset: t.CUInt32T) -> t.CInt:
|
||||
def seek(self, offset: uint32) -> int:
|
||||
if self._closed: return -1
|
||||
res: t.CInt = seek(self._fd, offset)
|
||||
res: int = seek(self._fd, offset)
|
||||
if res == 0:
|
||||
self._pos = offset
|
||||
return res
|
||||
|
||||
def tell(self) -> t.CUInt32T:
|
||||
def tell(self) -> uint32:
|
||||
return self._pos
|
||||
|
||||
def size(self) -> t.CUInt32T:
|
||||
def size(self) -> uint32:
|
||||
return self._size
|
||||
|
||||
def close(self) -> t.CInt:
|
||||
def close(self) -> int:
|
||||
if self._closed: return 0
|
||||
self._closed = 1
|
||||
return close(self._fd)
|
||||
|
||||
def is_closed(self) -> t.CInt:
|
||||
def is_closed(self) -> int:
|
||||
return self._closed
|
||||
|
||||
@t.Object
|
||||
class DirIO:
|
||||
_dd: t.CInt
|
||||
_closed: t.CInt
|
||||
_dd: int
|
||||
_closed: int
|
||||
|
||||
def __init__(self, dd: t.CInt):
|
||||
def __init__(self, dd: int):
|
||||
self._dd = dd
|
||||
self._closed = 0
|
||||
|
||||
def read(self, info: t.CVoid | t.CPtr) -> t.CInt:
|
||||
def read(self, info: t.CPtr) -> int:
|
||||
if self._closed: return -1
|
||||
return readdir(self._dd, info)
|
||||
|
||||
def close(self) -> t.CInt:
|
||||
def close(self) -> int:
|
||||
if self._closed: return 0
|
||||
self._closed = 1
|
||||
return closedir(self._dd)
|
||||
|
||||
def is_closed(self) -> t.CInt:
|
||||
def is_closed(self) -> int:
|
||||
return self._closed
|
||||
|
||||
def open_file(path: t.CConst | t.CChar | t.CPtr, flags: t.CUInt32T) -> FileIO | t.CPtr:
|
||||
fd: t.CInt = open(path, flags)
|
||||
def open_file(path: t.CConst | t.CChar | t.CPtr, flags: uint32) -> FileIO | t.CPtr:
|
||||
fd: int = open(path, flags)
|
||||
if fd < 0:
|
||||
return None
|
||||
return FileIO(fd, flags)
|
||||
|
||||
def open_dir(path: t.CConst | t.CChar | t.CPtr) -> DirIO | t.CPtr:
|
||||
dd: t.CInt = opendir(path)
|
||||
dd: int = opendir(path)
|
||||
if dd < 0:
|
||||
return None
|
||||
return DirIO(dd)
|
||||
+65
-65
@@ -1,65 +1,65 @@
|
||||
import t, c
|
||||
from . import syscall as syscall
|
||||
|
||||
def exit(code: t.CInt) -> t.CVoid:
|
||||
syscall._syscall1(t.CUInt64T(syscall.EXIT), t.CUInt64T(code))
|
||||
|
||||
def yield_cpu() -> t.CVoid:
|
||||
syscall._syscall2(t.CUInt64T(syscall.WAIT_WINDOW), t.CUInt64T(0), t.CUInt64T(2))
|
||||
|
||||
def spawn(path: t.CConst | t.CChar | t.CPtr, blocking: t.CInt = 0) -> t.CInt:
|
||||
return t.CInt(syscall._syscall2(t.CUInt64T(syscall.SPAWN), t.CUInt64T(path), t.CUInt64T(blocking)))
|
||||
|
||||
def thread_create(func: t.CVoid | t.CPtr, arg: t.CVoid | t.CPtr = None) -> t.CInt:
|
||||
return t.CInt(syscall._syscall2(t.CUInt64T(syscall.THREAD_CREATE), t.CUInt64T(func), t.CUInt64T(arg)))
|
||||
|
||||
@t.Object
|
||||
class Thread:
|
||||
_tid: t.CInt
|
||||
_func: t.CVoid | t.CPtr
|
||||
_arg: t.CVoid | t.CPtr
|
||||
_running: t.CInt
|
||||
|
||||
def __init__(self, func: t.CVoid | t.CPtr, arg: t.CVoid | t.CPtr = None):
|
||||
self._func = func
|
||||
self._arg = arg
|
||||
self._tid = -1
|
||||
self._running = 0
|
||||
|
||||
def start(self) -> t.CInt:
|
||||
if self._running: return -1
|
||||
self._tid = thread_create(self._func, self._arg)
|
||||
if self._tid < 0: return -1
|
||||
self._running = 1
|
||||
return 0
|
||||
|
||||
def is_alive(self) -> t.CInt:
|
||||
return self._running
|
||||
|
||||
def get_tid(self) -> t.CInt:
|
||||
return self._tid
|
||||
|
||||
@t.Object
|
||||
class Process:
|
||||
_pid: t.CInt
|
||||
_path: t.CArray[t.CChar, 128]
|
||||
|
||||
def __init__(self, path: t.CConst | t.CChar | t.CPtr):
|
||||
self._pid = -1
|
||||
i: t.CInt = 0
|
||||
for ch in path:
|
||||
if i >= 127: break
|
||||
self._path[i] = ch
|
||||
i += 1
|
||||
self._path[i] = 0
|
||||
|
||||
def start(self) -> t.CInt:
|
||||
self._pid = spawn(c.Addr(self._path[0]), 0)
|
||||
return self._pid
|
||||
|
||||
def start_blocking(self) -> t.CInt:
|
||||
self._pid = spawn(c.Addr(self._path[0]), 1)
|
||||
return self._pid
|
||||
|
||||
def get_pid(self) -> t.CInt:
|
||||
return self._pid
|
||||
import t, c
|
||||
from . import syscall as syscall
|
||||
|
||||
def exit(code: int) -> t.CVoid:
|
||||
syscall._syscall1(uint64(syscall.EXIT), uint64(code))
|
||||
|
||||
def yield_cpu() -> t.CVoid:
|
||||
syscall._syscall2(uint64(syscall.WAIT_WINDOW), uint64(0), uint64(2))
|
||||
|
||||
def spawn(path: t.CConst | t.CChar | t.CPtr, blocking: int = 0) -> int:
|
||||
return int(syscall._syscall2(uint64(syscall.SPAWN), uint64(path), uint64(blocking)))
|
||||
|
||||
def thread_create(func: t.CPtr, arg: t.CPtr = None) -> int:
|
||||
return int(syscall._syscall2(uint64(syscall.THREAD_CREATE), uint64(func), uint64(arg)))
|
||||
|
||||
@t.Object
|
||||
class Thread:
|
||||
_tid: int
|
||||
_func: t.CPtr
|
||||
_arg: t.CPtr
|
||||
_running: int
|
||||
|
||||
def __init__(self, func: t.CPtr, arg: t.CPtr = None):
|
||||
self._func = func
|
||||
self._arg = arg
|
||||
self._tid = -1
|
||||
self._running = 0
|
||||
|
||||
def start(self) -> int:
|
||||
if self._running: return -1
|
||||
self._tid = thread_create(self._func, self._arg)
|
||||
if self._tid < 0: return -1
|
||||
self._running = 1
|
||||
return 0
|
||||
|
||||
def is_alive(self) -> int:
|
||||
return self._running
|
||||
|
||||
def get_tid(self) -> int:
|
||||
return self._tid
|
||||
|
||||
@t.Object
|
||||
class Process:
|
||||
_pid: int
|
||||
_path: t.CArray[t.CChar, 128]
|
||||
|
||||
def __init__(self, path: t.CConst | t.CChar | t.CPtr):
|
||||
self._pid = -1
|
||||
i: int = 0
|
||||
for ch in path:
|
||||
if i >= 127: break
|
||||
self._path[i] = ch
|
||||
i += 1
|
||||
self._path[i] = 0
|
||||
|
||||
def start(self) -> int:
|
||||
self._pid = spawn(c.Addr(self._path[0]), 0)
|
||||
return self._pid
|
||||
|
||||
def start_blocking(self) -> int:
|
||||
self._pid = spawn(c.Addr(self._path[0]), 1)
|
||||
return self._pid
|
||||
|
||||
def get_pid(self) -> int:
|
||||
return self._pid
|
||||
+33
-33
@@ -1,33 +1,33 @@
|
||||
import vpsdk.syscall as _syscall
|
||||
import t, c
|
||||
import viperlib
|
||||
|
||||
# ============================================================
|
||||
# vpsdk.stdio - 用户态 printf/exit(CExport 裸名,供内核侧代码
|
||||
# 如 includes/memhub.vp 跨模块引用解析)
|
||||
#
|
||||
# 裸机 App 无 libc:printf 走 viperlib.vsnprintf 格式化 + SERIAL_PUTS
|
||||
# syscall 输出到串口;exit 走 EXIT syscall 通知内核销毁本进程窗口。
|
||||
# ============================================================
|
||||
|
||||
def printf(fmt: t.CConst | str, *args) -> t.CInt | t.CExport:
|
||||
"""格式化输出到串口(SERIAL_PUTS syscall),返回输出字节数"""
|
||||
if fmt is None:
|
||||
return 0
|
||||
buf: t.CArray[t.CChar, 1024]
|
||||
n: t.CInt = viperlib.vsnprintf(c.Addr(buf), 1024, fmt, args)
|
||||
_syscall._syscall1(t.CUInt64T(_syscall.SERIAL_PUTS), t.CUInt64T(c.Addr(buf)))
|
||||
return n
|
||||
|
||||
def exit(status: t.CInt) -> t.CVoid | t.CExport:
|
||||
"""终止当前进程(EXIT syscall:销毁本进程窗口)"""
|
||||
_syscall._syscall1(t.CUInt64T(_syscall.EXIT), t.CUInt64T(status))
|
||||
|
||||
|
||||
def fflush(stream: t.CConst | t.CVoid | t.CPtr) -> t.CInt | t.CExport:
|
||||
"""刷新输出流:串口/控制台输出都是直写,无缓冲可刷,空操作返回 0
|
||||
|
||||
覆盖 libc fflush 的裸机缺失(includes/memhub.vp 的诊断/终止路径 call @fflush);
|
||||
与 printf/exit 同为 CExport 裸名,供内核侧 includes 跨模块引用解析。
|
||||
"""
|
||||
return 0
|
||||
import vpsdk.syscall as _syscall
|
||||
import t, c
|
||||
import viperlib
|
||||
|
||||
# ============================================================
|
||||
# vpsdk.stdio - 用户态 printf/exit(CExport 裸名,供内核侧代码
|
||||
# 如 includes/memhub.vp 跨模块引用解析)
|
||||
#
|
||||
# 裸机 App 无 libc:printf 走 viperlib.vsnprintf 格式化 + SERIAL_PUTS
|
||||
# syscall 输出到串口;exit 走 EXIT syscall 通知内核销毁本进程窗口。
|
||||
# ============================================================
|
||||
|
||||
def printf(fmt: t.CConst | str, *args) -> int | t.CExport:
|
||||
"""格式化输出到串口(SERIAL_PUTS syscall),返回输出字节数"""
|
||||
if fmt is None:
|
||||
return 0
|
||||
buf: t.CArray[t.CChar, 1024]
|
||||
n: int = viperlib.vsnprintf(c.Addr(buf), 1024, fmt, args)
|
||||
_syscall._syscall1(uint64(_syscall.SERIAL_PUTS), uint64(c.Addr(buf)))
|
||||
return n
|
||||
|
||||
def exit(status: int) -> t.CVoid | t.CExport:
|
||||
"""终止当前进程(EXIT syscall:销毁本进程窗口)"""
|
||||
_syscall._syscall1(uint64(_syscall.EXIT), uint64(status))
|
||||
|
||||
|
||||
def fflush(stream: t.CConst | t.CPtr) -> int | t.CExport:
|
||||
"""刷新输出流:串口/控制台输出都是直写,无缓冲可刷,空操作返回 0
|
||||
|
||||
覆盖 libc fflush 的裸机缺失(includes/memhub.vp 的诊断/终止路径 call @fflush);
|
||||
与 printf/exit 同为 CExport 裸名,供内核侧 includes 跨模块引用解析。
|
||||
"""
|
||||
return 0
|
||||
+59
-59
@@ -1,59 +1,59 @@
|
||||
import vpsdk.syscall as _sc
|
||||
import string
|
||||
import t, c
|
||||
|
||||
HEAP_BLOCK_MAGIC: t.CDefine = 0x48454150
|
||||
|
||||
@t.Object
|
||||
class _heap_hdr:
|
||||
magic: t.CUInt32T
|
||||
size: t.CUInt32T
|
||||
|
||||
_heap_inited: t.CInt = 0
|
||||
|
||||
def _heap_init():
|
||||
global _heap_inited
|
||||
_heap_inited = 1
|
||||
|
||||
def malloc(size: t.CSizeT) -> t.CVoid | t.CPtr | t.CExport:
|
||||
global _heap_inited
|
||||
if size == 0: return None
|
||||
if _heap_inited == 0:
|
||||
_heap_init()
|
||||
hdr_size: t.CSizeT = _heap_hdr.__sizeof__()
|
||||
total: t.CSizeT = hdr_size + size
|
||||
ptr: t.CUInt64T = _sc._syscall1(t.CUInt64T(_sc.SYSCALL_MMAP), t.CUInt64T(total))
|
||||
if ptr == 0: return None
|
||||
hdr: _heap_hdr | t.CPtr = t.CVoid(ptr, t.CPtr)
|
||||
hdr.magic = HEAP_BLOCK_MAGIC
|
||||
hdr.size = t.CUInt32T(size)
|
||||
return t.CVoid(ptr + hdr_size, t.CPtr)
|
||||
|
||||
def free(ptr: t.CVoid | t.CPtr) -> t.CExport:
|
||||
if ptr is None: return
|
||||
hdr_size: t.CSizeT = _heap_hdr.__sizeof__()
|
||||
hdr: _heap_hdr | t.CPtr = t.CVoid(t.CUInt64T(ptr) - hdr_size, t.CPtr)
|
||||
if hdr.magic != HEAP_BLOCK_MAGIC: return
|
||||
|
||||
def calloc(nmemb: t.CSizeT, size: t.CSizeT) -> t.CVoid | t.CPtr | t.CExport:
|
||||
total: t.CSizeT = nmemb * size
|
||||
p: t.CVoid | t.CPtr = malloc(total)
|
||||
if p:
|
||||
string.memset(p, 0, total)
|
||||
return p
|
||||
|
||||
def realloc(ptr: t.CVoid | t.CPtr, size: t.CSizeT) -> t.CVoid | t.CPtr | t.CExport:
|
||||
if ptr is None: return malloc(size)
|
||||
if size == 0:
|
||||
free(ptr)
|
||||
return None
|
||||
hdr_size: t.CSizeT = _heap_hdr.__sizeof__()
|
||||
hdr: _heap_hdr | t.CPtr = t.CVoid(t.CUInt64T(ptr) - hdr_size, t.CPtr)
|
||||
if hdr.magic != HEAP_BLOCK_MAGIC: return None
|
||||
old_size: t.CSizeT = hdr.size
|
||||
new_ptr: t.CVoid | t.CPtr = malloc(size)
|
||||
if new_ptr is None: return None
|
||||
copy_size: t.CSizeT = old_size if old_size < size else size
|
||||
string.memcpy(new_ptr, ptr, copy_size)
|
||||
free(ptr)
|
||||
return new_ptr
|
||||
import vpsdk.syscall as _sc
|
||||
import string
|
||||
import t, c
|
||||
|
||||
HEAP_BLOCK_MAGIC: t.CDefine = 0x48454150
|
||||
|
||||
@t.Object
|
||||
class _heap_hdr:
|
||||
magic: uint32
|
||||
size: uint32
|
||||
|
||||
_heap_inited: int = 0
|
||||
|
||||
def _heap_init():
|
||||
global _heap_inited
|
||||
_heap_inited = 1
|
||||
|
||||
def malloc(size: t.CSizeT) -> t.CPtr | t.CExport:
|
||||
global _heap_inited
|
||||
if size == 0: return None
|
||||
if _heap_inited == 0:
|
||||
_heap_init()
|
||||
hdr_size: t.CSizeT = _heap_hdr.__sizeof__()
|
||||
total: t.CSizeT = hdr_size + size
|
||||
ptr: uint64 = _sc._syscall1(uint64(_sc.SYSCALL_MMAP), uint64(total))
|
||||
if ptr == 0: return None
|
||||
hdr: _heap_hdr | t.CPtr = t.CVoid(ptr, t.CPtr)
|
||||
hdr.magic = HEAP_BLOCK_MAGIC
|
||||
hdr.size = uint32(size)
|
||||
return t.CVoid(ptr + hdr_size, t.CPtr)
|
||||
|
||||
def free(ptr: t.CPtr) -> t.CExport:
|
||||
if ptr is None: return
|
||||
hdr_size: t.CSizeT = _heap_hdr.__sizeof__()
|
||||
hdr: _heap_hdr | t.CPtr = t.CVoid(uint64(ptr) - hdr_size, t.CPtr)
|
||||
if hdr.magic != HEAP_BLOCK_MAGIC: return
|
||||
|
||||
def calloc(nmemb: t.CSizeT, size: t.CSizeT) -> t.CPtr | t.CExport:
|
||||
total: t.CSizeT = nmemb * size
|
||||
p: t.CPtr = malloc(total)
|
||||
if p:
|
||||
string.memset(p, 0, total)
|
||||
return p
|
||||
|
||||
def realloc(ptr: t.CPtr, size: t.CSizeT) -> t.CPtr | t.CExport:
|
||||
if ptr is None: return malloc(size)
|
||||
if size == 0:
|
||||
free(ptr)
|
||||
return None
|
||||
hdr_size: t.CSizeT = _heap_hdr.__sizeof__()
|
||||
hdr: _heap_hdr | t.CPtr = t.CVoid(uint64(ptr) - hdr_size, t.CPtr)
|
||||
if hdr.magic != HEAP_BLOCK_MAGIC: return None
|
||||
old_size: t.CSizeT = hdr.size
|
||||
new_ptr: t.CPtr = malloc(size)
|
||||
if new_ptr is None: return None
|
||||
copy_size: t.CSizeT = old_size if old_size < size else size
|
||||
string.memcpy(new_ptr, ptr, copy_size)
|
||||
free(ptr)
|
||||
return new_ptr
|
||||
+117
-117
@@ -1,117 +1,117 @@
|
||||
import t, c
|
||||
|
||||
CREATE_WINDOW: t.CDefine = 1
|
||||
DRAW_TEXT: t.CDefine = 2
|
||||
EXIT: t.CDefine = 3
|
||||
OPEN: t.CDefine = 4
|
||||
CLOSE: t.CDefine = 5
|
||||
READ: t.CDefine = 6
|
||||
WRITE: t.CDefine = 7
|
||||
SEEK: t.CDefine = 8
|
||||
TELL: t.CDefine = 9
|
||||
SIZE: t.CDefine = 10
|
||||
MKDIR: t.CDefine = 11
|
||||
REMOVE: t.CDefine = 12
|
||||
OPENDIR: t.CDefine = 13
|
||||
READDIR: t.CDefine = 14
|
||||
CLOSEDIR: t.CDefine = 15
|
||||
STAT: t.CDefine = 16
|
||||
WAIT_WINDOW: t.CDefine = 17
|
||||
SERIAL_PUTS: t.CDefine = 18
|
||||
LOAD_SO: t.CDefine = 19
|
||||
SO_CALL1: t.CDefine = 20
|
||||
GET_WINBUF: t.CDefine = 21
|
||||
WIN_FLUSH: t.CDefine = 22
|
||||
POLL_EVENT: t.CDefine = 23
|
||||
SET_CURSOR: t.CDefine = 24
|
||||
|
||||
YIELD: t.CDefine = 25
|
||||
SET_TITLE: t.CDefine = 26
|
||||
SET_GEOMETRY: t.CDefine = 27
|
||||
SPAWN: t.CDefine = 28
|
||||
MMAP: t.CDefine = 29
|
||||
MUNMAP: t.CDefine = 30
|
||||
SET_RESIZABLE: t.CDefine = 31
|
||||
GET_WIN_SIZE: t.CDefine = 32
|
||||
THREAD_CREATE: t.CDefine = 33
|
||||
|
||||
# SYSCALL_* 别名(vpsdk.stdlib 等模块引用;数值与内核 VKernel/intr/syscall.vp 一致)
|
||||
SYSCALL_MMAP: t.CDefine = 29
|
||||
|
||||
def _syscall0(num: t.CUInt64T) -> t.CUInt64T:
|
||||
ret: t.CUInt64T
|
||||
c.Asm(f"""mov rax, {c.AsmInp(num, t.ASM_DESCR.REG_ANY)}
|
||||
syscall""",
|
||||
out=[c.AsmOut(ret, t.ASM_DESCR.OUTPUT_REG)],
|
||||
op=[t.ASM_DESCR.CLOBBER_MEMORY, t.ASM_DESCR.CLOBBER_RCX,
|
||||
t.ASM_DESCR.CLOBBER_R11])
|
||||
return ret
|
||||
|
||||
def _syscall1(num: t.CUInt64T, a1: t.CUInt64T) -> t.CUInt64T:
|
||||
ret: t.CUInt64T
|
||||
c.Asm(f"""mov rdi, {c.AsmInp(a1, t.ASM_DESCR.REG_ANY)}
|
||||
mov rax, {c.AsmInp(num, t.ASM_DESCR.REG_ANY)}
|
||||
syscall""",
|
||||
out=[c.AsmOut(ret, t.ASM_DESCR.OUTPUT_REG)],
|
||||
op=[t.ASM_DESCR.CLOBBER_MEMORY, t.ASM_DESCR.CLOBBER_RCX,
|
||||
t.ASM_DESCR.CLOBBER_R11, t.ASM_DESCR.CLOBBER_RDI])
|
||||
return ret
|
||||
|
||||
def _syscall2(num: t.CUInt64T, a1: t.CUInt64T, a2: t.CUInt64T) -> t.CUInt64T:
|
||||
ret: t.CUInt64T
|
||||
c.Asm(f"""mov rdi, {c.AsmInp(a1, t.ASM_DESCR.REG_ANY)}
|
||||
mov rsi, {c.AsmInp(a2, t.ASM_DESCR.REG_ANY)}
|
||||
mov rax, {c.AsmInp(num, t.ASM_DESCR.REG_ANY)}
|
||||
syscall""",
|
||||
out=[c.AsmOut(ret, t.ASM_DESCR.OUTPUT_REG)],
|
||||
op=[t.ASM_DESCR.CLOBBER_MEMORY, t.ASM_DESCR.CLOBBER_RCX,
|
||||
t.ASM_DESCR.CLOBBER_R11, t.ASM_DESCR.CLOBBER_RDI,
|
||||
t.ASM_DESCR.CLOBBER_RSI])
|
||||
return ret
|
||||
|
||||
def _syscall3(num: t.CUInt64T, a1: t.CUInt64T, a2: t.CUInt64T, a3: t.CUInt64T) -> t.CUInt64T:
|
||||
ret: t.CUInt64T
|
||||
c.Asm(f"""mov rdi, {c.AsmInp(a1, t.ASM_DESCR.REG_ANY)}
|
||||
mov rsi, {c.AsmInp(a2, t.ASM_DESCR.REG_ANY)}
|
||||
mov rdx, {c.AsmInp(a3, t.ASM_DESCR.REG_ANY)}
|
||||
mov rax, {c.AsmInp(num, t.ASM_DESCR.REG_ANY)}
|
||||
syscall""",
|
||||
out=[c.AsmOut(ret, t.ASM_DESCR.OUTPUT_REG)],
|
||||
op=[t.ASM_DESCR.CLOBBER_MEMORY, t.ASM_DESCR.CLOBBER_RCX,
|
||||
t.ASM_DESCR.CLOBBER_R11, t.ASM_DESCR.CLOBBER_RDI,
|
||||
t.ASM_DESCR.CLOBBER_RSI, t.ASM_DESCR.CLOBBER_RDX])
|
||||
return ret
|
||||
|
||||
def _syscall5(num: t.CUInt64T, a1: t.CUInt64T, a2: t.CUInt64T, a3: t.CUInt64T, a4: t.CUInt64T, a5: t.CUInt64T) -> t.CUInt64T:
|
||||
ret: t.CUInt64T
|
||||
c.Asm(f"""mov rdi, {c.AsmInp(a1, t.ASM_DESCR.REG_ANY)}
|
||||
mov rsi, {c.AsmInp(a2, t.ASM_DESCR.REG_ANY)}
|
||||
mov rdx, {c.AsmInp(a3, t.ASM_DESCR.REG_ANY)}
|
||||
mov r10, {c.AsmInp(a4, t.ASM_DESCR.REG_ANY)}
|
||||
mov r8, {c.AsmInp(a5, t.ASM_DESCR.REG_ANY)}
|
||||
mov rax, {c.AsmInp(num, t.ASM_DESCR.REG_ANY)}
|
||||
syscall""",
|
||||
out=[c.AsmOut(ret, t.ASM_DESCR.OUTPUT_REG)],
|
||||
op=[t.ASM_DESCR.CLOBBER_MEMORY, t.ASM_DESCR.CLOBBER_RCX,
|
||||
t.ASM_DESCR.CLOBBER_R11, t.ASM_DESCR.CLOBBER_RDI,
|
||||
t.ASM_DESCR.CLOBBER_RSI, t.ASM_DESCR.CLOBBER_RDX,
|
||||
t.ASM_DESCR.CLOBBER_R10, t.ASM_DESCR.CLOBBER_R8])
|
||||
return ret
|
||||
|
||||
def _syscall6(num: t.CUInt64T, a1: t.CUInt64T, a2: t.CUInt64T, a3: t.CUInt64T, a4: t.CUInt64T, a5: t.CUInt64T, a6: t.CUInt64T) -> t.CUInt64T:
|
||||
ret: t.CUInt64T
|
||||
c.Asm(f"""mov rdi, {c.AsmInp(a1, t.ASM_DESCR.REG_ANY)}
|
||||
mov rsi, {c.AsmInp(a2, t.ASM_DESCR.REG_ANY)}
|
||||
mov rdx, {c.AsmInp(a3, t.ASM_DESCR.REG_ANY)}
|
||||
mov r10, {c.AsmInp(a4, t.ASM_DESCR.REG_ANY)}
|
||||
mov r8, {c.AsmInp(a5, t.ASM_DESCR.REG_ANY)}
|
||||
mov r9, {c.AsmInp(a6, t.ASM_DESCR.REG_ANY)}
|
||||
mov rax, {c.AsmInp(num, t.ASM_DESCR.REG_ANY)}
|
||||
syscall""",
|
||||
out=[c.AsmOut(ret, t.ASM_DESCR.OUTPUT_REG)],
|
||||
op=[t.ASM_DESCR.CLOBBER_MEMORY, t.ASM_DESCR.CLOBBER_RCX,
|
||||
t.ASM_DESCR.CLOBBER_R11, t.ASM_DESCR.CLOBBER_RDI,
|
||||
t.ASM_DESCR.CLOBBER_RSI, t.ASM_DESCR.CLOBBER_RDX,
|
||||
t.ASM_DESCR.CLOBBER_R10, t.ASM_DESCR.CLOBBER_R8,
|
||||
t.ASM_DESCR.CLOBBER_R9])
|
||||
return ret
|
||||
import t, c
|
||||
|
||||
CREATE_WINDOW: t.CDefine = 1
|
||||
DRAW_TEXT: t.CDefine = 2
|
||||
EXIT: t.CDefine = 3
|
||||
OPEN: t.CDefine = 4
|
||||
CLOSE: t.CDefine = 5
|
||||
READ: t.CDefine = 6
|
||||
WRITE: t.CDefine = 7
|
||||
SEEK: t.CDefine = 8
|
||||
TELL: t.CDefine = 9
|
||||
SIZE: t.CDefine = 10
|
||||
MKDIR: t.CDefine = 11
|
||||
REMOVE: t.CDefine = 12
|
||||
OPENDIR: t.CDefine = 13
|
||||
READDIR: t.CDefine = 14
|
||||
CLOSEDIR: t.CDefine = 15
|
||||
STAT: t.CDefine = 16
|
||||
WAIT_WINDOW: t.CDefine = 17
|
||||
SERIAL_PUTS: t.CDefine = 18
|
||||
LOAD_SO: t.CDefine = 19
|
||||
SO_CALL1: t.CDefine = 20
|
||||
GET_WINBUF: t.CDefine = 21
|
||||
WIN_FLUSH: t.CDefine = 22
|
||||
POLL_EVENT: t.CDefine = 23
|
||||
SET_CURSOR: t.CDefine = 24
|
||||
|
||||
YIELD: t.CDefine = 25
|
||||
SET_TITLE: t.CDefine = 26
|
||||
SET_GEOMETRY: t.CDefine = 27
|
||||
SPAWN: t.CDefine = 28
|
||||
MMAP: t.CDefine = 29
|
||||
MUNMAP: t.CDefine = 30
|
||||
SET_RESIZABLE: t.CDefine = 31
|
||||
GET_WIN_SIZE: t.CDefine = 32
|
||||
THREAD_CREATE: t.CDefine = 33
|
||||
|
||||
# SYSCALL_* 别名(vpsdk.stdlib 等模块引用;数值与内核 VKernel/intr/syscall.vp 一致)
|
||||
SYSCALL_MMAP: t.CDefine = 29
|
||||
|
||||
def _syscall0(num: uint64) -> uint64:
|
||||
ret: uint64
|
||||
c.Asm(f"""mov rax, {c.AsmInp(num, t.ASM_DESCR.REG_ANY)}
|
||||
syscall""",
|
||||
out=[c.AsmOut(ret, t.ASM_DESCR.OUTPUT_REG)],
|
||||
op=[t.ASM_DESCR.CLOBBER_MEMORY, t.ASM_DESCR.CLOBBER_RCX,
|
||||
t.ASM_DESCR.CLOBBER_R11])
|
||||
return ret
|
||||
|
||||
def _syscall1(num: uint64, a1: uint64) -> uint64:
|
||||
ret: uint64
|
||||
c.Asm(f"""mov rdi, {c.AsmInp(a1, t.ASM_DESCR.REG_ANY)}
|
||||
mov rax, {c.AsmInp(num, t.ASM_DESCR.REG_ANY)}
|
||||
syscall""",
|
||||
out=[c.AsmOut(ret, t.ASM_DESCR.OUTPUT_REG)],
|
||||
op=[t.ASM_DESCR.CLOBBER_MEMORY, t.ASM_DESCR.CLOBBER_RCX,
|
||||
t.ASM_DESCR.CLOBBER_R11, t.ASM_DESCR.CLOBBER_RDI])
|
||||
return ret
|
||||
|
||||
def _syscall2(num: uint64, a1: uint64, a2: uint64) -> uint64:
|
||||
ret: uint64
|
||||
c.Asm(f"""mov rdi, {c.AsmInp(a1, t.ASM_DESCR.REG_ANY)}
|
||||
mov rsi, {c.AsmInp(a2, t.ASM_DESCR.REG_ANY)}
|
||||
mov rax, {c.AsmInp(num, t.ASM_DESCR.REG_ANY)}
|
||||
syscall""",
|
||||
out=[c.AsmOut(ret, t.ASM_DESCR.OUTPUT_REG)],
|
||||
op=[t.ASM_DESCR.CLOBBER_MEMORY, t.ASM_DESCR.CLOBBER_RCX,
|
||||
t.ASM_DESCR.CLOBBER_R11, t.ASM_DESCR.CLOBBER_RDI,
|
||||
t.ASM_DESCR.CLOBBER_RSI])
|
||||
return ret
|
||||
|
||||
def _syscall3(num: uint64, a1: uint64, a2: uint64, a3: uint64) -> uint64:
|
||||
ret: uint64
|
||||
c.Asm(f"""mov rdi, {c.AsmInp(a1, t.ASM_DESCR.REG_ANY)}
|
||||
mov rsi, {c.AsmInp(a2, t.ASM_DESCR.REG_ANY)}
|
||||
mov rdx, {c.AsmInp(a3, t.ASM_DESCR.REG_ANY)}
|
||||
mov rax, {c.AsmInp(num, t.ASM_DESCR.REG_ANY)}
|
||||
syscall""",
|
||||
out=[c.AsmOut(ret, t.ASM_DESCR.OUTPUT_REG)],
|
||||
op=[t.ASM_DESCR.CLOBBER_MEMORY, t.ASM_DESCR.CLOBBER_RCX,
|
||||
t.ASM_DESCR.CLOBBER_R11, t.ASM_DESCR.CLOBBER_RDI,
|
||||
t.ASM_DESCR.CLOBBER_RSI, t.ASM_DESCR.CLOBBER_RDX])
|
||||
return ret
|
||||
|
||||
def _syscall5(num: uint64, a1: uint64, a2: uint64, a3: uint64, a4: uint64, a5: uint64) -> uint64:
|
||||
ret: uint64
|
||||
c.Asm(f"""mov rdi, {c.AsmInp(a1, t.ASM_DESCR.REG_ANY)}
|
||||
mov rsi, {c.AsmInp(a2, t.ASM_DESCR.REG_ANY)}
|
||||
mov rdx, {c.AsmInp(a3, t.ASM_DESCR.REG_ANY)}
|
||||
mov r10, {c.AsmInp(a4, t.ASM_DESCR.REG_ANY)}
|
||||
mov r8, {c.AsmInp(a5, t.ASM_DESCR.REG_ANY)}
|
||||
mov rax, {c.AsmInp(num, t.ASM_DESCR.REG_ANY)}
|
||||
syscall""",
|
||||
out=[c.AsmOut(ret, t.ASM_DESCR.OUTPUT_REG)],
|
||||
op=[t.ASM_DESCR.CLOBBER_MEMORY, t.ASM_DESCR.CLOBBER_RCX,
|
||||
t.ASM_DESCR.CLOBBER_R11, t.ASM_DESCR.CLOBBER_RDI,
|
||||
t.ASM_DESCR.CLOBBER_RSI, t.ASM_DESCR.CLOBBER_RDX,
|
||||
t.ASM_DESCR.CLOBBER_R10, t.ASM_DESCR.CLOBBER_R8])
|
||||
return ret
|
||||
|
||||
def _syscall6(num: uint64, a1: uint64, a2: uint64, a3: uint64, a4: uint64, a5: uint64, a6: uint64) -> uint64:
|
||||
ret: uint64
|
||||
c.Asm(f"""mov rdi, {c.AsmInp(a1, t.ASM_DESCR.REG_ANY)}
|
||||
mov rsi, {c.AsmInp(a2, t.ASM_DESCR.REG_ANY)}
|
||||
mov rdx, {c.AsmInp(a3, t.ASM_DESCR.REG_ANY)}
|
||||
mov r10, {c.AsmInp(a4, t.ASM_DESCR.REG_ANY)}
|
||||
mov r8, {c.AsmInp(a5, t.ASM_DESCR.REG_ANY)}
|
||||
mov r9, {c.AsmInp(a6, t.ASM_DESCR.REG_ANY)}
|
||||
mov rax, {c.AsmInp(num, t.ASM_DESCR.REG_ANY)}
|
||||
syscall""",
|
||||
out=[c.AsmOut(ret, t.ASM_DESCR.OUTPUT_REG)],
|
||||
op=[t.ASM_DESCR.CLOBBER_MEMORY, t.ASM_DESCR.CLOBBER_RCX,
|
||||
t.ASM_DESCR.CLOBBER_R11, t.ASM_DESCR.CLOBBER_RDI,
|
||||
t.ASM_DESCR.CLOBBER_RSI, t.ASM_DESCR.CLOBBER_RDX,
|
||||
t.ASM_DESCR.CLOBBER_R10, t.ASM_DESCR.CLOBBER_R8,
|
||||
t.ASM_DESCR.CLOBBER_R9])
|
||||
return ret
|
||||
+1557
-1557
File diff suppressed because it is too large.
Load diff
+93
-93
@@ -1,93 +1,93 @@
|
||||
import t, c
|
||||
from . import syscall as syscall
|
||||
from stdint import *
|
||||
|
||||
STYLE_CLASSIC: t.CDefine = 0
|
||||
STYLE_WIN10: t.CDefine = 1
|
||||
STYLE_WIN11: t.CDefine = 2
|
||||
STYLE_WIN7: t.CDefine = 3
|
||||
STYLE_WINXP: t.CDefine = 4
|
||||
|
||||
EVENT_TYPE_NONE: t.CDefine = 0
|
||||
EVENT_TYPE_CLICK: t.CDefine = 1
|
||||
EVENT_TYPE_HOVER: t.CDefine = 2
|
||||
EVENT_TYPE_RELEASE: t.CDefine = 3
|
||||
EVENT_TYPE_HOVER_LEAVE: t.CDefine = 4
|
||||
EVENT_TYPE_KEY: t.CDefine = 5
|
||||
EVENT_TYPE_KEY_RELEASE: t.CDefine = 6
|
||||
EVENT_TYPE_PING: t.CDefine = 7
|
||||
EVENT_TYPE_RESIZE: t.CDefine = 8
|
||||
|
||||
KEY_STATE_PRESS: t.CDefine = 1
|
||||
KEY_STATE_RELEASE: t.CDefine = 2
|
||||
KEY_STATE_REPEAT: t.CDefine = 3
|
||||
|
||||
CURSOR_DEFAULT: t.CDefine = 0
|
||||
CURSOR_IBEAM: t.CDefine = 1
|
||||
CURSOR_RESIZE_EW: t.CDefine = 2
|
||||
CURSOR_RESIZE_NS: t.CDefine = 3
|
||||
CURSOR_RESIZE_NWSE: t.CDefine = 4
|
||||
|
||||
VK_LEFT: t.CDefine = -1
|
||||
VK_RIGHT: t.CDefine = -2
|
||||
VK_UP: t.CDefine = -3
|
||||
VK_DOWN: t.CDefine = -4
|
||||
VK_HOME: t.CDefine = -5
|
||||
VK_END: t.CDefine = -6
|
||||
VK_DELETE: t.CDefine = -7
|
||||
VK_PRIOR: t.CDefine = -8
|
||||
VK_NEXT: t.CDefine = -9
|
||||
|
||||
@c.Attribute(t.attr.packed)
|
||||
@t.Object
|
||||
class InputEvent:
|
||||
type: t.CUInt32T
|
||||
win_id: t.CInt
|
||||
x: t.CInt
|
||||
y: t.CInt
|
||||
button: t.CUInt8T
|
||||
_pad0: t.CUInt8T
|
||||
_pad1: t.CUInt8T
|
||||
_pad2: t.CUInt8T
|
||||
|
||||
def create_window(x: t.CInt, y: t.CInt, w: t.CInt, h: t.CInt, title: t.CConst | t.CChar | t.CPtr, style: t.CInt) -> t.CInt:
|
||||
return t.CInt(syscall._syscall6(t.CUInt64T(syscall.CREATE_WINDOW), t.CUInt64T(x), t.CUInt64T(y), t.CUInt64T(w), t.CUInt64T(h), t.CUInt64T(title), t.CUInt64T(style)))
|
||||
|
||||
def draw_text(win_id: t.CInt, x: t.CInt, y: t.CInt, text: t.CConst | t.CChar | t.CPtr, color: t.CUInt32T) -> t.CInt:
|
||||
return t.CInt(syscall._syscall5(t.CUInt64T(syscall.DRAW_TEXT), t.CUInt64T(win_id), t.CUInt64T(x), t.CUInt64T(y), t.CUInt64T(text), t.CUInt64T(color)))
|
||||
|
||||
def get_winbuf(win_id: t.CInt) -> UINT32PTR:
|
||||
return t.CVoid(syscall._syscall2(t.CUInt64T(syscall.GET_WINBUF), t.CUInt64T(win_id), 0), t.CPtr)
|
||||
|
||||
def get_win_size(win_id: t.CInt) -> t.CInt:
|
||||
return t.CInt(syscall._syscall2(t.CUInt64T(syscall.GET_WIN_SIZE), t.CUInt64T(win_id), 0))
|
||||
|
||||
def flush(win_id: t.CInt) -> t.CVoid:
|
||||
syscall._syscall2(t.CUInt64T(syscall.WIN_FLUSH), t.CUInt64T(win_id), 0)
|
||||
|
||||
def mainloop(win_id: t.CInt) -> t.CVoid:
|
||||
syscall._syscall1(t.CUInt64T(syscall.WAIT_WINDOW), t.CUInt64T(win_id))
|
||||
|
||||
def poll_event(evt: InputEvent | t.CPtr) -> t.CInt:
|
||||
return t.CInt(syscall._syscall1(t.CUInt64T(syscall.POLL_EVENT), t.CUInt64T(evt)))
|
||||
|
||||
def is_active(win_id: t.CInt) -> t.CInt:
|
||||
return t.CInt(syscall._syscall2(t.CUInt64T(syscall.WAIT_WINDOW), t.CUInt64T(win_id), 1))
|
||||
|
||||
def set_cursor_type(win_id: t.CInt, cursor_t: t.CInt) -> t.CVoid:
|
||||
syscall._syscall2(t.CUInt64T(syscall.SET_CURSOR), t.CUInt64T(win_id), t.CUInt64T(cursor_t))
|
||||
|
||||
def set_title(win_id: t.CInt, title: t.CConst | t.CChar | t.CPtr) -> t.CInt:
|
||||
return t.CInt(syscall._syscall2(t.CUInt64T(syscall.SET_TITLE), t.CUInt64T(win_id), t.CUInt64T(title)))
|
||||
|
||||
def set_geometry(win_id: t.CInt, x: t.CInt, y: t.CInt, w: t.CInt, h: t.CInt) -> t.CInt:
|
||||
return t.CInt(syscall._syscall5(t.CUInt64T(syscall.SET_GEOMETRY), t.CUInt64T(win_id), t.CUInt64T(x), t.CUInt64T(y), t.CUInt64T(w), t.CUInt64T(h)))
|
||||
|
||||
def set_resizable(win_id: t.CInt, rw: t.CInt, rh: t.CInt) -> t.CInt:
|
||||
return t.CInt(syscall._syscall3(t.CUInt64T(syscall.SET_RESIZABLE), t.CUInt64T(win_id), t.CUInt64T(rw), t.CUInt64T(rh)))
|
||||
|
||||
#class Window:
|
||||
# HWND: t.CInt
|
||||
# def __init__(self):
|
||||
# self.HWND = create_window(100, 100, 100, 100)
|
||||
|
||||
import t, c
|
||||
from . import syscall as syscall
|
||||
from stdint import *
|
||||
|
||||
STYLE_CLASSIC: t.CDefine = 0
|
||||
STYLE_WIN10: t.CDefine = 1
|
||||
STYLE_WIN11: t.CDefine = 2
|
||||
STYLE_WIN7: t.CDefine = 3
|
||||
STYLE_WINXP: t.CDefine = 4
|
||||
|
||||
EVENT_TYPE_NONE: t.CDefine = 0
|
||||
EVENT_TYPE_CLICK: t.CDefine = 1
|
||||
EVENT_TYPE_HOVER: t.CDefine = 2
|
||||
EVENT_TYPE_RELEASE: t.CDefine = 3
|
||||
EVENT_TYPE_HOVER_LEAVE: t.CDefine = 4
|
||||
EVENT_TYPE_KEY: t.CDefine = 5
|
||||
EVENT_TYPE_KEY_RELEASE: t.CDefine = 6
|
||||
EVENT_TYPE_PING: t.CDefine = 7
|
||||
EVENT_TYPE_RESIZE: t.CDefine = 8
|
||||
|
||||
KEY_STATE_PRESS: t.CDefine = 1
|
||||
KEY_STATE_RELEASE: t.CDefine = 2
|
||||
KEY_STATE_REPEAT: t.CDefine = 3
|
||||
|
||||
CURSOR_DEFAULT: t.CDefine = 0
|
||||
CURSOR_IBEAM: t.CDefine = 1
|
||||
CURSOR_RESIZE_EW: t.CDefine = 2
|
||||
CURSOR_RESIZE_NS: t.CDefine = 3
|
||||
CURSOR_RESIZE_NWSE: t.CDefine = 4
|
||||
|
||||
VK_LEFT: t.CDefine = -1
|
||||
VK_RIGHT: t.CDefine = -2
|
||||
VK_UP: t.CDefine = -3
|
||||
VK_DOWN: t.CDefine = -4
|
||||
VK_HOME: t.CDefine = -5
|
||||
VK_END: t.CDefine = -6
|
||||
VK_DELETE: t.CDefine = -7
|
||||
VK_PRIOR: t.CDefine = -8
|
||||
VK_NEXT: t.CDefine = -9
|
||||
|
||||
@c.Attribute(t.attr.packed)
|
||||
@t.Object
|
||||
class InputEvent:
|
||||
type: uint32
|
||||
win_id: int
|
||||
x: int
|
||||
y: int
|
||||
button: uint8
|
||||
_pad0: uint8
|
||||
_pad1: uint8
|
||||
_pad2: uint8
|
||||
|
||||
def create_window(x: int, y: int, w: int, h: int, title: t.CConst | t.CChar | t.CPtr, style: int) -> int:
|
||||
return int(syscall._syscall6(uint64(syscall.CREATE_WINDOW), uint64(x), uint64(y), uint64(w), uint64(h), uint64(title), uint64(style)))
|
||||
|
||||
def draw_text(win_id: int, x: int, y: int, text: t.CConst | t.CChar | t.CPtr, color: uint32) -> int:
|
||||
return int(syscall._syscall5(uint64(syscall.DRAW_TEXT), uint64(win_id), uint64(x), uint64(y), uint64(text), uint64(color)))
|
||||
|
||||
def get_winbuf(win_id: int) -> UINT32PTR:
|
||||
return t.CVoid(syscall._syscall2(uint64(syscall.GET_WINBUF), uint64(win_id), 0), t.CPtr)
|
||||
|
||||
def get_win_size(win_id: int) -> int:
|
||||
return int(syscall._syscall2(uint64(syscall.GET_WIN_SIZE), uint64(win_id), 0))
|
||||
|
||||
def flush(win_id: int) -> t.CVoid:
|
||||
syscall._syscall2(uint64(syscall.WIN_FLUSH), uint64(win_id), 0)
|
||||
|
||||
def mainloop(win_id: int) -> t.CVoid:
|
||||
syscall._syscall1(uint64(syscall.WAIT_WINDOW), uint64(win_id))
|
||||
|
||||
def poll_event(evt: InputEvent | t.CPtr) -> int:
|
||||
return int(syscall._syscall1(uint64(syscall.POLL_EVENT), uint64(evt)))
|
||||
|
||||
def is_active(win_id: int) -> int:
|
||||
return int(syscall._syscall2(uint64(syscall.WAIT_WINDOW), uint64(win_id), 1))
|
||||
|
||||
def set_cursor_type(win_id: int, cursor_t: int) -> t.CVoid:
|
||||
syscall._syscall2(uint64(syscall.SET_CURSOR), uint64(win_id), uint64(cursor_t))
|
||||
|
||||
def set_title(win_id: int, title: t.CConst | t.CChar | t.CPtr) -> int:
|
||||
return int(syscall._syscall2(uint64(syscall.SET_TITLE), uint64(win_id), uint64(title)))
|
||||
|
||||
def set_geometry(win_id: int, x: int, y: int, w: int, h: int) -> int:
|
||||
return int(syscall._syscall5(uint64(syscall.SET_GEOMETRY), uint64(win_id), uint64(x), uint64(y), uint64(w), uint64(h)))
|
||||
|
||||
def set_resizable(win_id: int, rw: int, rh: int) -> int:
|
||||
return int(syscall._syscall3(uint64(syscall.SET_RESIZABLE), uint64(win_id), uint64(rw), uint64(rh)))
|
||||
|
||||
#class Window:
|
||||
# HWND: int
|
||||
# def __init__(self):
|
||||
# self.HWND = create_window(100, 100, 100, 100)
|
||||
|
||||
Reference in new issue
Block a user