// The OS/K Team licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. #include //----------------------------------------------------------------------------// #define MAX_RFRAME_IDX 255 // // Register frames // ulong **rfs = NULL; size_t rfs_used = 0; size_t rfs_current_idx = 0; #define CHK_INDEX(idx) \ if ((size_t)idx > MAX_RFRAME_IDX) \ _except(E_UDF, "cpudev: invalid rframe index: #%u", idx); #define CHK_FRAME(idx) \ CHK_INDEX(idx); \ if (rfs[idx] == NULL) \ _except(E_UDF, \ "cpudev: operation on inactive reframe #%u", idx); //----------------------------------------------------------------------------// long cpudev_getmaxidx(dev_t *dev) { R(RAX) = MAX_RFRAME_IDX; return 0; } long cpudev_getrfusage(dev_t *dev) { R(RAX) = rfs_used; return 0; } long cpudev_getcuridx(dev_t *dev) { R(RAX) = rfs_current_idx; return 0; } long cpudev_leastavail(dev_t *dev) { size_t it; for (it = 0; it <= MAX_RFRAME_IDX; it++) { if (rfs[it] == NULL) { R(RAX) = it; return 0; } } R(RAX) = -1; return 0; } //----------------------------------------------------------------------------// long cpudev_isactive(dev_t *dev) { CHK_INDEX(R(AX0)); R(RAX) = (rfs[R(AX0)] != NULL); return 0; } long cpudev_activate(dev_t *dev) { CHK_INDEX(R(AX0)); if (rfs[R(AX0)] != NULL) _except(E_UDF, "cpudev: activating already activated rframe: #%u", R(AX0)); rfs[R(AX0)] = calloc(NREGS, sizeof(ulong)); if (rfs[R(AX0)] == 0) return -1; rfs_used++; return 0; } long cpudev_deactivate(dev_t *dev) { CHK_FRAME(R(AX0)); if (R(AX0) == 0) _except(E_UDF, "cpudev: deactivating rframe #0"); free(rfs[R(AX0)]); rfs[R(AX0)] = NULL; rfs_used--; assert(rfs_used > 0); return 0; } //----------------------------------------------------------------------------// long cpudev_copyframe(dev_t *dev) { CHK_FRAME(R(AX0)); CHK_FRAME(R(AX1)); if (R(AX0) == R(AX1)) return -1; memcpy(rfs[R(AX0)], rfs[R(AX1)], NREGS * sizeof(ulong)); return 0; } long cpudev_moveframe(dev_t *dev) { CHK_INDEX(R(AX0)); CHK_FRAME(R(AX1)); if (R(AX1) == 0) _except(E_UDF, "cpudev: trying to move frame #0"); if (rfs[R(AX0)] != NULL) _except(E_UDF, "cpudev: trying to move frame #%u " "active frame #%u", R(AX1), R(AX0)); rfs[R(AX0)] = rfs[R(AX1)]; rfs[R(AX1)] = NULL; return 0; } long cpudev_switchframe(dev_t *dev) { CHK_FRAME(R(AX0)); rfs_current_idx = R(AX0); ctx->rf = rfs[R(AX0)]; return 0; } //----------------------------------------------------------------------------// long cpudev_loadargs(dev_t *dev) { CHK_FRAME(R(AX0)); R(AX5) = rfs[R(AX0)][AX5]; R(AX4) = rfs[R(AX0)][AX4]; R(AX3) = rfs[R(AX0)][AX3]; R(AX2) = rfs[R(AX0)][AX2]; R(AX1) = rfs[R(AX0)][AX1]; R(AX0) = rfs[R(AX0)][AX0]; return 0; } long cpudev_loadreg(dev_t *dev) { CHK_FRAME(R(AX0)); if ((ushort)R(AX1) >= NREGS || R(AX1) == RZX) _except(E_UDF, "cpudev: register invalid or index out of range: #%u", R(AX1)); R(RAX) = rfs[R(AX0)][R(AX1)]; return 0; } long cpudev_storereg(dev_t *dev) { CHK_FRAME(R(AX0)); if ((ushort)R(AX1) >= NREGS) _except(E_UDF, "cpudev: register index out of range: #%u", R(AX1)); rfs[R(AX0)][R(AX1)] = R(AX2); return 0; } //----------------------------------------------------------------------------// #define CHK_IDT_INDEX(idx) \ if ((ulong)idx >= IDT_SLOTS) \ _except(E_UDF, "cpudev: invalid IDT slot index: #%u", idx); /* except.h */ ulong idt[IDT_SLOTS] = { 0 }; bool idt_masked[IDT_SLOTS] = { 0 }; // deliberately masked by software bool idt_handling[IDT_SLOTS] = { 0 }; // a handler is already running long cpudev_idtadd(dev_t *dev) { CHK_FRAME(R(AX1)); CHK_IDT_INDEX(R(AX0)); if (idt[R(AX0)] != 0) _except(E_UDF, "cpudev: IDT slot index already in use: #%u", R(AX0)); assert(idt_handling[R(AX0)] == 0); idt[R(AX0)] = R(AX1); return 0; } long cpudev_idtdel(dev_t *dev) { CHK_IDT_INDEX(R(AX0)); if (idt[R(AX0)] == 0) _except(E_UDF, "cpudev: IDT slot index not in use: #%u", R(AX0)); idt[R(AX0)] = 0; idt_handling[R(AX0)] = 0; return 0; } long cpudev_idtquery(dev_t *dev) { if (R(AX0) >= IDT_SLOTS || idt[R(AX0)] == 0) R(RAX) = R(RDX) = 0; else { R(RAX) = 1; R(RDX) = idt[R(AX0)]; } return 0; } long cpudev_idtdone(dev_t *dev) { CHK_IDT_INDEX(R(AX0)); if (idt_handling[R(AX0)] == 0) _except(E_UDF, "cpudev: idtdone, not handling E/I #%u", R(AX0)); idt_handling[R(AX0)]--; return 0; } //----------------------------------------------------------------------------// long cpudev_poweron(dev_t *dev) { rfs = calloc(MAX_RFRAME_IDX + 2, sizeof(reg_t *)); if (rfs == NULL) return -1; rfs[0] = ctx->rf; rfs_used = 1; dev->state = DEVGOOD; dev->fslots[16] = cpudev_getmaxidx; dev->fslots[17] = cpudev_getrfusage; dev->fslots[18] = cpudev_getcuridx; dev->fslots[19] = cpudev_leastavail; dev->fslots[20] = cpudev_isactive; dev->fslots[21] = cpudev_activate; dev->fslots[22] = cpudev_deactivate; dev->fslots[23] = cpudev_copyframe; dev->fslots[24] = cpudev_moveframe; dev->fslots[25] = cpudev_switchframe; dev->fslots[32] = cpudev_loadargs; dev->fslots[33] = cpudev_loadreg; dev->fslots[48] = cpudev_storereg; dev->fslots[64] = cpudev_idtadd; dev->fslots[65] = cpudev_idtdel; dev->fslots[66] = cpudev_idtquery; dev->fslots[67] = cpudev_idtdone; return 0; } long cpudev_poweroff(dev_t *dev) { size_t i; if (rfs) { for (i = 0; i <= MAX_RFRAME_IDX; i++) free(rfs[i]); free(rfs); } dev->state = DEVPWOF; return 0; } //----------------------------------------------------------------------------// dev_t cpudev = { .type = "cpu", .name = "K-CPU", .modl = "Prisma 1", .vend = "The OS/K Team", .major = KARCH_MAJOR, .minor = KARCH_MINOR, .revis = KARCH_REVIS, .fpwon = cpudev_poweron, .fpwoff = cpudev_poweroff, };