I don't think the Chinese had presses like Gutenberg invented. Type was set in a frame, inked, and the paper pressed over the inked type manually. Gutenberg's great innovation was coupling the screw press, already in use for pressing olives and grapes for oil and juice, with movable metal type. The Chinese didn't put the two together.
Screw presses were also used in binding codexes and that’s more likely the model for what Gutenberg used for his printing press.
What I find interesting is the speculation that Gutenberg didn’t quite have type like what spread through Europe after he made his Bible, but it was something more akin to using punches to make plates. Now if I could only remember where I read this thirty years ago…
It's fast. Two skilled pressmen working together could do 200 to 250 impressions per hour or about one every 15 seconds (which might be 4, 8, 16 pages on each impression depending on page size). That was the speed text was put to paper from Gutenberg all the way until steam presses arrive at the start of the 19th century. The screw press also applies an even uniform pressure across the whole page; that's hard to do manually and impossible to do in 15 seconds. Screw-press you can do drunk, and many printers did. (Just read Ben Franklin's account of how much his fellow printshop workers drank: [0]) Source for all this: I studied early modern history and especially history of the book.
Movable type is an amazing invention, without which the whole history of the world would look utterly different. Everyone who has the slightest interest should try setting some movable type if you can find a printshop in your city offering classes (I did; it's fun). It's harder than you might think and you learn why skilled compositors and printers were quite well-paid by the standards of early-modern craftspeople. But you also see the enormous efficiency gains because once that type is set up, the marginal cost of producing each copy is low.
[0] https://blog.lostartpress.com/2013/06/18/strong-beer-that-he... : "My companion at the press drank every day a pint before breakfast, a pint at breakfast with his bread and cheese, a pint between breakfast and dinner, a pint at dinner; a pint in the afternoon about six o’clock, and another when he had done his day’s work. I thought it a detestable custom; but it was necessary, he supposed, to drink strong beer, that he might be strong to labour."
Mark Kurlinsky's "Paper" covers the early history of printing presses in Europe in great detail. Printers and their presses followed, or instigated, the local paper making industry. There is less focus on the evolution of moveable type there, but I'm also reading "Thinking With Type" by Ellen Lupton which hits the highlights in the history of typeface design.
Maybe AI should be the teacher, not the student. That is, used to tutor and educate, not to supply students with neatly packaged answers, but to challenge them to learn and judge when they have grasped a topic and move on to the next.
You know, a personal teaching assistant. Who wouldn't do better with one of those?
Have it read and compare the code with what it knows about open source. Many AI engines can also google that and give a comprehensive list of similarities.
Reduces the list of things to check by maybe orders of magnitude and months to days.
Used to be a staff member working on an x86 OS called CTOS. I realized if I implemented a couple of traps, we could run command-line DOS programs. So I did. And it worked. Dev tools, text processing, piped commands all worked.
It helped that the DOS executable format was the same as the CTOS format - because we had traded Bill Gates our linker (which produces executables) for his BASIC compiler.
Thanks for sharing, never heard about it before. What was kernel programming back then? Briefly checked the wikipedia and looks like CTOS was kinda big in the government space back in the 80s.
It was popular with govt because it came with an HDLC network build-in, server/client depended on the OS you booted. This saved you a network administrator.
The kernel was in Intel ASM86 but the rest of the OS was written in PLM86. When I joined it was 2MB of code on a 128K 8086 cpu. By the time I left it was 9MB of code running on an 80386.
If you wanted to get into development mode in CTOS, the keyword was 'developement' - an e between the p and the m. Worked on this system back in early 1990 as a developer.
Why/when are traps used rather than explicit system calls? Is it just historical coevolution? Or is the idea that the user mode program doesn’t need to know that it’s unprivileged? Or is it just repurposing the error handler path to perform privileged operations?
Most processors support both "interrupts" (an external peripheral is banging on the CPU's interrupt pins... but also invocable from software; software interrupts; SWIs; INT instruction on x86) and "exceptions" (e.g. divide by zero, bus error, illegal instruction). Depending on the processor, accessing the "privileged" mode can be done either by software interrupts, exceptions, or both. An operating system should pick one and stick with it.
Other uses for interrupt/exception/trap vectors include hardware breakpoints: don't try and single-step the CPU, overwrite the code with an illegal instruction and control will flow to the illegal instruction handler where you can see all the registers then execute the real instruction that was meant to be there and return to where you left off. Some CPUs have a formal "BKPT" type instruction for that.
One other use on the 68000 is that any unrecognised instruction that started $Fxxx triggered the F-line handler; all the floating point instructions were in the form $Fxxx, so if you didn't have an FPU, you could put a software emulator for the FPU instructions in the F-line handler and software wouldn't know the difference. Traps/exceptions don't have to be a jump from unprivileged to privileged, they can just be utilitarian.
> Depending on the processor, accessing the "privileged" mode can be done either by software interrupts, exceptions, or both. An operating system should pick one and stick with it.
Practically most will support access via both, but for different reasons. For example, page faults (which the software cannot possibly predict) are going to be exception-mediated, but syscalls (which the software asks for) are triggered via an interrupt.
At the time of DOS, x86 didn't have multiple privileges. The system call instruction was typically INT, the software interrupt instruction.
Later on the 386 Intel added virtual 8086 mode which trapped to the kernel privileged instruction exception also for certain instructions that had to be virtualized, among them INT.
We used a set of INT instructions in well-known low memory addresses that all jumped to the same place. We had an ASM file that you linked with, that had sixteen different address combinations for each.
The common entry point would look back on the stack and calculate from the return address which entry point had been called, and run the appropriate kernel call. We called it the CS:IP hack.
In the context of this post, the DOS INT10 and INTx(I forget) required the caller to load registers with the desired system call number, then perform the trap instruction in their code. Fortunately CTOS didn't need those particular software interrupts, so I could implement them for my purposes.
Windows 95 used a related hack. Whenever a v8086 program asked to create a call to protected mode code ("please give me a real mode address to call to, in order to start executing the protected mode routine at address 0x123456"), Windows would store the entry point in a table and hand out real mode addresses like FFD0:0, FFCF:10, FFCE:20, FFCD:30, FFCC:40 that all point to the same instruction (because the segment part is shifted left by 4 in real or v8086 modes).
The routine at 0xFFD00 could then enter protected mode and use the code segment to build the index into a table of entry points: FFD0 goes to index 0, FFCF goes to index 1, and so on. But for extra kicks, the address isn't actually pointing to valid code. It points to a random "c" character in the BIOS, which is an ARPL instruction - which in turn is invalid in v8086 mode and therefore invokes the undefined opcode exception handler. The exception handler, which handily enough is already running in protected mode, then takes care of doing the 32-bit call.
> It so happens that on the 80386 chip of that era, the fastest way to get from V86-mode into kernel mode was to execute an invalid instruction! Consequently, Windows/386 used an invalid instruction as its syscall trap.
I also read this part but I wonder how did they benchmark back then?
> Schulman’s Unauthorized Windows 95 describes a particularly unhinged one: in the hypervisor of Windows/386 (and subsequently 386 Enhanced Mode in Windows 3.0 and 3.1, as well as the only available mode in 3.11, 95, 98, and Me), a driver could dynamically register upcalls for real-mode guests (within reason), all without either exerting control over the guest’s memory map or forcing the guest to do anything except a simple CALL to access it. The secret was that all the far addresses returned by the registration API referred to the exact same byte in memory, a protected-mode-only instruction whose attempted execution would trap into the hypervisor, and the trap handler would determine which upcall was meant by which of the redundant encodings was used.
And if that’s not unhinged enough for you: the boot code tried to locate the chosen instruction inside the firmware ROM, because that will have to be mapped into the guest memory map anyway. It did have a fallback if that did not work out, but it usually succeeded. This time, the secret (the knowledge of which will not make you happier, this is your final warning) is that the instruction chosen was ARPL, and the encoding of ARPL r/m16, AX starts with 63 hex, also known as the ASCII code of the lowercase letter C. The absolute madmen put the upcall entry point inside the BIOS copyright string.
(Incidentally, the ARPL instruction, “adjust requested privilege level”, is very specific to the 286’s weird don’t-call-it-capability-based segmented architecture... But it’s has a certain cunning to it, like CPU-enforced __user tagging of unprivileged addresses at runtime.)
Ahhh.. probably my first program. Don't forget the int 20 at the end! It was beeping great. Still never unlocked the mysteries of those TSR programs though.
It's been a long time since I've touched any of this, so the details have slipped my mind. However, the general idea was that there were two different exit calls in DOS: terminate and terminate and stay resident. The difference between the two is that the stay resident option wouldn't release the memory used by your application. Further, the interrupt table, which told the processor how to handle each interrupt, was in RAM and therefore writable.
So, what TSRs would do is overwrite one or more interrupts to point to a routine that would check if the system call in question was one it wanted to handle (eg, to add a hotkey it would grab the keyboard handler and check for a special set of keys before passing control back to the normal handler). Once that was fine, it would call the TSR system call and control would be passed back to the OS with the hook still in place
Still never unlocked the mysteries of those TSR programs though.
I made a bunch of those, in TurboPascal. Just needed to save registers (including stack and heap segments) and hook some key combination. One of them was used commercially for installations by a very big company.
Testing was a little prone to spectacular failures. But once the general procedure was debugged, it was easy as pie.
I don't know OG x86 (cuz, ewww) but on 68k this was generally the way. On my Atari ST a syscall was performed by filling your registers and stack as expected, then executing one of the TRAP opcodes and that would get the CPU To save PC etc & jump to the handler but in supervisor mode, where your syscall could then read state perform accordingly, and then return back to you.
I think x86_64 has just formalized this into a specific SYSCALL instruction?
ARM variants call it SVC (supervisor call).
Same difference.
Some older operating systems just implemented their syscalls as ordinary subroutine jumps, though, and everything ran in supervisor etc. I believe AmigaOS was like this, you just went through a jump table. Which, I think, shaves some cycles but also means compromises in terms of building for memory protection, etc.
Depends on the processor architecture and its nomenclature.
Traps typically also result from exceptional conditions (like divide by zero or page fault).
An architecture may or may not provide non-trap paths for less-privileged code to invoke more-privileged subsystems (call gates, "syscall" instructions, etc.).
Traps typically need some way to preserve all userspace-accessible registers (otherwise resuming from a page fault is .. hard). Dedicated syscall instructions may only need to restore a subset of registers.
In some implementations, processors may discover that an instruction must trap after it starts irreversibly changing architecturally-visibile state; in cases like that, the processor needs to leave enough breadcrumbs for the OS to allow either a clean unwind or a resumption of the interrupted instruction. My understanding is that the original 68000 somewhat famously got this wrong.
if you know a particular process or system callmakes errors,then you run code that checks for that error,or exception,or preempively hooks a problematic system call,to redirect to "your"code that handles the state of exception,and returns.
The F-14 Tomcat had an early period microprocessor and landing on an aircraft carrier would have the tailhook snag arresting wires in a trap. But the trap idea precedes the Tomcat by a decade in computing according to the AI.
hello! hello! I was mainly admin and COBOL dev with them (I wish I kept the collection of the manuals and PRGs, alas when no space..), bitsavers have a quite collection (incl a virtualbox HDD) if you are interested!
Again, the insistence with cherry-picking results. Shame.
Conclusions: Common vaccines were not associated with a decreased risk of dementia. Unmeasured confounding and detection bias likely accounted for the observed increased risk.
"Results: Common vaccines were associated with an increased risk of dementia (OR, 1.38 [95% CI, 1.36-1.40]), compared with no exposure."
It's not even a long scroll to get to the results
Conclusions: Common vaccines were not associated with a decreased risk of dementia. Unmeasured confounding and detection bias likely accounted for the observed increased risk.
reply