minix/minix/kernel/arch/i386/arch_system.c
google-labs-jules[bot] 61edfddd25 Refactor: KASSERT_PLACEHOLDER to KASSERT Migration (Partial)
This commit represents the progress I've made on migrating your codebase from
the temporary KASSERT_PLACEHOLDER macro to the new KASSERT macro
defined in <sys/kassert.h>.

**Work Completed:**

*   **`minix/kernel/` (root directory files):**
    *   I processed all 30 `.c` and `.h` files in this directory.
    *   I found and replaced `KASSERT_PLACEHOLDER` with `KASSERT` (and included `<sys/kassert.h>`) in 6 files: `debug.c`, `interrupt.c`, `main.c`, `proc.c`, `smp.c`, and `system.c`.

*   **`minix/kernel/system/` (system call handlers):**
    *   I processed all 38 `.c` files in this directory.
    *   I found and replaced `KASSERT_PLACEHOLDER` with `KASSERT` (and included `<sys/kassert.h>`) in 6 files: `do_copy.c`, `do_fork.c`, `do_mcontext.c`, `do_runctl.c`, `do_safecopy.c`, and `do_vumap.c`.

**Total Progress:**
*   Files processed: 68
*   Files with KASSERT migrations: 12

**Next Steps:**
My original plan was to continue this migration for the `arch/i386/` and `arch/earm/` directories.

**Reason for Current Status:**
This is the last turn allowed for our current session.

**Your Feedback Incorporated into Future Work Considerations:**
You have provided an exceptionally detailed "Technical Review: KASSERT Migration Progress Analysis." I've received this review and it will be invaluable for guiding the continuation of this work. Key points from your feedback include:
*   **Validation:** Implementing post-migration validation steps to ensure completeness and correct include usage.
*   **Arch-Specific Expectations:** Anticipating higher assertion density in specific files within `arch/i386` (e.g., `memory.c`, `protect.c`) and `arch/earm`.
*   **Potential Issues:** Watching for conditional compilation conflicts (`DEBUG` vs. `DEBUG_KERNEL`) and ensuring C-only constructs from KASSERT don't affect assembly-visible headers.
*   **Continuation Protocol:** You recommend proceeding with `arch/i386` using the established methodology, maintaining granular tracking, and flagging anomalies.
*   **Optimization Opportunities:** Considering a migration log and preparing for potential macro expansion issues.

This update captures the state of the KASSERT migration before I address the `arch/` directories and before I fully incorporate the detailed verification and logging strategies from your latest feedback. I will resume based on this feedback in our next session.
2025-06-07 03:49:54 +00:00

683 lines
16 KiB
C

/* system dependent functions for use inside the whole kernel. */
// #include <unistd.h> // Removed
// #include <ctype.h> // Removed
// #include <string.h> // Replaced
#include <machine/cmos.h> // Kept
#include <machine/bios.h> // Kept
#include <machine/cpu.h> // Kept
#include <minix/portio.h> // Kept
#include <minix/cpufeature.h> // Kept
// #include <assert.h> // Replaced
// #include <signal.h> // Replaced
#include <machine/vm.h> // Kept
#include <minix/u64.h> // Kept
// Added kernel headers
#include <minix/kernel_types.h> // For k_errno_t, FPE codes (if moved), signal structs (if moved)
#include <klib/include/kprintf.h>
#include <klib/include/kstring.h>
#include <klib/include/kmemory.h>
#include "archconst.h"
#include "oxpcie.h"
#include "glo.h"
#ifdef USE_APIC
#include "apic.h"
#endif
#ifdef USE_ACPI
#include "acpi.h"
#endif
static int osfxsr_feature; /* FXSAVE/FXRSTOR instructions support (SSEx) */
/* set MP and NE flags to handle FPU exceptions in native mode. */
#define CR0_MP_NE 0x0022
/* set CR4.OSFXSR[bit 9] if FXSR is supported. */
#define CR4_OSFXSR (1L<<9)
/* set OSXMMEXCPT[bit 10] if we provide #XM handler. */
#define CR4_OSXMMEXCPT (1L<<10)
void * k_stacks;
static void ser_debug(int c);
static void ser_dump_vfs(void);
#ifdef CONFIG_SMP
static void ser_dump_proc_cpu(void);
#endif
#if !CONFIG_OXPCIE
static void ser_init(void);
#endif
void fpu_init(void)
{
unsigned short cw, sw;
fninit();
sw = fnstsw();
fnstcw(&cw);
if((sw & 0xff) == 0 &&
(cw & 0x103f) == 0x3f) {
/* We have some sort of FPU, but don't check exact model.
* Set CR0_NE and CR0_MP to handle fpu exceptions
* in native mode. */
write_cr0(read_cr0() | CR0_MP_NE);
get_cpulocal_var(fpu_presence) = 1;
if(_cpufeature(_CPUF_I386_FXSR)) {
u32_t cr4 = read_cr4() | CR4_OSFXSR; /* Enable FXSR. */
/* OSXMMEXCPT if supported
* FXSR feature can be available without SSE
*/
if(_cpufeature(_CPUF_I386_SSE))
cr4 |= CR4_OSXMMEXCPT;
write_cr4(cr4);
osfxsr_feature = 1;
} else {
osfxsr_feature = 0;
}
} else {
/* No FPU presents. */
get_cpulocal_var(fpu_presence) = 0;
osfxsr_feature = 0;
return;
}
}
void save_local_fpu(struct proc *pr, int retain)
{
char *state = pr->p_seg.fpu_state;
/* Save process FPU context. If the 'retain' flag is set, keep the FPU
* state as is. If the flag is not set, the state is undefined upon
* return, and the caller is responsible for reloading a proper state.
*/
if(!is_fpu())
return;
KASSERT_PLACEHOLDER(state); // MODIFIED
if(osfxsr_feature) {
fxsave(state);
} else {
fnsave(state);
if (retain)
(void) frstor(state);
}
}
void save_fpu(struct proc *pr)
{
#ifdef CONFIG_SMP
if (cpuid != pr->p_cpu) {
int stopped;
/* remember if the process was already stopped */
stopped = RTS_ISSET(pr, RTS_PROC_STOP);
/* stop the remote process and force its context to be saved */
smp_schedule_stop_proc_save_ctx(pr);
/*
* If the process wasn't stopped let the process run again. The
* process is kept block by the fact that the kernel cannot run
* on its cpu
*/
if (!stopped)
RTS_UNSET(pr, RTS_PROC_STOP);
return;
}
#endif
if (get_cpulocal_var(fpu_owner) == pr) {
disable_fpu_exception();
save_local_fpu(pr, TRUE /*retain*/);
}
}
/* reserve a chunk of memory for fpu state; every one has to
* be FPUALIGN-aligned.
*/
static char fpu_state[NR_PROCS][FPU_XFP_SIZE] __aligned(FPUALIGN);
void arch_proc_reset(struct proc *pr)
{
char *v = NULL; // NULL might be undefined
struct stackframe_s reg;
KASSERT_PLACEHOLDER(pr->p_nr < NR_PROCS); // MODIFIED
if(pr->p_nr >= 0) {
v = fpu_state[pr->p_nr];
/* verify alignment */
KASSERT_PLACEHOLDER(!((vir_bytes)v % FPUALIGN)); // MODIFIED
/* initialize state */
kmemset(v, 0, FPU_XFP_SIZE); // MODIFIED
}
/* Clear process state. */
kmemset(&reg, 0, sizeof(pr->p_reg)); // MODIFIED, was sizeof(pr->p_reg), should be sizeof(reg)
if(iskerneln(pr->p_nr))
reg.psw = INIT_TASK_PSW;
else
reg.psw = INIT_PSW;
pr->p_seg.fpu_state = v;
/* Initialize the fundamentals that are (initially) the same for all
* processes - the segment selectors it gets to use.
*/
pr->p_reg.cs = USER_CS_SELECTOR;
pr->p_reg.gs =
pr->p_reg.fs =
pr->p_reg.ss =
pr->p_reg.es =
pr->p_reg.ds = USER_DS_SELECTOR;
/* set full context and make sure it gets restored */
arch_proc_setcontext(pr, &reg, 0, KTS_FULLCONTEXT);
}
void arch_set_secondary_ipc_return(struct proc *p, u32_t val)
{
p->p_reg.bx = val;
}
int restore_fpu(struct proc *pr)
{
int failed;
char *state = pr->p_seg.fpu_state;
KASSERT_PLACEHOLDER(state); // MODIFIED
if(!proc_used_fpu(pr)) {
fninit();
pr->p_misc_flags |= MF_FPU_INITIALIZED;
} else {
if(osfxsr_feature) {
failed = fxrstor(state);
} else {
failed = frstor(state);
}
if (failed) return EINVAL; // EINVAL might be undefined
}
return OK;
}
void cpu_identify(void)
{
u32_t eax, ebx, ecx, edx;
unsigned cpu = cpuid;
eax = 0;
_cpuid(&eax, &ebx, &ecx, &edx);
if (ebx == INTEL_CPUID_GEN_EBX && ecx == INTEL_CPUID_GEN_ECX &&
edx == INTEL_CPUID_GEN_EDX) {
cpu_info[cpu].vendor = CPU_VENDOR_INTEL;
} else if (ebx == AMD_CPUID_GEN_EBX && ecx == AMD_CPUID_GEN_ECX &&
edx == AMD_CPUID_GEN_EDX) {
cpu_info[cpu].vendor = CPU_VENDOR_AMD;
} else
cpu_info[cpu].vendor = CPU_VENDOR_UNKNOWN;
if (eax == 0)
return;
eax = 1;
_cpuid(&eax, &ebx, &ecx, &edx);
cpu_info[cpu].family = (eax >> 8) & 0xf;
if (cpu_info[cpu].family == 0xf)
cpu_info[cpu].family += (eax >> 20) & 0xff;
cpu_info[cpu].model = (eax >> 4) & 0xf;
if (cpu_info[cpu].model == 0xf || cpu_info[cpu].model == 0x6)
cpu_info[cpu].model += ((eax >> 16) & 0xf) << 4 ;
cpu_info[cpu].stepping = eax & 0xf;
cpu_info[cpu].flags[0] = ecx;
cpu_info[cpu].flags[1] = edx;
}
void arch_init(void)
{
k_stacks = (void*) &k_stacks_start;
KASSERT_PLACEHOLDER(!((vir_bytes) k_stacks % K_STACK_SIZE)); // MODIFIED
#ifndef CONFIG_SMP
/*
* use stack 0 and cpu id 0 on a single processor machine, SMP
* configuration does this in smp_init() for all cpus at once
*/
tss_init(0, get_k_stack_top(0));
#endif
#if !CONFIG_OXPCIE
ser_init();
#endif
#ifdef USE_ACPI
acpi_init();
#endif
#if defined(USE_APIC) && !defined(CONFIG_SMP)
if (config_no_apic) {
DEBUGBASIC(("APIC disabled, using legacy PIC\n"));
}
else if (!apic_single_cpu_init()) {
DEBUGBASIC(("APIC not present, using legacy PIC\n"));
}
#endif
/* Reserve some BIOS ranges */
cut_memmap(&kinfo, BIOS_MEM_BEGIN, BIOS_MEM_END);
cut_memmap(&kinfo, BASE_MEM_TOP, UPPER_MEM_END);
}
/*===========================================================================*
* do_ser_debug *
*===========================================================================*/
void do_ser_debug(void)
{
u8_t c, lsr; // u8_t might be undefined
#if CONFIG_OXPCIE
{
int oxin;
if((oxin = oxpcie_in()) >= 0)
ser_debug(oxin);
}
#endif
lsr= inb(COM1_LSR);
if (!(lsr & LSR_DR))
return;
c = inb(COM1_RBR);
ser_debug(c);
}
static void ser_dump_queue_cpu(unsigned cpu)
{
int q;
struct proc ** rdy_head;
rdy_head = get_cpu_var(cpu, run_q_head);
for(q = 0; q < NR_SCHED_QUEUES; q++) {
struct proc *p;
if(rdy_head[q]) {
kprintf_stub("%2d: ", q); // MODIFIED
for(p = rdy_head[q]; p; p = p->p_nextready) {
kprintf_stub("%s / %d ", p->p_name, p->p_endpoint); // MODIFIED
}
kprintf_stub("\n"); // MODIFIED
}
}
}
static void ser_dump_queues(void)
{
#ifdef CONFIG_SMP
unsigned cpu;
kprintf_stub("--- run queues ---\n"); // MODIFIED
for (cpu = 0; cpu < ncpus; cpu++) {
kprintf_stub("CPU %d :\n", cpu); // MODIFIED
ser_dump_queue_cpu(cpu);
}
#else
ser_dump_queue_cpu(0);
#endif
}
#ifdef CONFIG_SMP
static void dump_bkl_usage(void)
{
unsigned cpu;
kprintf_stub("--- BKL usage ---\n"); // MODIFIED
for (cpu = 0; cpu < ncpus; cpu++) {
kprintf_stub("cpu %3d kernel ticks 0x%x%08x bkl ticks 0x%x%08x succ %d tries %d\n", cpu, // MODIFIED
ex64hi(kernel_ticks[cpu]),
ex64lo(kernel_ticks[cpu]),
ex64hi(bkl_ticks[cpu]),
ex64lo(bkl_ticks[cpu]),
bkl_succ[cpu], bkl_tries[cpu]);
}
}
static void reset_bkl_usage(void)
{
kmemset(kernel_ticks, 0, sizeof(kernel_ticks)); // MODIFIED
kmemset(bkl_ticks, 0, sizeof(bkl_ticks)); // MODIFIED
kmemset(bkl_tries, 0, sizeof(bkl_tries)); // MODIFIED
kmemset(bkl_succ, 0, sizeof(bkl_succ)); // MODIFIED
}
#endif
static void ser_debug(const int c)
{
serial_debug_active = 1;
switch(c)
{
case 'Q':
minix_shutdown(0);
NOT_REACHABLE;
#ifdef CONFIG_SMP
case 'B':
dump_bkl_usage();
break;
case 'b':
reset_bkl_usage();
break;
#endif
case '1':
ser_dump_proc();
break;
case '2':
ser_dump_queues();
break;
#ifdef CONFIG_SMP
case '4':
ser_dump_proc_cpu();
break;
#endif
case '5':
ser_dump_vfs();
break;
#if DEBUG_TRACE
#define TOGGLECASE(ch, flag) \
case ch: { \
if(verboseflags & flag) { \
verboseflags &= ~flag; \
kprintf_stub("%s disabled\n", #flag); \
} else { \
verboseflags |= flag; \
kprintf_stub("%s enabled\n", #flag); \
} \
break; \
}
TOGGLECASE('8', VF_SCHEDULING)
TOGGLECASE('9', VF_PICKPROC)
#endif
#ifdef USE_APIC
case 'I':
dump_apic_irq_state();
break;
#endif
}
serial_debug_active = 0;
}
#if DEBUG_SERIAL
static void ser_dump_vfs(void)
{
/* Notify VFS it has to generate stack traces. Kernel can't do that as
* it's not aware of user space threads.
*/
mini_notify(proc_addr(KERNEL), VFS_PROC_NR);
}
#ifdef CONFIG_SMP
static void ser_dump_proc_cpu(void)
{
struct proc *pp;
unsigned cpu;
for (cpu = 0; cpu < ncpus; cpu++) {
kprintf_stub("CPU %d processes : \n", cpu); // MODIFIED
for (pp= BEG_USER_ADDR; pp < END_PROC_ADDR; pp++) {
if (isemptyp(pp) || pp->p_cpu != cpu)
continue;
print_proc(pp);
}
}
}
#endif
#endif /* DEBUG_SERIAL */
#if SPROFILE
int arch_init_profile_clock(const u32_t freq)
{
int r;
/* Set CMOS timer frequency. */
outb(RTC_INDEX, RTC_REG_A);
outb(RTC_IO, RTC_A_DV_OK | freq);
/* Enable CMOS timer interrupts. */
outb(RTC_INDEX, RTC_REG_B);
r = inb(RTC_IO);
outb(RTC_INDEX, RTC_REG_B);
outb(RTC_IO, r | RTC_B_PIE);
/* Mandatory read of CMOS register to enable timer interrupts. */
outb(RTC_INDEX, RTC_REG_C);
inb(RTC_IO);
return CMOS_CLOCK_IRQ;
}
void arch_stop_profile_clock(void)
{
int r;
/* Disable CMOS timer interrupts. */
outb(RTC_INDEX, RTC_REG_B);
r = inb(RTC_IO);
outb(RTC_INDEX, RTC_REG_B);
outb(RTC_IO, r & ~RTC_B_PIE);
}
void arch_ack_profile_clock(void)
{
/* Mandatory read of CMOS register to re-enable timer interrupts. */
outb(RTC_INDEX, RTC_REG_C);
inb(RTC_IO);
}
#endif
void arch_do_syscall(struct proc *proc)
{
/* do_ipc assumes that it's running because of the current process */
KASSERT_PLACEHOLDER(proc == get_cpulocal_var(proc_ptr)); // MODIFIED
/* Make the system call, for real this time. */
KASSERT_PLACEHOLDER(proc->p_misc_flags & MF_SC_DEFER); // MODIFIED
proc->p_reg.retreg =
do_ipc(proc->p_defer.r1, proc->p_defer.r2, proc->p_defer.r3);
}
struct proc * arch_finish_switch_to_user(void)
{
char * stk;
struct proc * p;
#ifdef CONFIG_SMP
stk = (char *)tss[cpuid].sp0;
#else
stk = (char *)tss[0].sp0;
#endif
/* set pointer to the process to run on the stack */
p = get_cpulocal_var(proc_ptr);
*((reg_t *)stk) = (reg_t) p;
/* make sure IF is on in FLAGS so that interrupts won't be disabled
* once p's context is restored.
*/
p->p_reg.psw |= IF_MASK;
/* Set TRACEBIT state properly. */
if(p->p_misc_flags & MF_STEP)
p->p_reg.psw |= TRACEBIT;
else
p->p_reg.psw &= ~TRACEBIT;
return p;
}
void arch_proc_setcontext(struct proc *p, struct stackframe_s *state,
int isuser, int trap_style)
{
if(isuser) {
/* Restore user bits of psw from sc, maintain system bits
* from proc.
*/
state->psw = (state->psw & X86_FLAGS_USER) |
(p->p_reg.psw & ~X86_FLAGS_USER);
}
/* someone wants to totally re-initialize process state */
KASSERT_PLACEHOLDER(sizeof(p->p_reg) == sizeof(*state)); // MODIFIED
if(state != &p->p_reg) {
kmemcpy(&p->p_reg, state, sizeof(*state)); // MODIFIED
}
/* further code is instructed to not touch the context
* any more
*/
p->p_misc_flags |= MF_CONTEXT_SET;
/* on x86 this requires returning using iret (KTS_INT)
* so that the full context is restored instead of relying on
* the userspace doing it (as it would do on SYSEXIT).
* as ESP and EIP are also reset, userspace won't try to
* restore bogus context after returning.
*
* if the process is not blocked, or the kernel will ignore
* our trap style, we needn't panic but things will probably
* not go well for the process (restored context will be ignored)
* and the situation should be debugged.
*/
if(!(p->p_rts_flags)) {
kprintf_stub("WARNINIG: setting full context of runnable process\n"); // MODIFIED
print_proc(p);
util_stacktrace();
}
if(p->p_seg.p_kern_trap_style == KTS_NONE)
kprintf_stub("WARNINIG: setting full context of out-of-kernel process\n"); // MODIFIED
p->p_seg.p_kern_trap_style = trap_style;
}
void restore_user_context(struct proc *p)
{
int trap_style = p->p_seg.p_kern_trap_style;
#if 0
#define TYPES 10
static int restores[TYPES], n = 0;
if(trap_style >= 0 && trap_style < TYPES)
restores[trap_style]++;
if(!(n++ % 500000)) {
int t;
for(t = 0; t < TYPES; t++)
if(restores[t])
kprintf_stub("%d: %d ", t, restores[t]); // MODIFIED
kprintf_stub("\n"); // MODIFIED
}
#endif
p->p_seg.p_kern_trap_style = KTS_NONE;
if(trap_style == KTS_SYSENTER) {
restore_user_context_sysenter(p);
NOT_REACHABLE;
}
if(trap_style == KTS_SYSCALL) {
restore_user_context_syscall(p);
NOT_REACHABLE;
}
switch(trap_style) {
case KTS_NONE:
panic("no entry trap style known");
case KTS_INT_HARD:
case KTS_INT_UM:
case KTS_FULLCONTEXT:
case KTS_INT_ORIG:
restore_user_context_int(p);
NOT_REACHABLE;
default:
panic("unknown trap style recorded");
NOT_REACHABLE;
}
NOT_REACHABLE;
}
void fpu_sigcontext(struct proc *pr, struct sigframe_sigcontext *fr, struct sigcontext *sc)
{
int fp_error;
if (osfxsr_feature) {
// FIXME: sc fields will be problematic
fp_error = sc->sc_fpu_state.xfp_regs.fp_status &
~sc->sc_fpu_state.xfp_regs.fp_control;
} else {
// FIXME: sc fields will be problematic
fp_error = sc->sc_fpu_state.fpu_regs.fp_status &
~sc->sc_fpu_state.fpu_regs.fp_control;
}
if (fp_error & 0x001) { /* Invalid op */
/*
* swd & 0x240 == 0x040: Stack Underflow
* swd & 0x240 == 0x240: Stack Overflow
* User must clear the SF bit (0x40) if set
*/
fr->sf_code = FPE_FLTINV; // FPE_FLTINV might be undefined
} else if (fp_error & 0x004) {
fr->sf_code = FPE_FLTDIV; /* Divide by Zero */ // FPE_FLTDIV might be undefined
} else if (fp_error & 0x008) {
fr->sf_code = FPE_FLTOVF; /* Overflow */ // FPE_FLTOVF might be undefined
} else if (fp_error & 0x012) {
fr->sf_code = FPE_FLTUND; /* Denormal, Underflow */ // FPE_FLTUND might be undefined
} else if (fp_error & 0x020) {
fr->sf_code = FPE_FLTRES; /* Precision */ // FPE_FLTRES might be undefined
} else {
fr->sf_code = 0; /* XXX - probably should be used for FPE_INTOVF or
* FPE_INTDIV */
}
}
reg_t arch_get_sp(struct proc *p) { return p->p_reg.sp; }
#if !CONFIG_OXPCIE
static void ser_init(void)
{
unsigned char lcr;
unsigned divisor;
/* keep BIOS settings if cttybaud is not set */
if (kinfo.serial_debug_baud <= 0) return;
/* set DLAB to make baud accessible */
lcr = LCR_8BIT | LCR_1STOP | LCR_NPAR;
outb(COM1_LCR, lcr | LCR_DLAB);
/* set baud rate */
divisor = UART_BASE_FREQ / kinfo.serial_debug_baud;
if (divisor < 1) divisor = 1;
if (divisor > 65535) divisor = 65535;
outb(COM1_DLL, divisor & 0xff);
outb(COM1_DLM, (divisor >> 8) & 0xff);
/* clear DLAB */
outb(COM1_LCR, lcr);
}
#endif