Skip to content

Commit e36194f

Browse files
authored
Merge pull request #168 from f9micro/fix-kprobe
Resolve issues IRQ handling, IPC, and fpage
2 parents 69e0388 + edceda3 commit e36194f

File tree

10 files changed

+307
-76
lines changed

10 files changed

+307
-76
lines changed

.github/workflows/build.yml

Lines changed: 32 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -58,17 +58,42 @@ jobs:
5858
cat qemu.log
5959
echo "==================="
6060
61+
# Check for crashes first (highest priority failure)
62+
if grep -qE "MEMFAULT|HardFault|panic|PANIC" qemu.log; then
63+
echo "✗ Kernel crash detected"
64+
exit 1
65+
fi
66+
67+
# Check for test failures
68+
if grep -q "FAILED" qemu.log; then
69+
echo "✗ Test failure detected:"
70+
grep -B1 "FAILED" qemu.log
71+
exit 1
72+
fi
73+
74+
# Check for successful boot
6175
if grep -q "Press '?' to print KDB menu" qemu.log; then
62-
echo "✓ KDB shell ready"; exit 0
76+
echo "✓ KDB shell ready"
6377
elif grep -q "KDB" qemu.log; then
64-
echo "✓ KDB initialized"; exit 0
78+
echo "✓ KDB initialized"
6579
elif grep -q "f9\|F9" qemu.log; then
66-
echo "✓ Kernel boot detected"; exit 0
80+
echo "✓ Kernel boot detected"
81+
else
82+
echo "✗ No boot message detected (timeout or minimal output)"
83+
exit 1
84+
fi
85+
86+
# Check for test results if tests ran
87+
if grep -q "test suite complete" qemu.log; then
88+
ok_count=$(grep -c "OK" qemu.log || echo 0)
89+
echo "✓ Test suite complete: $ok_count tests passed"
90+
exit 0
6791
fi
6892
69-
if grep -qE "MEMFAULT|HardFault|panic" qemu.log; then
70-
echo "✗ Kernel crash detected"; exit 1
93+
# Fallback: tests started but didn't complete
94+
if grep -q "test suite starts" qemu.log; then
95+
echo "✗ Test suite started but did not complete (timeout)"
96+
exit 1
7197
fi
7298
73-
echo "✗ No boot message detected (timeout or minimal output)"
74-
exit 1
99+
exit 0

include/platform/irq.h

Lines changed: 26 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,12 @@ void irq_init(void);
1616

1717
static inline void irq_disable(void)
1818
{
19-
__asm__ __volatile__ ("cpsid i");
19+
__asm__ __volatile__ ("cpsid i" ::: "memory");
2020
}
2121

2222
static inline void irq_enable(void)
2323
{
24-
__asm__ __volatile__ ("cpsie i");
24+
__asm__ __volatile__ ("cpsie i" ::: "memory");
2525
}
2626

2727
static inline void irq_svc(void)
@@ -34,9 +34,8 @@ static inline int irq_number(void)
3434
int irqno;
3535

3636
__asm__ __volatile__ (
37-
"mrs r0, ipsr\n"
38-
"mov r0, %0"
39-
: "=r" (irqno) : : "r0");
37+
"mrs %0, ipsr"
38+
: "=r" (irqno));
4039

4140
return irqno;
4241
}
@@ -45,7 +44,7 @@ static inline int irq_number(void)
4544
* Global to hold saved r4-r11 across irq_save_regs_only / irq_save_rest.
4645
* Used to capture registers before compiler can corrupt them.
4746
*/
48-
extern uint32_t __irq_saved_regs[8];
47+
extern volatile uint32_t __irq_saved_regs[8];
4948

5049
/*
5150
* irq_save_regs_only()
@@ -70,9 +69,16 @@ extern uint32_t __irq_saved_regs[8];
7069
#define __irq_save(ctx) \
7170
{ \
7271
uint32_t *_regs = (uint32_t *)(ctx)->regs; \
73-
extern uint32_t __irq_saved_regs[8]; \
74-
for (int _i = 0; _i < 8; _i++) \
75-
_regs[_i] = __irq_saved_regs[_i]; \
72+
extern volatile uint32_t __irq_saved_regs[8]; \
73+
/* Explicit unrolled copy to prevent loop mis-optimization */ \
74+
_regs[0] = __irq_saved_regs[0]; \
75+
_regs[1] = __irq_saved_regs[1]; \
76+
_regs[2] = __irq_saved_regs[2]; \
77+
_regs[3] = __irq_saved_regs[3]; \
78+
_regs[4] = __irq_saved_regs[4]; \
79+
_regs[5] = __irq_saved_regs[5]; \
80+
_regs[6] = __irq_saved_regs[6]; \
81+
_regs[7] = __irq_saved_regs[7]; \
7682
} \
7783
__asm__ __volatile__ ("and r4, lr, 0xf":::"r4"); \
7884
__asm__ __volatile__ ("teq r4, #0x9"); \
@@ -113,7 +119,7 @@ extern uint32_t __irq_saved_regs[8];
113119
__asm__ __volatile__ ("msrne psp, r0"); \
114120
__asm__ __volatile__ ("mov r0, %0" : : "r" ((ctx)->regs)); \
115121
__asm__ __volatile__ ("ldm r0, {r4-r11}"); \
116-
__asm__ __volatile__ ("msr control, r2");
122+
__asm__ __volatile__ ("msr control, r2\n\tisb" ::: "memory");
117123

118124
#ifdef CONFIG_FPU
119125
#define irq_restore(ctx) \
@@ -162,8 +168,17 @@ extern uint32_t __irq_saved_regs[8];
162168
{ \
163169
register tcb_t *sel; \
164170
sel = schedule_select(); \
165-
if (sel != current) \
171+
if (sel != current) { \
166172
context_switch(current, sel); \
173+
} else { \
174+
/* No context switch - restore saved registers \
175+
* and return via irq_return path */ \
176+
extern volatile uint32_t __irq_saved_regs[8]; \
177+
__asm__ __volatile__ ( \
178+
"mov r0, %0\n\t" \
179+
"ldm r0, {r4-r11}" \
180+
: : "r" (__irq_saved_regs) : "r0"); \
181+
} \
167182
}
168183

169184
#define request_schedule() \

kernel/fpage.c

Lines changed: 115 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,13 @@ void fpages_init(void)
8181
*/
8282
static void insert_fpage_chain_to_as(as_t *as, fpage_t *first, fpage_t *last)
8383
{
84-
fpage_t *fp = as->first;
84+
fpage_t *fp;
85+
86+
/* NULL chain is a no-op */
87+
if (!first || !last)
88+
return;
89+
90+
fp = as->first;
8591

8692
if (!fp) {
8793
/* First chain in AS */
@@ -149,14 +155,13 @@ static fpage_t *create_fpage(memptr_t base, size_t shift, int mpid)
149155
dbg_printf(DL_KDB,
150156
"FPAGE: alloc failed! count=%d base=%p shift=%d mpid=%d\n",
151157
fpage_alloc_count, base, shift, mpid);
152-
} else {
153-
fpage_alloc_count++;
154-
if ((fpage_alloc_count % 50) == 0)
155-
dbg_printf(DL_KDB, "FPAGE: allocated %d fpages\n",
156-
fpage_alloc_count);
158+
return NULL;
157159
}
158160

159-
assert((intptr_t) fpage);
161+
fpage_alloc_count++;
162+
if ((fpage_alloc_count % 50) == 0)
163+
dbg_printf(DL_KDB, "FPAGE: allocated %d fpages\n",
164+
fpage_alloc_count);
160165

161166
fpage->as_next = NULL;
162167
fpage->map_next = fpage; /* That is first fpage in mapping */
@@ -179,11 +184,26 @@ void destroy_fpage(fpage_t *fpage)
179184
ktable_free(&fpage_table, fpage);
180185
}
181186

187+
/**
188+
* Free a chain of fpages
189+
* @param first - first fpage in chain (may be NULL)
190+
*/
191+
static void free_fpage_chain(fpage_t *first)
192+
{
193+
fpage_t *fp, *next;
194+
195+
for (fp = first; fp; fp = next) {
196+
next = fp->as_next;
197+
ktable_free(&fpage_table, fp);
198+
}
199+
}
200+
182201
static void create_fpage_chain(memptr_t base, size_t size, int mpid,
183202
fpage_t **pfirst, fpage_t **plast)
184203
{
185204
int shift, sshift, bshift;
186205
fpage_t *fpage = NULL;
206+
fpage_t *newfp;
187207

188208
while (size) {
189209
/* Select minimum of base alignment and largest fitting size.
@@ -195,29 +215,40 @@ static void create_fpage_chain(memptr_t base, size_t size, int mpid,
195215

196216
shift = (bshift < sshift) ? bshift : sshift;
197217

218+
newfp = create_fpage(base, shift, mpid);
219+
if (!newfp) {
220+
/* Allocation failed - leave chain incomplete */
221+
dbg_printf(DL_KDB,
222+
"FPAGE: chain alloc failed at base=%p\n", base);
223+
return;
224+
}
225+
198226
if (!*pfirst) {
199227
/* Create first page */
200-
fpage = create_fpage(base, shift, mpid);
228+
fpage = newfp;
201229
*pfirst = fpage;
202230
*plast = fpage;
203231
} else {
204232
/* Build chain */
205-
fpage->as_next = create_fpage(base, shift, mpid);
233+
fpage->as_next = newfp;
206234
fpage = fpage->as_next;
207235
*plast = fpage;
208236
}
209237

210-
size -= (1 << shift);
211-
base += (1 << shift);
238+
size -= ((memptr_t)1 << shift);
239+
base += ((memptr_t)1 << shift);
212240
}
213241
}
214242

215243
fpage_t *split_fpage(as_t *as, fpage_t *fpage, memptr_t split, int rl)
216244
{
217245
memptr_t base = fpage->fpage.base,
218-
end = fpage->fpage.base + (1 << fpage->fpage.shift);
246+
end = fpage->fpage.base + ((memptr_t)1 << fpage->fpage.shift);
219247
fpage_t *lfirst = NULL, *llast = NULL, *rfirst = NULL, *rlast = NULL;
220248

249+
if (!as || !fpage)
250+
return NULL;
251+
221252
/* For rl=1 (right side), round DOWN to include the split point.
222253
* For rl=0 (left side), round UP to exclude past the split point.
223254
*/
@@ -226,11 +257,10 @@ fpage_t *split_fpage(as_t *as, fpage_t *fpage, memptr_t split, int rl)
226257
else
227258
split = mempool_align(fpage->fpage.mpid, split);
228259

229-
if (!as)
230-
return NULL;
231-
232-
/* Check if we can split something */
233-
if (split == base || split == end) {
260+
/* Check if split point is valid after alignment.
261+
* Must be strictly between base and end.
262+
*/
263+
if (split <= base || split >= end) {
234264
return fpage;
235265
}
236266

@@ -246,6 +276,26 @@ fpage_t *split_fpage(as_t *as, fpage_t *fpage, memptr_t split, int rl)
246276
create_fpage_chain(split, (end - split),
247277
fpage->fpage.mpid, &rfirst, &rlast);
248278

279+
/* Check if both chains were created successfully.
280+
* If either failed, keep the original fpage intact.
281+
*/
282+
if (!lfirst || !llast || !rfirst || !rlast) {
283+
/* Free any partially created chains */
284+
fpage_t *fp, *next;
285+
for (fp = lfirst; fp; fp = next) {
286+
next = fp->as_next;
287+
ktable_free(&fpage_table, fp);
288+
}
289+
for (fp = rfirst; fp; fp = next) {
290+
next = fp->as_next;
291+
ktable_free(&fpage_table, fp);
292+
}
293+
dbg_printf(DL_KDB,
294+
"FPAGE: split failed, keeping original (base=%p split=%p)\n",
295+
base, split);
296+
return NULL;
297+
}
298+
249299
remove_fpage_from_as(as, fpage);
250300
ktable_free(&fpage_table, fpage);
251301

@@ -283,6 +333,14 @@ int assign_fpages_ext(int mpid, as_t *as, memptr_t base, size_t size,
283333

284334
end = base + size;
285335

336+
/* Overflow check: end must be greater than base */
337+
if (end < base) {
338+
dbg_printf(DL_KDB,
339+
"FPAGE: overflow in assign_fpages_ext base=%p size=%p\n",
340+
base, size);
341+
return -1;
342+
}
343+
286344
if (as) {
287345
/* find unmapped space */
288346
fp = &as->first;
@@ -315,8 +373,10 @@ int assign_fpages_ext(int mpid, as_t *as, memptr_t base, size_t size,
315373
}
316374

317375
/* NULL guard: create_fpage_chain may fail */
318-
if (!first || !last)
376+
if (!first || !last) {
377+
free_fpage_chain(first);
319378
return -1;
379+
}
320380

321381
last->as_next = *fp;
322382
*fp = first;
@@ -382,6 +442,14 @@ int assign_fpages_ext(int mpid, as_t *as, memptr_t base, size_t size,
382442
return -1;
383443

384444
create_fpage_chain(abase, aend - abase, mpid, pfirst, plast);
445+
446+
/* Check if chain creation failed */
447+
if (!*pfirst || !*plast) {
448+
free_fpage_chain(*pfirst);
449+
*pfirst = NULL;
450+
*plast = NULL;
451+
return -1;
452+
}
385453
}
386454
}
387455

@@ -397,9 +465,24 @@ int assign_fpages(as_t *as, memptr_t base, size_t size)
397465

398466
int map_fpage(as_t *src, as_t *dst, fpage_t *fpage, map_action_t action)
399467
{
400-
fpage_t *fpmap = (fpage_t *) ktable_alloc(&fpage_table);
468+
fpage_t *fpmap;
469+
470+
/* NULL fpage or dst is a programming error - fail gracefully */
471+
if (!fpage || !dst) {
472+
dbg_printf(DL_KDB,
473+
"FPAGE: map_fpage NULL arg! fpage=%p dst=%p\n",
474+
fpage, dst);
475+
return -1;
476+
}
477+
478+
fpmap = (fpage_t *) ktable_alloc(&fpage_table);
479+
480+
if (!fpmap) {
481+
dbg_printf(DL_KDB,
482+
"FPAGE: map alloc failed! src=%p dst=%p\n", src, dst);
483+
return -1;
484+
}
401485

402-
/* FIXME: check for fpmap == NULL */
403486
fpmap->as_next = NULL;
404487
fpmap->mpu_next = NULL;
405488

@@ -438,8 +521,18 @@ int unmap_fpage(as_t *as, fpage_t *fpage)
438521
if (!(fpage->fpage.flags & FPAGE_CLONE))
439522
return -1;
440523

441-
while (fpprev->map_next != fpage)
442-
fpprev = fpprev->map_next;
524+
/* Find previous fpage in circular map list with cycle guard */
525+
{
526+
int guard = CONFIG_MAX_FPAGES;
527+
while (fpprev->map_next != fpage && --guard > 0)
528+
fpprev = fpprev->map_next;
529+
530+
if (guard <= 0) {
531+
dbg_printf(DL_KDB,
532+
"FPAGE: cycle detected in unmap_fpage %p\n", fpage);
533+
return -1;
534+
}
535+
}
443536

444537
/* Clear flags */
445538
fpprev->fpage.flags &= ~FPAGE_MAPPED;

0 commit comments

Comments
 (0)