I took this from the train back from Majdanek. Fields outside Cienin, in Wielkopolska, fifty-odd kilometres from Chełmno nad Nerem.
The train was carrying me away from a place where people were murdered. The fields were ordinary.
Chełmno was the first German extermination camp. The Germans built it for no purpose but killing, and they called it Kulmhof. The gas vans began running there in December 1941; by the end, more than a hundred and fifty thousand people had been murdered there, almost all of them Jews.
Between five and six million Polish citizens were killed, three million of them Jews. Much of the killing was carried out on Polish soil: at Auschwitz-Birkenau, Treblinka, Sobibór, Bełżec, Majdanek, and Chełmno, all of them German Nazi camps and killing centers built in German-occupied Poland.
Whole towns where no one came home.
A civilization of a thousand years, destroyed in five.
The fields are beautiful now. The forests have grown back. The track is still there. It is the same line: the transports from Łódź came along it as far as Koło, east of here. The last ten kilometres were made in lorries, on narrow-gauge trains, and on foot. Rye and wheat move in the wind; storks return in spring; villages keep their names. That beauty is not a contradiction of what happened. It is the same country: the one that was taken from the people who lived in it, and the one that outlived them.
This soil was left in someone's arms before memory began.
What remains is the duty to remember precisely. The names. The places. The dates. The silence in those places now is not empty. It is the shape of what was taken.
This is a shared history, and it cannot be told without Poland. For nearly a thousand years, Polish citizens (Jews and Catholics, scholars and merchants) built one of the great civilizations of Europe. From the Statute of Kalisz in 1264, through the academies of Kraków and Lublin, to the printing houses of Warsaw and the streets of Wilno, they wrote in Polish, Yiddish, and Hebrew. They fought together in Polish uprisings. They rest together in Polish soil.
And then they were murdered, the Jews hunted until there was almost no one left to find. And the world let it happen. And the fields kept growing: beautiful, indifferent, alive.
To study this history through the objects, documents, and testimonies that preserve it, I recommend:
Images are now fabricated as easily as they are taken. So the claim this page makes is narrow. Light hit a sensor and the sensor wrote a file. The file is the one you are looking at, and it has not changed since I took the photo. That much rests on my word. The hash, the signatures, and the Bitcoin block at the foot of this page prove the rest: it has not changed since it was signed and anchored.
Provenance · Integrity Record
Canonical text · SHA‑512
Hash of the canonical text source (kept local; the manifest is public). Verify with sha512sum -c SHA512SUMS-html; the Bitcoin attestation, once confirmed, is in the .ots proof.
I have been thinking about Jadwiga Ankiewicz for months, and I still do not know how to begin. She was just a girl living in Warsaw. Her family remembered her as caring, attentive, sensitive, and brave. She loved geography, football, and sewing costumes for the family plays she directed herself.
On 15 January 1943, when she was sixteen, the Germans caught her in one of the largest street round-ups Warsaw had seen. They locked her in Pawiak prison, and two days later a cattle car took her to Majdanek. The trip takes five hours by train. It took twenty-four hours. There was no water. By morning they were licking the snow that blew in through the gaps in the floorboards.
At the camp they were searched by hooded German women. The notebook and the pencil stayed hidden, though being caught with them could mean a beating, or death. She wrote anyway, almost every day, out of sight of the guards. She wrote about the sunset and the barbed wire that cut across it. She wrote about the lights that hung from the wire: “How I hate those glittering, mocking lights. They always spoil a good mood.” She wrote about home, and asked whether anyone there still thought of her, or knew where she was.
She worked in the laundry, next to the old crematorium and the building where the bodies were kept. Four friends went there with her: Krysia, Marysia, Janka, and Mietka. Jadwiga was the youngest. The other women called the five of them the Majdanek quintuplets. The camp was run by the SS-Totenkopfverbände, the Death's Head units. Her months there fell during the destruction of the Warsaw Ghetto, and she watched the transports come in. She wrote about that too. She wrote about a German guard named Anni who, in a good mood, played tag with them in the field. She wrote what was in front of her, on the day it happened.
She wrote about the truck that pulled up to the crematorium window. A few Germans went inside, and then the window opened and they began throwing out naked bodies, Soviet prisoners of war catching them by the arms and legs and tossing them onto the truck. She walked right past it on her way to get bread. “There was so much blood in fact that it was dripping from gaps in the truck's cargo section and forming pools underneath the vehicle,” she wrote. “The stench was so overwhelming we had to hold our breaths. What particularly etched itself into my memory was the face of a Jewish man whose mouth was wide open as if in his last moments he had been gasping for breath (maybe they really are gassing them).” She felt nothing in the bread line, and nothing on the walk back. Then, in the drying room of the laundry, she sat down dizzy and sick. She could not vomit. She burst into tears and did not care who saw. Krysia tried to comfort her, but Mrs. Wisia waved her off. “Let her cry, she'll feel better,” she said, and sat down beside her and said nothing. When it was over she said: “And now, little quintuplet, chin up.” That night Jadwiga could not sleep. The face came back in her dreams.
She was released on 17 May 1943. The women who were staying behind sang them off with tears in their eyes. Some had been in prison for a year, some for two. “Oh God, they are crying, they are not coming with us, why can't they come with us? All of them deserve their Freedom,” she wrote. Then a Gestapo officer read out eighty-seven names. Hers was the second. He stopped at K, and none of the other quintuplets was called.
Before they let her go, the Gestapo told the prisoners to hand over any notes. She kept the notebook under the lining of her jacket and waited to be searched. The search never came.
From the road she looked back at the camp. The thousands of people in it were no longer people, “just numbered stripes.” She wrote: “I suddenly feel that I will never be completely free of it, a part of me has stayed back there, at Majdanek.” On the train home the wheels said it for her: “to home, to home.”
In Warsaw she worked as a waitress and joined the Grey Ranks, the underground of the Polish scouts, as a liaison. On 30 January 1944 the Germans shot her dead in a Warsaw back street. The circumstances have never been explained. She was seventeen. Her father, who was hiding under a false name, came to the funeral anyway. The family buried her at Bródno and went home without her. She had been free for eight months.
Her father fought in the Warsaw Uprising with the Home Army. On 1 September 1944 the Germans captured him and sent him to Auschwitz, then to Flossenbürg. He died at its subcamp in Leitmeritz on 20 December 1944. The war took the father and the daughter, and left the mother and the sister the notebook. Her mother kept it, and after her, Maria Halina. In 1998 Maria Halina and her husband, Leonard Suchan, gave the museum a typed copy, and later the forty-seven pages themselves. Many prisoners at Majdanek wrote notes. As far as the State Museum at Majdanek knows, hers is the only original diary kept inside the camp to survive. The last entry, describing her release, was probably finished at home, in Warsaw. The hand never once shook.
She was born on 11 September 1926. For her hundredth year, from 23 to 25 September 2026, the museum is opening an exhibition at her old school, meeting her family, and laying flowers on her grave. She was given no such recognition while she lived. She has it now.
Jadwiga saw a lot. We will probably never know everything she saw. Not even the museum will. The work is not finished.
Her diary is published by the State Museum at Majdanek in Polish as Majdanek. 15 I–17 V 43 r. Dziennik (2020), with English and German editions in 2021. Quotations here are from the English edition, Majdanek January 15 – May 17, 1943: Diary, edited by Jolanta Laskowska and translated by Witold Wojtaszko. Read more at the museum.
Provenance · Integrity Record
Canonical text · SHA‑512
Hash of the canonical text source (kept local; the manifest is public). Verify with sha512sum -c SHA512SUMS-html; the Bitcoin attestation, once confirmed, is in the .ots proof.
On preemptive, timed-sliced UNIX or Linux operating systems such as Solaris, AIX, Linux, BSD, and OS X, program code from one process executes on the processor for a time slice or quantum. After this time has elapsed, program code from another process executes for a time quantum. Linux divides CPU time into epochs, and each process has a specified time quantum within an epoch. The execution quantum is so small that the interleaved execution of independent, schedulable entities – often performing unrelated tasks – gives the appearance of multiple software applications running in parallel.
When the currently executing process relinquishes the processor, either voluntarily or involuntarily, another process can execute its program code. This event is known as a context switch, which facilitates interleaved execution. Time-sliced, interleaved execution of program code within an address space is known as concurrency.
The Linux kernel is fully preemptive, which means that it can force a context switch for a higher priority process. When a context switch occurs, the state of a process is saved to its process control block, and another process resumes execution on the processor.
A UNIX process is considered heavyweight because it has its own address space, file descriptors, register state, and program counter. In Linux, this information is stored in the task_struct. However, when a process context switch occurs, this information must be saved, which is a computationally expensive operation.
Concurrency applies to both threads and processes. A thread is an independent sequence of execution within a UNIX process, and it is also considered a schedulable entity. Both threads and processes are scheduled for execution on a processor core, but thread context switching is lighter in weight than process context switching.
In UNIX, processes often have multiple threads of execution that share the process's memory space. When multiple threads of execution are running inside a process, they typically perform related tasks. The Linux user-space APIs for process and thread management abstract many details. However, the concurrency level can be adjusted to influence the time quantum so that the system throughput is affected by shorter and longer durations of schedulable entity execution time.
While threads are typically lighter weight than processes, there have been different implementations across UNIX and Linux operating systems over the years. The three models that typically define the implementations across preemptive, time-sliced, multi-user UNIX and Linux operating systems are defined as follows - 1:1, 1:N, and M:N where 1:1 refers to the mapping of one user-space thread to one kernel thread, 1:N refers to the mapping of multiple user-space threads to a single kernel thread. M:N refers to the mapping of N user-space threads to M kernel threads.
In the 1:1 model, one user-space thread is mapped to one kernel thread. This allows for true parallelism, as each thread can run on a separate processor core. However, creating and managing a large number of kernel threads can be expensive.
In the 1:N model, multiple user-space threads are mapped to a single kernel thread. This is more lightweight, as there are fewer kernel threads to create and manage. However, it does not allow for true parallelism, as only one thread can execute on a processor core at a time.
In the M:N model, N user-space threads are mapped to M kernel threads. This provides a balance between the 1:1 and 1:N models, as it allows for both true parallelism and lightweight thread creation and management. However, it can be complex to implement and can lead to issues with load balancing and resource allocation.
Parallelism on a time-sliced, preemptive operating system means the simultaneous execution of multiple schedulable entities over a time quantum. Both processes and threads can execute in parallel across multiple cores or processors. Concurrency and parallelism are at play on a multi-user system with preemptive time-slicing and multiple processor cores. Affinity scheduling refers to scheduling processes and threads across multiple cores so that their concurrent and parallel execution is close to optimal.
It's worth noting that affinity scheduling refers to the practice of assigning processes or threads to specific processors or cores to optimize their execution and minimize unnecessary context switching. This can improve overall system performance by reducing cache misses and increasing cache hits, among other benefits. In contrast, non-affinity scheduling allows processes and threads to be executed on any available processor or core, which can result in more frequent context switching and lower performance.
Software applications are often designed to solve computationally complex problems. If the algorithm to solve a computationally complex problem can be parallelized, then multiple threads or processes can all run at the same time across multiple cores. Each process or thread executes by itself and does not contend for resources with other threads or processes working on the other parts of the problem to be solved. When each thread or process reaches the point where it can no longer contribute any more work to the solution of the problem, it waits at the barrier if a barrier has been implemented in software. When all threads or processes reach the barrier, their work output is synchronized and often aggregated by the primary process. Complex test frameworks often implement the barrier synchronization problem when certain types of tests can be run in parallel. Most individual software applications running on preemptive, time-sliced, multi-user Linux and UNIX operating systems are not designed with heavy, parallel thread or parallel, multiprocess execution in mind.
Minimizing lock granularity increases concurrency, throughput, and execution efficiency when designing multithreaded and multiprocess software programs. Multithreaded and multiprocess programs that do not correctly utilize synchronization primitives often require countless hours of debugging. The use of semaphores, mutex locks, and other synchronization primitives should be minimized to the maximum extent possible in computer programs that share resources between multiple threads or processes. Proper program design allows schedulable entities to run parallel or concurrently with high throughput and minimum resource contention. This is optimal for solving computationally complex problems on preemptive, time-sliced, multi-user operating systems without requiring hard, real-time scheduling.
The DE1-SoC from Terasic is an excellent board for hardware design and prototyping. The following VHDL process is from a hardware design created for the Terasic DE1-SoC FPGA. The ten switches and four buttons on the FPGA are used as an n-bit counter with an adjustable multiplier to increase the output frequency of one or more output pins at a 50% duty cycle.
As the switches are moved or the buttons are pressed, the seven-segment display is updated to reflect the numeric output frequency, and the output pin(s) are driven at the desired frequency. The onboard clock runs at 50MHz, and the signal on the output pins is set on the rising edge of the clock input signal (positive edge-triggered). At 50MHz, the output pins can be toggled at a maximum rate of 50 million cycles per second or 25 million rising edges of the clock per second. An LED attached to one of the output pins would blink 25 million times per second, not recognizable to the human eye. The persistence of vision, which is the time the human eye retains an image after it disappears from view, is approximately 1/16th of a second. Therefore, an LED blinking at 25 million times per second would appear as a continuous light to the human eye.
scaler <= compute_prescaler((to_integer(unsigned( SW )))*scaler_mlt); gpiopulse_process : process(CLOCK_50, KEY(0)) begin if (KEY(0) = '0') then -- async reset count <= 0; elsif rising_edge(CLOCK_50) then if (count = scaler - 1) then state <= not state; count <= 0; elsif (count = clk50divider) then -- auto reset count <= 0; else count <= count + 1; end if; end if; end process gpiopulse_process;
The scaler signal is calculated using the compute_prescaler function, which takes the value of a switch (SW) as an input, multiplies it with a multiplier (scaler_mlt), and then converts it to an integer using to_integer. This scaler signal is used to control the frequency of the pulse signal generated on the output pin.
The gpiopulse_process process is triggered by a rising edge of the CLOCK_50 signal and a push-button (KEY(0)) press. It includes an asynchronous reset when KEY(0) is pressed.
The count signal is incremented on each rising edge of the CLOCK_50 signal until it reaches the value of scaler - 1. When this happens, the state signal is inverted and count is reset to 0. If count reaches the value of clk50divider, it is also reset to 0.
Overall, this code generates a pulse signal with a frequency controlled by the value of a switch and a multiplier, which is generated on a specific output pin of the FPGA board. The pulse signal is toggled between two states at a frequency determined by the scaler signal.
It is important to note that concurrent statements within an architecture are executed concurrently, meaning that they are evaluated concurrently and in no particular order. However, the sequential statements within a process are executed sequentially, meaning that they are evaluated in order, one at a time. Processes themselves are executed concurrently with other processes, and each process has its own execution context.
The 96boards CE specification calls for an optional JTAG connection. The specification also indicates that the optional JTAG connection shall use a 10 pin through hole, .05" (1.27mm) pitch JTAG connector. The part is readily available on most electronics sites. Breaking out the pins with long wires and shrink wrapping them is ideal for making sure that each connection is labeled and separate when connecting to a JTAG debugger. While a JTAG connection is not required for flashing or loading the bootloaders onto the board, the JTAG connection is useful for advanced chip-level debugging. The serial UART connection is sufficient for loading release or debug versions of bl0, bl1, bl2, bl31, bl32, the kernel, and userspace. Last but not least, ARM-powered boards, with 12V power input, often require external fans to keep the board cool. As seen in the below photos, two 5V fans were powered from an external power supply. Any work on microcontroller boards should be performed on a grounded surface. Proper grounding procedures should always be followed as most microcontroller boards contain ESD sensitive components.
In the below photos, a 96Boards SBC is mounted on an IP65, ABS plastic junction box for durability. The pins are extended and mounted with screws underneath the junction box. The electrical conduit holes on the side of the junction box are ideal for holding small, project fans. The remaining electrical conduit holes provide a clean place to place the remaining wires from the board - micro USB, USB-C, and 12V power.
The Kirin 960 SoC and on-board USB 3.0 make the HiKey 960 SBC an ideal platform for running a Linux Bridged firewall. The number of single-board computers with an SoC as powerful as the HiSilicon Kirin 960 is limited.
When compared with the Raspberry Pi series of single board computers (SBC), the HiKey 960 SBC is significantly more powerful. The Kirin 960 also stands above the ARM powered SoCs which reside in most commercial routers.
USB 3.0 makes the HiKey 960 board an attractive option for bridging or routing, filtering network traffic, or connecting to an external gateway via IPSec. Both network traffic filtering and IPSec tunneling can be computationally expensive operations. However, the multicore Kirin 960 is well suited for these types of tasks.
In order to be able to run an IPSec client tunnel and a Linux Bridged firewall connected over 1G ethernet links, certain kernel configuration modifications are needed. Furthermore, the Android Linux kernel for the HiKey 960 board does not boot on a standard Linux root filesystem because it is designed to boot an Android customized rootfs.
The latest googlesource Linux kernel (hikey-linaro-4.9) for Android (designed to boot Android on the HiKey 960 board) has been customized to remove the Android specific components so that the kernel boots on a standard Linux root filesystem, with the proper drivers enabled for network connectivity via attached 1000Mb/s USB 3.0 to ethernet adapters. The standard UART interface on the board should be used for serial connectivity and shell access. WiFi and Bluetooth have been removed from the kernel configuration. The kernel should be booted off of a microSDHC UHS-I card. The 96boards instructions should be followed for configuring the HiKey 960 board, setting the jumpers on the board, building and flashing the l-loader, firmware package, partition tables, UEFI loader, ARM Trusted Firmware, and optional Op-TEE. Links for the normal Linux kernel configuration, multi-interface bridge configuration, and single interface IPSec configuration are below. Additional kernel config modifications may be needed for certain types of applications.
kernel build instructions
mkdir /usr/local/toolchains
cd /usr/local/toolchains/
TC=gcc-linaro-7.2.1-2017.11-x86_64_aarch64-linux-gnu
wget https://releases.linaro.org/components/toolchain/binaries/latest/aarch64-linux-gnu/$TC.tar.xz
tar -xJf $TC.tar.xz
export ARCH=arm64
export CROSS_COMPILE=/usr/local/toolchains/$TC/bin/aarch64-linux-gnu-
export PATH=/usr/local/toolchains/$TC/gcc-aarch64-linux-gnu/bin:$PATH
cd /usr/local/src
git clone https://android.googlesource.com/kernel/hikey-linaro
cd hikey-linaro
git checkout -b android-hikey-linaro-4.9
make hikey960_defconfig
make -j8
multi-interface bridge configuration
Bridged configuration, no ip addresses on dual nic interfaces. (crossover cable is useful for testing). Bridge interface obtains dhcp address (/11) from wlan router. Aliased interface added to br0 and assigned private subnet ip on different subnet (/8). Spanning tree set on bridge interface. Basic ebtables and iptables ruleset below.
brctl addbr <br>
brctl addif <br> <eth1> <eth2>
ifconfig <br> up
ifconfig <eth1> up
ifconfig <eth2> up
brctl stp <br> yes
dhclient <br>
ifconfig <br>:0 <a.b.c.d/sn> up
iptables --table nat --append POSTROUTING --out-interface <br> -j MASQUERADE
iptables -P INPUT DROP
iptables --append FORWARD --in-interface <br>:0 -j ACCEPT
ebtables -P FORWARD DROP
ebtables -P INPUT DROP
ebtables -P OUTPUT DROP
ebtables -t filter -A FORWARD -p IPv4 -j ACCEPT
ebtables -t filter -A INPUT -p IPv4 -j ACCEPT
ebtables -t filter -A OUTPUT -p IPv4 -j ACCEPT
ebtables -t filter -A INPUT -p ARP -j ACCEPT
ebtables -t filter -A OUTPUT -p ARP -j ACCEPT
ebtables -t filter -A FORWARD -p ARP -j REJECT
ebtables -t filter -A FORWARD -p IPv6 -j DROP
ebtables -t filter -A FORWARD -d Multicast -j DROP
ebtables -t filter -A FORWARD -p X25 -j DROP
ebtables -t filter -A FORWARD -p FR_ARP -j DROP
ebtables -t filter -A FORWARD -p BPQ -j DROP
ebtables -t filter -A FORWARD -p DEC -j DROP
ebtables -t filter -A FORWARD -p DNA_DL -j DROP
ebtables -t filter -A FORWARD -p DNA_RC -j DROP
ebtables -t filter -A FORWARD -p LAT -j DROP
ebtables -t filter -A FORWARD -p DIAG -j DROP
ebtables -t filter -A FORWARD -p CUST -j DROP
ebtables -t filter -A FORWARD -p SCA -j DROP
ebtables -t filter -A FORWARD -p TEB -j DROP
ebtables -t filter -A FORWARD -p RAW_FR -j DROP
ebtables -t filter -A FORWARD -p AARP -j DROP
ebtables -t filter -A FORWARD -p ATALK -j DROP
ebtables -t filter -A FORWARD -p 802_1Q -j DROP
ebtables -t filter -A FORWARD -p IPX -j DROP
ebtables -t filter -A FORWARD -p NetBEUI -j DROP
ebtables -t filter -A FORWARD -p PPP -j DROP
ebtables -t filter -A FORWARD -p ATMMPOA -j DROP
ebtables -t filter -A FORWARD -p PPP_DISC -j DROP
ebtables -t filter -A FORWARD -p PPP_SES -j DROP
ebtables -t filter -A FORWARD -p ATMFATE -j DROP
ebtables -t filter -A FORWARD -p LOOP -j DROP
ebtables -t filter -A FORWARD --log-level info --log-ip --log-prefix FFWLOG
ebtables -t filter -A OUTPUT --log-level info --log-ip --log-arp --log-prefix OFWLOG -j DROP
ebtables -t filter -A INPUT --log-level info --log-ip --log-prefix IFWLOG
single-interface ipsec gateway configuration
iptables -t nat -A POSTROUTING -s <clientip>/32 -o <eth> -j SNAT --to-source <virtualip>
iptables -t nat -A POSTROUTING -s <clientip>/32 -o <eth> -m policy --dir out --pol ipsec -j ACCEPT