mirror of
https://github.com/wfjm/w11.git
synced 2026-01-21 10:42:10 +00:00
stktst: minor updates, add README and data [skip ci]
- stktst.c: add (s,c,o) breakdown of sp address - dotst.s: skip -c and -s for negative counts
This commit is contained in:
parent
6d98a17e86
commit
1be7bb0376
@ -1,4 +1,4 @@
|
||||
# $Id: $
|
||||
# $Id: Makefile 1267 2022-08-02 06:27:29Z mueller $
|
||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||
# Copyright 2022- by Walter F.J. Mueller <W.F.J.Mueller@gsi.de>
|
||||
#
|
||||
|
||||
83
tools/tests/stktst/README.md
Normal file
83
tools/tests/stktst/README.md
Normal file
@ -0,0 +1,83 @@
|
||||
## stktst: a program testing 2.11BSD stack extension logic
|
||||
|
||||
The `stktst` program exercises the 2.11BSD stack extension logic.
|
||||
In a first step, the `sp` can be aligned to a click (64 byte) or a
|
||||
segment (8129 byte) boundary.
|
||||
An offset can also be applied after this alignment.
|
||||
In a second step, a sequence of integer and floating point instructions with
|
||||
a `-(sp)` destination is executed.
|
||||
This allows to set up almost every possible stack extension situation.
|
||||
|
||||
Motivation for `stktst` were differences in the `MMR1` register implementation
|
||||
in different PDP-11 CPUs, and differences in the modeling of `MMR1` in
|
||||
different PDP-11 simulators.
|
||||
That combined with the 2.11BSD stack extension handling prior to #473 can lead
|
||||
to unexpected "Memory fault" aborts in 2.11BSD.
|
||||
|
||||
The results are collected in the [data](data) folder.
|
||||
|
||||
`stktst` has an assembler core [dotst.s](dotst.s) which is called from a
|
||||
C main program [stktst.c](stktst.c). It is called as
|
||||
```
|
||||
./stktst <cmd> <count> [-s ns] [-c nc] [-o no]
|
||||
```
|
||||
The options control the initial stack alignment:
|
||||
- **`-s ns`**: aligns to 8192 byte segment boundaries. ns=1 to the next one,
|
||||
nc=2 to the second next one, etc.
|
||||
Obviously, `ns` should be smaller than 8.
|
||||
The option is ignored if ns<=0.
|
||||
- **`-c nc`**: aligns to 64 byte click boundaries. nc=1 to the next one,
|
||||
nc=2 to the second next one, etc.
|
||||
The first alignment step will not change the stack if it was alreay on a
|
||||
click bounday, it will therefore add 0 to 64 bytes to the stack.
|
||||
The option is ignored if nc<=0.
|
||||
Click alignment is done after segment alignment.
|
||||
- **`-o no`**: adds `no` to `sp`. `no` must be even and can be positive or
|
||||
negative.
|
||||
|
||||
**Notes**:
|
||||
- no range checks is done for `no`.
|
||||
After a **-s** is is save to use small positive `no` values to position `sp`
|
||||
a bit before a segment boundary.
|
||||
After a **-c** is is better to use negative `no` values to position `sp`
|
||||
before the next click boundary.
|
||||
- the stack allocated below the argument and environment values.
|
||||
The initial `sp` value will therefore decrease when the number of characters
|
||||
in the argument list increases because the stack base moves down.
|
||||
In some cases it is therefore prudent to specify the numbers as quoted
|
||||
strings with some leading blanks, like
|
||||
```
|
||||
./stktst d ' 3' -c ' 2' -o ' 4'
|
||||
```
|
||||
That allows to change the counts without changing the length of the
|
||||
argument list.
|
||||
|
||||
The `cmd` argument selects the instruction that does the stack push and
|
||||
`count` determines how often it is executed.
|
||||
The available modes for `cmd` are
|
||||
- **`I`**: use `clr -(sp)` --> integer word push
|
||||
- **`i`**: use `movfi -(sp)` after `seti` --> word push from FPP
|
||||
- **`l`**: use `movfi -(sp)` after `setl` --> double word push from FPP
|
||||
- **`f`**: use `movf -(sp)` after `setf` --> double word push from FPP
|
||||
- **`d`**: use `movf -(sp)` after `setd` --> quad word push from FPP
|
||||
|
||||
For debug purposes three additional `cmd` modes are available:
|
||||
- **`r`**: uses `count` as an address and reads
|
||||
- **`w`**: uses `count` as an address, reads and re-writes
|
||||
- **`h`**: runs a `halt`
|
||||
|
||||
`stktst` prints the `sp` after alignment and after the stack pushes like
|
||||
```
|
||||
stktst-I: before sp 177304 (0, 4,60); 177200 (0, 5,64);
|
||||
stktst-I: after sp 177304 (0, 4,60); 177200 (0, 5,64); 167200 (0, 69,64);
|
||||
```
|
||||
and gives the `sp` value
|
||||
- after `dotst.s` is called
|
||||
- after alignments and offsets were applied
|
||||
- after stack pushes were executed
|
||||
|
||||
and prints it in octal and broken down in segment, click and byte offset.
|
||||
Because the stack is a downward growing segment, all offsets measure the
|
||||
distance to the top of memory and increase when the `sp` decreases.
|
||||
|
||||
When a stack extension fails, the program will print the first line and abort.
|
||||
109
tools/tests/stktst/data/2022-08-03_simh_3.11_bsd_447.md
Normal file
109
tools/tests/stktst/data/2022-08-03_simh_3.11_bsd_447.md
Normal file
@ -0,0 +1,109 @@
|
||||
## 2022-08-03: tests with SimH V3.11-0 and 2.11BSD 447 (plus 453 patch)
|
||||
|
||||
### Background
|
||||
The `MMR1` response after an MMU abort in an FPP instruction depends on the CPU.
|
||||
In an 11/70, the registers reflect the state at abort and `MMR1` shows the
|
||||
change. In a J11, the registers are unchanged, and `MMR1` shows zero.
|
||||
|
||||
SimH V3.11-0 used the FPP MMU abort handling for _all_ CPU models.
|
||||
So even when an 11/70 is modeled, the behavior is like a J11.
|
||||
|
||||
The 2.11BSD stack extension logic checks whether the `sp` is below the
|
||||
current stack allocation, and only in that case, the stack is extended.
|
||||
On a J11-based system that fails, that's why 2.11BSD up to #473 has a
|
||||
workaround and shifts the `sp` down by 4 _if and only if_ a J11 was
|
||||
probed at boot time. The pertinent code in `/usr/src/sys/pdp/trap.c` is
|
||||
```
|
||||
osp = sp;
|
||||
if (kdj11)
|
||||
osp -= 4;
|
||||
if (backup(u.u_ar0) == 0)
|
||||
if (!(u.u_sigstk.ss_flags & SA_ONSTACK) && grow((u_int)osp))
|
||||
goto out;
|
||||
i = SIGSEGV;
|
||||
```
|
||||
|
||||
That leads to two vulnerabilities:
|
||||
- a `double` push of 8 bytes might fail on J11 systems, real or simulated,
|
||||
- in a SimH 11/70, which probes as an 11/70 but behaves like a J11, any
|
||||
push from an FPP instruction might fail.
|
||||
|
||||
The first is a 2.11BSD issue, the second is a SimH issue.
|
||||
|
||||
The tests were run under `tcsh`, it gives "Segmentation fault" in case of
|
||||
a problem. Under `sh` one gets "Memory fault".
|
||||
|
||||
### SimH in 11/94 mode
|
||||
SimH pdp11 started with
|
||||
```
|
||||
set cpu 11/94
|
||||
```
|
||||
and 2.11BSD starts with
|
||||
```
|
||||
94Boot from xp(0,0,0) at 0176700
|
||||
```
|
||||
Extending the stack with `float` pushes is no problem until the stack segment
|
||||
has grown to 020000 and memory is really exhausted:
|
||||
```
|
||||
./stktst f ' 1024'
|
||||
# stktst-I: before sp 177334 (0, 4,36); 177334 (0, 4,36);
|
||||
# stktst-I: after sp 177334 (0, 4,36); 177334 (0, 4,36); 167334 (0, 68,36);
|
||||
./stktst f '14263'
|
||||
# stktst-I: before sp 177334 (0, 4,36); 177334 (0, 4,36);
|
||||
# stktst-I: after sp 177334 (0, 4,36); 177334 (0, 4,36); 020000 (6,127,64);
|
||||
./stktst f '14264'
|
||||
# stktst-I: before sp 177334 (0, 4,36); 177334 (0, 4,36);
|
||||
# Segmentation fault (core dumped)
|
||||
|
||||
```
|
||||
|
||||
Extending with `double` pushes works when the `double` is aligned on an
|
||||
8 byte border. In this case the 4 byte correction done in 2.11BSD #473
|
||||
ensures that the `sp` is interpreted as below current allocation.
|
||||
The alignment is set up with `-c 2 -o 0`:
|
||||
```
|
||||
./stktst d ' 512' -c ' 2' -o ' 0'
|
||||
# stktst-I: before sp 177304 (0, 4,60); 177200 (0, 5,64);
|
||||
# stktst-I: after sp 177304 (0, 4,60); 177200 (0, 5,64); 167200 (0, 69,64);
|
||||
./stktst d '7120' -c ' 2' -o ' 0'
|
||||
# stktst-I: before sp 177304 (0, 4,60); 177200 (0, 5,64);
|
||||
# stktst-I: after sp 177304 (0, 4,60); 177200 (0, 5,64); 020000 (6,127,64);
|
||||
./stktst d '7121' -c ' 2' -o ' 0'
|
||||
# stktst-I: before sp 177304 (0, 4,60); 177200 (0, 5,64);
|
||||
# Segmentation fault (core dumped)
|
||||
```
|
||||
|
||||
Misaligned `double` pushes fail as expected.
|
||||
A 4 byte misalignment is set up with `-c 2 -o -4`.
|
||||
Even with the 4 byte correction the `sp` appears to be in the allocated area,
|
||||
and a `SIGSEGV` is taken:
|
||||
```
|
||||
./stktst d ' 1' -c ' 2' -o ' -4'
|
||||
# stktst-I: before sp 177304 (0, 4,60); 177174 (0, 6, 4);
|
||||
# stktst-I: after sp 177304 (0, 4,60); 177174 (0, 6, 4); 177164 (0, 6,12);
|
||||
./stktst d ' 319' -c ' 2' -o ' -4'
|
||||
# stktst-I: before sp 177304 (0, 4,60); 177174 (0, 6, 4);
|
||||
# stktst-I: after sp 177304 (0, 4,60); 177174 (0, 6, 4); 172204 (0, 45,60);
|
||||
./stktst d ' 320' -c ' 2' -o ' -4'
|
||||
# stktst-I: before sp 177304 (0, 4,60); 177174 (0, 6, 4);
|
||||
# Segmentation fault (core dumped)
|
||||
```
|
||||
|
||||
The initial stack size is 20 clicks
|
||||
(see [SSIZE](https://www.retro11.de/ouxr/211bsd/usr/src/sys/pdp/machparam.h.html#m:SSIZE)),
|
||||
the stack increment is also 20 clicks
|
||||
(see [SINCR](https://www.retro11.de/ouxr/211bsd/usr/src/sys/pdp/machparam.h.html#m:SINCR)).
|
||||
The initial stack segment size is a bit larger due to argument and environment
|
||||
allocations.
|
||||
In the tests it was 24 clicks as tests with the **r** command show:
|
||||
```
|
||||
./stktst r 0175004
|
||||
# OK
|
||||
./stktst r 0175000
|
||||
# OK
|
||||
./stktst r 0174776
|
||||
# Segmentation fault (core dumped)
|
||||
```
|
||||
|
||||
It is therefore a bit surprising that the failure happens at the border
|
||||
expected for the second stack extend and not around 0175000.
|
||||
@ -1,4 +1,4 @@
|
||||
/ $Id: $
|
||||
/ $Id: dotst.s 1268 2022-08-04 07:03:08Z mueller $
|
||||
/ SPDX-License-Identifier: GPL-3.0-or-later
|
||||
/ Copyright 2022- by Walter F.J. Mueller <W.F.J.Mueller@gsi.de>
|
||||
/
|
||||
@ -17,7 +17,7 @@
|
||||
/
|
||||
/ Revision History:
|
||||
/ Date Rev Version Comment
|
||||
/ 2022-08-01 1267 1.0 Initial version
|
||||
/ 2022-08-03 1268 1.0 Initial version
|
||||
/
|
||||
|
||||
.globl _dotst
|
||||
@ -82,7 +82,7 @@ testx:
|
||||
mov sp,r4
|
||||
/ handle -s
|
||||
tst 6(r2) / idat[3] -s count > 0 ?
|
||||
beq optc
|
||||
ble optc
|
||||
bic $017777,r4 / sp &= 017777
|
||||
mov 6(r2),r1
|
||||
dec r1 / idat[3]-1
|
||||
@ -90,7 +90,7 @@ testx:
|
||||
sub r1,r4 / sp -= 8192 * (idat[3]-1)
|
||||
/ handle -c
|
||||
optc: tst 4(r2) / idat[2] -c count > 0 ?
|
||||
beq opto
|
||||
ble opto
|
||||
bic $000077,r4 / sp &= 077
|
||||
mov 4(r2),r1
|
||||
dec r1 / idat[2]-1
|
||||
|
||||
@ -1,10 +1,10 @@
|
||||
/* $Id: $ */
|
||||
/* $Id: stktst.c 1268 2022-08-04 07:03:08Z mueller $ */
|
||||
/* SPDX-License-Identifier: GPL-3.0-or-later */
|
||||
/* Copyright 2022- by Walter F.J. Mueller <W.F.J.Mueller@gsi.de> */
|
||||
|
||||
/* Revision History: */
|
||||
/* Date Rev Version Comment */
|
||||
/* 2022-08-01 1267 1.0 Initial version */
|
||||
/* 2022-08-03 1268 1.0 Initial version */
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
@ -37,6 +37,15 @@ int doconv(arg)
|
||||
return ires;
|
||||
}
|
||||
|
||||
print_stack(val)
|
||||
unsigned int val;
|
||||
{
|
||||
unsigned int ns = 7-(val>>13);
|
||||
unsigned int nc = 127-((val&017777)>>6);
|
||||
unsigned int no = 64-(val&077);
|
||||
fprintf(stdout," %06o (%1d,%3d,%2d);", val, ns, nc, no);
|
||||
}
|
||||
|
||||
|
||||
int main(argc, argv)
|
||||
int argc;
|
||||
@ -47,7 +56,7 @@ int main(argc, argv)
|
||||
int rcnt = 0;
|
||||
int cnt = 0;
|
||||
int idat[5];
|
||||
int odat[3];
|
||||
unsigned int odat[3];
|
||||
int optrwh = 0;
|
||||
int dotst();
|
||||
|
||||
@ -105,12 +114,19 @@ int main(argc, argv)
|
||||
/* call test: 1st round */
|
||||
dotst(idat, odat);
|
||||
if (optrwh) exit(0);
|
||||
fprintf(stdout, "stktst-I: before sp %06o %06o\n", odat[0], odat[1]);
|
||||
printf("stktst-I: before sp");
|
||||
print_stack(odat[0]);
|
||||
print_stack(odat[1]);
|
||||
printf("\n");
|
||||
|
||||
/* call test: 2nd round */
|
||||
idat[1] = rcnt;
|
||||
dotst(idat, odat);
|
||||
fprintf(stdout, "stktst-I: after sp %06o %06o %6o\n",
|
||||
odat[0], odat[1], odat[2]);
|
||||
printf("stktst-I: after sp");
|
||||
print_stack(odat[0]);
|
||||
print_stack(odat[1]);
|
||||
print_stack(odat[2]);
|
||||
printf("\n");
|
||||
|
||||
exit(0);
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user