<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
	<title>nwb.sh  </title>
	<link href="https://nwb.sh/atom.xml" rel="self" />
	<updated>2023-03-10T18:42:05Z</updated>
	<author>
		<name>Nathan Barnett</name>
	</author>
	<id>https://nwb.sh,2023-01-04:default-atom-feed/</id>
	<entry>
		<title>Hello World Boot Sector</title>
		<content type="html">&lt;h1&gt;Hello World Boot Sector&lt;/h1&gt;
&lt;p&gt;2023-03-08&lt;/p&gt;
&lt;p&gt;I wanted to adventure into learning some x86 16-bit real mode assembly for the&lt;br /&gt;
original IBM PC BIOS. This means even PCs with CSM still can boot this!&lt;br /&gt;
&lt;br /&gt;
I used this &lt;a href=&quot;https://stanislavs.org/helppc/int_table.html&quot;&gt;site&lt;/a&gt; for referencing
IBM BIOS routines.  &lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;16-bit x86 assembly  &lt;/h2&gt;
&lt;p&gt;I save my assembly in hello.asm&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-asm&quot;&gt;bits 16				; Tell nasm we&#39;re doing 16-bit mode
org 7C00h			; The BIOS loads the boot sector to this address then jumps

start:
	mov ah, 0x0		; set video mode
	mov al, 0x7		; 80x25 monochrome text (supports even MDA!)
	int 10h			; BIOS interrupt video routine

	mov ah, 0x2		; move cursor
	mov dx, 0x0		; set cursor to top-left corner
	int 10h

init_video:
	mov ah, 0xE		; TTY text printing
	mov si, msg		; put our message in the stack index

loop:
	lodsb			; will load msg into al and increment si for us
	or al, al		; if al is null 0, we&#39;ve reached the end, so halt CPU
	jz halt
	int 10h
	jmp loop

halt:
	hlt


msg: db &amp;quot;Hello, world!&amp;quot;, 0

times 510-($-$$) db 0	; fill up to 510 bytes
dw 0xAA55				; special boot sector signature
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Assemble and Test  &lt;/h2&gt;
&lt;p&gt;I assemble with nasm:&lt;br /&gt;
&lt;code&gt;nasm -f bin -o hello.bin hello.asm&lt;/code&gt;&lt;br /&gt;
Then I can test it in QEMU with SeaBIOS:&lt;br /&gt;
&lt;code&gt;qemu-system-i386 -drive format=raw,file=hello.bin&lt;/code&gt;  &lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/public/qemu_helloworld.png&quot; alt=&quot;QEMU displaying Hello, world!&quot; /&gt;&lt;/p&gt;</content>
		<link href="https://nwb.sh/ibm_pc_boot"/>
		<id>https://nwb.sh/ibm_pc_boot</id>
		<updated>2023-03-08T00:00:00Z</updated>
		<published>2023-03-08T00:00:00Z</published>
	</entry>
	<entry>
		<title>Generating 20,000 primes on the Apple M1</title>
		<content type="html">&lt;h1&gt;Generating 20,000 primes on the Apple M1&lt;/h1&gt;
&lt;p&gt;2023-03-10&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;versus an i7-10700k, a Pentium G4400, and a Raspberry Pi 4!&lt;/strong&gt;&lt;br /&gt;
&lt;br /&gt;
Sometime last year, I wanted to see if I could write a C program to produce primes&lt;br /&gt;
in order by just brute force division: i.e., literally checking factors of each&lt;br /&gt;
iteration.&lt;br /&gt;
&lt;br /&gt;
I&#39;m still learning C and computer science in general, so excuse any rookie mistakes.&lt;br /&gt;
&lt;br /&gt;
That said, one thing of note is how fast the Apple M1 (on my 2020 MacBook Air)&lt;br /&gt;
can generate these primes.  &lt;/p&gt;
&lt;p&gt;The program in question can be found on GitHub &lt;a href=&quot;https://github.com/nwb99/simpleprime&quot;&gt;here&lt;/a&gt;.&lt;br /&gt;
&lt;br /&gt;
I used clang with various optimization options rather than gcc to have parity between  macOS and Linux (and it was faster than gcc anyway for whatever reason).
&lt;br /&gt;
Anyway, if you want to try this yourself, you can totally run it multiple times,&lt;br /&gt;
and it&#39;ll append the results for each round in results.txt.&lt;br /&gt;
&lt;code&gt;for i in {1..5}; do ./test.sh; done&lt;/code&gt;&lt;br /&gt;
If you want to do five rounds for example to see if you get similar results.&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;Time test on a 2020 M1 MacBook Air&lt;/h2&gt;
&lt;p&gt;&lt;img src=&quot;/public/simpleprime/m1.png&quot; alt=&quot;times to generate 20,000 primes on Apple M1&quot; /&gt;&lt;br /&gt;
&lt;br /&gt;
1.4-ish seconds is ridiculously impressive!&lt;br /&gt;
It&#39;s a little slower printing to stdout.&lt;br /&gt;
&lt;br /&gt;
&lt;video width=&quot;621&quot; height=&quot;442&quot; controls&gt;
    &lt;source src=&quot;/public/simpleprime/m1_prime.mp4&quot; type=&quot;video/mp4&quot;&gt;
Your browser does not support the video tag.
&lt;/video&gt;&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;Time test on my i7-10700k desktop&lt;/h2&gt;
&lt;p&gt;&lt;img src=&quot;/public/simpleprime/10700k.png&quot; alt=&quot;times to generate 20,000 primes on an i7-10700k&quot; /&gt;&lt;br /&gt;
&lt;br /&gt;
This was technically done in WSL2 (in Debian), but it is surprising that a laptop&lt;br /&gt;
with no fan outpaces this thing in single core performance, at least for this task.  &lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;Time test on a Dell 5040 with a Pentium G4400&lt;/h2&gt;
&lt;p&gt;&lt;br /&gt;
&lt;img src=&quot;/public/simpleprime/g4400.png&quot; alt=&quot;times to generate 20,000 primes on a Pentium G4400&quot; /&gt;&lt;br /&gt;
&lt;br /&gt;
No surprise that the 6th-generation Skylake Pentium will be the slower than the&lt;br /&gt;
previous two (especially the M1).  &lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;Time test on a Raspberry Pi 4 (2GB version)&lt;/h2&gt;
&lt;p&gt;&lt;br /&gt;
&lt;img src=&quot;/public/simpleprime/pi4.png&quot; alt=&quot;times to generate 20,000 primes on a Raspberry Pi 4&quot; /&gt;&lt;br /&gt;
&lt;br /&gt;
Of course the Pi is the slowest of all of them. However, it&#39;s still impressive!&lt;br /&gt;
&lt;/p&gt;</content>
		<link href="https://nwb.sh/generating_20000_primes_c"/>
		<id>https://nwb.sh/generating_20000_primes_c</id>
		<updated>2023-03-10T00:00:00Z</updated>
		<published>2023-03-10T00:00:00Z</published>
	</entry>
	<entry>
		<title>Exploiting LCD refresh with Arduino</title>
		<content type="html">&lt;h1&gt;Exploiting LCD refresh with Arduino&lt;/h1&gt;
&lt;p&gt;2023-03-08&lt;/p&gt;
&lt;p&gt;I had an interesting idea to get around the 8 custom character limit on these&lt;br /&gt;
cheap LCDs based on the HD44780 by rapidly redefining the character set&lt;br /&gt;
while refreshing the display (every 27ms) in between each set.&lt;br /&gt;
I wanted to use millis() and play &quot;At Doom&#39;s Gate&quot;, but I could never get it&lt;br /&gt;
to work correctly.&lt;br /&gt;
This was done with PlatformIO in VSCode.  &lt;/p&gt;
&lt;p&gt;&lt;video width=&quot;304&quot; height=&quot;540&quot; controls&gt;
  &lt;source src=&quot;/public/doom_arduino.mp4&quot; type=&quot;video/mp4&quot;&gt;
&lt;/video&gt;&lt;/p&gt;
&lt;h2&gt;Defining a character set&lt;/h2&gt;
&lt;p&gt;I created a separate &#39;DOOM.h&#39; to define my custom characters for the DOOM logo.&lt;br /&gt;
It&#39;s also available on &lt;a href=&quot;https://pastebin.com/K2D5nBvJ&quot;&gt;Pastebin&lt;/a&gt;.  &lt;/p&gt;
&lt;hr /&gt;
&lt;pre&gt;&lt;code class=&quot;language-Arduino&quot;&gt;/* LOGO */
byte top[8][8] = {
  // UL
  {
    B11111,
    B01111,
    B01111,
    B01110,
    B01110,
    B01110,
    B01110,
    B01110
  },
  // UR
  {
    B11100,
    B11110,
    B11111,
    B00111,
    B00111,
    B00111,
    B00111,
    B00111
  },
  // UL
  {
    B00001,
    B00011,
    B00111,
    B01110,
    B01110,
    B01110,
    B01110,
    B01111
  },
  // UR
  {
    B11000,
    B11100,
    B11110,
    B00111,
    B00111,
    B00111,
    B00111,
    B00111
  },
  // UL
  {
    B00011,
    B00111,
    B01111,
    B11100,
    B11100,
    B11100,
    B11100,
    B11100
  },
  // UR
  {
    B10000,
    B11000,
    B11100,
    B01110,
    B01110,
    B01110,
    B01110,
    B11110
  },
  // UL
  {
    B11000,
    B11000,
    B11100,
    B11100,
    B11110,
    B11111,
    B11111,
    B11111
  },
  // UR
  {
    B00000,
    B00111,
    B00111,
    B00111,
    B01111,
    B11111,
    B11111,
    B11111
  }

};

byte bottom[8][8] = {
    // LL
  {
    B01110,
    B01110,
    B01110,
    B01111,
    B01111,
    B01111,
    B01100,
    B01000
  },
  // LR
  {
    B00111,
    B01111,
    B11110,
    B11100,
    B11000,
    B10000,
    B00000,
    B00000
  },
  // LL
  {
    B01111,
    B01111,
    B00111,
    B00011,
    B00001,
    B00000,
    B00000,
    B00000
  },
  // LR
  {
    B00111,
    B10111,
    B11110,
    B11100,
    B11000,
    B10000,
    B00000,
    B00000
  },
  // LL
  {
    B11100,
    B11101,
    B01111,
    B00111,
    B00011,
    B00001,
    B00000,
    B00000
  },
  // LR
  {
    B11110,
    B11110,
    B11100,
    B11000,
    B10000,
    B00000,
    B00000,
    B00000
  },
   // LL
  {
    B11111,
    B11111,
    B11101,
    B11101,
    B01100,
    B00100,
    B00000,
    B00000
  },
  // LR
  {
    B11111,
    B11111,
    B10111,
    B10111,
    B00111,
    B00111,
    B00011,
    B00001
  }
};
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;  &lt;/p&gt;
&lt;h2&gt;Now the actual sketch  &lt;/h2&gt;
&lt;p&gt;And the main Arduino sketch: also on &lt;a href=&quot;https://pastebin.com/iafmZqgm&quot;&gt;Pastebin&lt;/a&gt;&lt;br /&gt;
This can be done with 4 lines instead of 8, but it may be better with 8.&lt;br /&gt;
It will still work nonetheless: tweaking the delays may help.  &lt;/p&gt;
&lt;hr /&gt;
&lt;pre&gt;&lt;code class=&quot;language-Arduino&quot;&gt;#include &amp;lt;Arduino.h&amp;gt;
#include &amp;lt;LiquidCrystal.h&amp;gt;
#include &amp;quot;DOOM.h&amp;quot;

#define LCD_RS    9
#define LCD_EN    8
#define LCD_D0   14 // A0
#define LCD_D1   15 // A1
#define LCD_D2    2
#define LCD_D3    3
#define LCD_D4    4
#define LCD_D5    5
#define LCD_D6    6
#define LCD_D7    7

#define LCD_W    16
#define LCD_H     2

#define EMPTY    &amp;quot;                &amp;quot;
#define STARTMSG &amp;quot;Hello, world!&amp;quot;

LiquidCrystal lcd(LCD_RS, LCD_EN, LCD_D0, LCD_D1, LCD_D2, LCD_D3, LCD_D4,
                  LCD_D5, LCD_D6, LCD_D7);

void drawDOOM_1();
void drawDOOM_2();

void setup() {
  lcd.begin(LCD_W, LCD_H);
  lcd.clear();
  lcd.setCursor(0, 0);
  lcd.print(STARTMSG);
  delay(1500);
  lcd.clear();
}

void loop() {
  drawDOOM_1();
  delay(27);
  drawDOOM_2();
  delay(27);
}

void drawDOOM_1() {
  lcd.setCursor(4, 1);
  lcd.print(&amp;quot;        &amp;quot;);
  lcd.createChar(0, bottom[0]);
  lcd.createChar(1, bottom[1]);
  lcd.createChar(2, bottom[2]);
  lcd.createChar(3, bottom[3]);
  lcd.createChar(4, bottom[4]);
  lcd.createChar(5, bottom[5]);
  lcd.createChar(6, bottom[6]);
  lcd.createChar(7, bottom[7]);

  lcd.setCursor(4, 1);
  lcd.write(byte(0));
  lcd.setCursor(5, 1);
  lcd.write(byte(1));
  lcd.setCursor(6, 1);
  lcd.write(byte(2));
  lcd.setCursor(7, 1);
  lcd.write(byte(3));
  lcd.setCursor(8, 1);
  lcd.write(byte(4));
  lcd.setCursor(9, 1);
  lcd.write(byte(5));
  lcd.setCursor(10, 1);
  lcd.write(byte(6));
  lcd.setCursor(11, 1);
  lcd.write(byte(7));
}

void drawDOOM_2() {
  lcd.setCursor(4, 0);
  lcd.print(&amp;quot;        &amp;quot;);
  lcd.createChar(0, top[0]);
  lcd.createChar(1, top[1]);
  lcd.createChar(2, top[2]);
  lcd.createChar(3, top[3]);
  lcd.createChar(4, top[4]);
  lcd.createChar(5, top[5]);
  lcd.createChar(6, top[6]);
  lcd.createChar(7, top[7]);

  lcd.setCursor(4, 0);
  lcd.write(byte(0));
  lcd.setCursor(5, 0);
  lcd.write(byte(1));
  lcd.setCursor(6, 0);
  lcd.write(byte(2));
  lcd.setCursor(7, 0);
  lcd.write(byte(3));
  lcd.setCursor(8, 0);
  lcd.write(byte(4));
  lcd.setCursor(9, 0);
  lcd.write(byte(5));
  lcd.setCursor(10, 0);
  lcd.write(byte(6));
  lcd.setCursor(11, 0);
  lcd.write(byte(7));
}
&lt;/code&gt;&lt;/pre&gt;</content>
		<link href="https://nwb.sh/exploiting_lcds"/>
		<id>https://nwb.sh/exploiting_lcds</id>
		<updated>2023-03-08T00:00:00Z</updated>
		<published>2023-03-08T00:00:00Z</published>
	</entry>
	<entry>
		<title>Arch Linux Btrfs with hibernation in a swapfile</title>
		<content type="html">&lt;h1&gt;Arch Linux Btrfs with hibernation in a swapfile&lt;/h1&gt;
&lt;p&gt;2023-03-09&lt;/p&gt;
&lt;p&gt;The Arch Wiki technically contains everything needed to make this work, but&lt;br /&gt;
it isn&#39;t the best organized and not obvious how it should be done. Here I&lt;br /&gt;
document the process I took to make it work on two different PCs.&lt;br /&gt;
&lt;br /&gt;
This post expects you to already know how to use the Linux command line.&lt;br /&gt;
&lt;br /&gt;
If you need to see the images larger, simply zoom the page, or right-click and&lt;br /&gt;
open the image in a new tab and zoom there.&lt;br /&gt;
&lt;br /&gt;
Feel free to skip around as needed.  &lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;Preparing for Installation&lt;/h2&gt;
&lt;p&gt;Head over to archlinux.org and get an ISO of Arch and write it to a USB or DVD,&lt;br /&gt;
if that&#39;s your style (it&#39;s too big for CD nowadays!). A tool like balenaEtcher&lt;br /&gt;
is user friendly, and I use it often. Of course &lt;code&gt;dd&lt;/code&gt; works well, too, but it is&lt;br /&gt;
much easier to screw up and overwrite your data using it if done carelessly.&lt;br /&gt;
I suppose one could use &lt;code&gt;cat&lt;/code&gt; as well, with a redirect:&lt;br /&gt;
&lt;code&gt;cat arch.iso &amp;gt; /dev/sdX&lt;/code&gt;, where X is the appropriate drive. Still, &lt;code&gt;cat&lt;/code&gt; is&lt;br /&gt;
dangerous like &lt;code&gt;dd&lt;/code&gt;.  &lt;/p&gt;
&lt;p&gt;Get it booted up, be it UEFI or BIOS mode, and check to make sure the network&lt;br /&gt;
works. It&#39;s possible to do it with WiFi, but I prefer wired for setup.&lt;br /&gt;
&lt;br /&gt;
&lt;strong&gt;Run &lt;code&gt;# ip a&lt;/code&gt; and ensure you have an appropriate IP address and ping google.com&lt;br /&gt;
or some other known, good address.&lt;/strong&gt;&lt;br /&gt;
&lt;img src=&quot;/public/kde-btrfs-swapfile/1-netcheck.png&quot; alt=&quot;Checking network connection before installing&quot; /&gt;&lt;br /&gt;
&lt;br /&gt;
Now, if the connection is working, the process can continue.&lt;br /&gt;
&lt;strong&gt;Run &lt;code&gt;# lsblk&lt;/code&gt; and obtain the correct drive path.&lt;/strong&gt;&lt;br /&gt;
In my case, it&#39;s &lt;code&gt;/dev/vda&lt;/code&gt; but on a real machine, it&#39;s like &lt;code&gt;/dev/sda&lt;/code&gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;img src=&quot;/public/kde-btrfs-swapfile/2-lsblk.png&quot; alt=&quot;A prompt with the output of lsblk&quot; /&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;strong&gt;Either fdisk or gdisk can be used, whether using BIOS or UEFI, respectively.&lt;/strong&gt;&lt;br /&gt;
&lt;em&gt;These instructions are assuming a blank disk.&lt;/em&gt;&lt;br /&gt;
Since I&#39;m using BIOS boot, I&#39;ll be using MBR instead of GPT, electing for fdisk.&lt;br /&gt;
I create the very first partition of 1 GiB for &lt;code&gt;/boot&lt;/code&gt;, which will be formatted&lt;br /&gt;
as ext4; however, if GPT and UEFI is being used, it must be formatted as FAT32,&lt;br /&gt;
with type of EF00. Here, I leave the MBR type the default 0x83 for Linux.&lt;br /&gt;
I create the second partition which will be LUKS encrypted and formatted Btrfs.&lt;br /&gt;
It&#39;s also default type 0x83. I also marked the first partition as active.&lt;br /&gt;
&lt;strong&gt;Make sure you&#39;re partitioning the correct drive!&lt;/strong&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;img src=&quot;/public/kde-btrfs-swapfile/3-fdisk.png&quot; alt=&quot;Fdisk partitioning&quot; /&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;strong&gt;Once partitioning is done, the partitions must be formatted.&lt;/strong&gt;&lt;br /&gt;
While the boot partition can be encrypted, frankly it&#39;s easier if it&#39;s not.&lt;br /&gt;
Here, since I&#39;m using MBR, I can format as ext4 with&lt;br /&gt;
&lt;code&gt;# mkfs.ext4 /dev/vda1&lt;/code&gt;, where vda1 corresponds to my 1st partition.&lt;br /&gt;
However with UEFI, it must be FAT32, &lt;code&gt;# mkfs.fat -F32 /dev/vda1&lt;/code&gt;.&lt;br /&gt;
The UEFI spec calls for 32-bit FAT, which is why it is forced with &lt;code&gt;-F 32&lt;/code&gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;img src=&quot;/public/kde-btrfs-swapfile/4-ext4_boot.png&quot; alt=&quot;Formatting the boot partition with ext4&quot; /&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;strong&gt;Now that&#39;s done, I want to encrypt my main partition.&lt;/strong&gt;&lt;br /&gt;
This isn&#39;t necessary for the rest of this post to work, but commands would be&lt;br /&gt;
adjusted accordingly.&lt;br /&gt;
&lt;br /&gt;
&lt;code&gt;# cryptsetup luksFormat /dev/vda2&lt;/code&gt;, where again, vda2 is replaced with &lt;em&gt;your&lt;/em&gt;&lt;br /&gt;
appropriate partition and supply the new encryption password.&lt;br /&gt;
After the LUKS encryption is done, it needs to be opened:&lt;br /&gt;
&lt;code&gt;# cryptsetup open /dev/vda2 luks&lt;/code&gt;, the &lt;code&gt;luks&lt;/code&gt; at the end can be anything. It&#39;s&lt;br /&gt;
just what the mapping will be called, in this case &lt;code&gt;/dev/mapper/luks&lt;/code&gt;.  &lt;/p&gt;
&lt;p&gt;Once the partition is authenticated, it can be formatted as Btrfs:&lt;br /&gt;
&lt;code&gt;# mkfs.btrfs /dev/mapper/luks&lt;/code&gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;img src=&quot;/public/kde-btrfs-swapfile/5-luks_btrfs.png&quot; alt=&quot;formatting LUKS and btrfs&quot; /&gt;
&lt;br /&gt;
&lt;strong&gt;It&#39;s time to create the Btrfs subvolumes.&lt;/strong&gt;&lt;br /&gt;
I mount the new partition to &lt;code&gt;/mnt&lt;/code&gt;:
&lt;code&gt;# mount /dev/mapper/luks /mnt&lt;/code&gt;.&lt;br /&gt;
Here I created the following: @, @home, @log, @snapshots, @swap.&lt;br /&gt;
The @ subvolume will just be the root &lt;code&gt;/&lt;/code&gt;, and the others mounted within that.&lt;br /&gt;
&lt;br /&gt;
&lt;img src=&quot;/public/kde-btrfs-swapfile/6-btrfs_subvol.png&quot; alt=&quot;Creating btrfs subvolumes&quot; /&gt;  &lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Now it must be remounted to have the subvolumes mounted in the correct place.&lt;/strong&gt;&lt;br /&gt;
First the current should be unmounted: &lt;code&gt;# umount /mnt&lt;/code&gt;.&lt;br /&gt;
Now, mounting the root subvolume &lt;code&gt;@&lt;/code&gt; to /mnt with the following:&lt;br /&gt;
&lt;code&gt;# mount -o noatime,subvol=@ /dev/mapper/luks /mnt&lt;/code&gt;. The mount option &lt;code&gt;noatime&lt;/code&gt;&lt;br /&gt;
is chosen to reduce the overhead of keeping access times for every file.&lt;br /&gt;
&lt;br /&gt;
After the root is mounted, the new mount points needs to be made, whether with&lt;br /&gt;
the &lt;code&gt;-m&lt;/code&gt; option with mount or manually with mkdir. Both options are shown here.&lt;br /&gt;
After mounting, I run &lt;code&gt;mount&lt;/code&gt; again to ensure they mounted with the proper&lt;br /&gt;
options at the expected mount point, just to be safe.&lt;br /&gt;
&lt;br /&gt;
&lt;img src=&quot;/public/kde-btrfs-swapfile/7-mounts.png&quot; alt=&quot;Creating subvolume mountpoints&quot; /&gt;  &lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;Installing Arch (finally)  &lt;/h2&gt;
&lt;p&gt;While this step is optional, it doesn&#39;t hurt to generate a new mirrorlist&lt;br /&gt;
that works best for your location. It will be copied to the system during the&lt;br /&gt;
installation process. I recommend reading reflector&#39;s man page.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/public/kde-btrfs-swapfile/8-reflector.png&quot; alt=&quot;running reflector to sort repos based on speed and latest sync&quot; /&gt;  &lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Finally time to install Arch!&lt;/strong&gt;&lt;br /&gt;
At the minimum you&#39;ll need base and linux packages. However, I added packages&lt;br /&gt;
that make my life easier further in the installation.&lt;br /&gt;
&lt;code&gt;# pacstrap -K /mnt base base-devel linux linux-firmware screen neovim dhclient&lt;/code&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;img src=&quot;/public/kde-btrfs-swapfile/9-pacstrap_done.png&quot; alt=&quot;pacstrap installing the Arch system&quot; /&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;strong&gt;Arch is &lt;em&gt;technically&lt;/em&gt; installed now&lt;/strong&gt;&lt;br /&gt;
But it&#39;s in a completely useless state without being able to boot itself.&lt;br /&gt;
&lt;br /&gt;
We need to generate a fstab for the new installation:&lt;br /&gt;
&lt;code&gt;# genfstab -U /mnt &amp;gt;&amp;gt; /mnt/etc/fstab&lt;/code&gt;.&lt;br /&gt;
It should autodetect if it&#39;s on an SSD, but if not, it can be added to the&lt;br /&gt;
mount options afterwards.&lt;br /&gt;
After it is generated, check that it looks okay.&lt;br /&gt;
&lt;br /&gt;
&lt;img src=&quot;/public/kde-btrfs-swapfile/10-fstab1.png&quot; alt=&quot;generating the new fstab&quot; /&gt;&lt;br /&gt;
&lt;br /&gt;
And I ended up adding &lt;code&gt;ssd&lt;/code&gt; to my btrfs mount options using vim, as shown.&lt;br /&gt;
&lt;br /&gt;
&lt;img src=&quot;/public/kde-btrfs-swapfile/11-fstab_ssd.png&quot; alt=&quot;fstab but with ssd in mount options&quot; /&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;strong&gt;Time to chroot!&lt;/strong&gt;&lt;br /&gt;
We&#39;re going to change root to the new installation as if we were booted to it.&lt;br /&gt;
&lt;code&gt;# arch-chroot /mnt&lt;/code&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;img src=&quot;/public/kde-btrfs-swapfile/12-chroot.png&quot; alt=&quot;arch-chroot&quot; /&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;strong&gt;Setting the timezone.&lt;/strong&gt;&lt;br /&gt;
You can &lt;code&gt;ls&lt;/code&gt; to find the appropriate region if you don&#39;t know already. While&lt;br /&gt;
I&#39;m in Tennessee as of posting, I&#39;m in Central time: &lt;code&gt;America/Chicago&lt;/code&gt;.&lt;br /&gt;
I created a symlink to &lt;code&gt;/etc/localtime&lt;/code&gt; as directed by the &lt;a href=&quot;https://wiki.archlinux.org/title/Installation_guide#Time_zone&quot;&gt;installation guide&lt;/a&gt;.&lt;br /&gt;
&lt;code&gt;# ln -sf /usr/share/zoneinfo/America/Chicago /etc/localtime&lt;/code&gt; afterwards I run&lt;br /&gt;
&lt;code&gt;# hwclock --systohc&lt;/code&gt; to sync the time to the CMOS of the system.&lt;br /&gt;
&lt;br /&gt;
&lt;img src=&quot;/public/kde-btrfs-swapfile/13-timezone.png&quot; alt=&quot;setting the timezone with a symlink&quot; /&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;strong&gt;Setting the default language and hostname&lt;/strong&gt;&lt;br /&gt;
This is fairly self-explanatory, although sed isn&#39;t necessary to uncomment&lt;br /&gt;
your respective locale. That said, if you would rather use a text editor like&lt;br /&gt;
&lt;code&gt;nano&lt;/code&gt; it needs to be installed with pacman first, since I installed neovim in&lt;br /&gt;
my example here.&lt;br /&gt;
&lt;br /&gt;
&lt;img src=&quot;/public/kde-btrfs-swapfile/14-lang_hostname.png&quot; alt=&quot;setting the language and hostname&quot; /&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;strong&gt;mkinitcpio.conf&lt;/strong&gt;&lt;br /&gt;
The init ramdisk needs to be configured to know how to decrypt the partition.&lt;br /&gt;
Add &lt;code&gt;encrypt&lt;/code&gt; before &lt;code&gt;filesystems&lt;/code&gt; and after &lt;code&gt;block&lt;/code&gt; in the &lt;code&gt;HOOKS&lt;/code&gt; about half-&lt;br /&gt;
way down the config file, using your editor of choice: I use neovim.&lt;br /&gt;
&lt;strong&gt;Note:&lt;/strong&gt; That is &lt;em&gt;not&lt;/em&gt; an underscore (it was my cursor) between &lt;strong&gt;encrypt&lt;/strong&gt;&lt;br /&gt;
and &lt;strong&gt;filesystems&lt;/strong&gt;, simply a space.&lt;br /&gt;
&lt;br /&gt;
&lt;img src=&quot;/public/kde-btrfs-swapfile/15-mkinitcpio_conf.png&quot; alt=&quot;editing mkinitcpio.conf to support encryption&quot; /&gt;&lt;br /&gt;
&lt;br /&gt;
After mkinitcpio.conf is edited, run &lt;code&gt;# mkinitcpio -P&lt;/code&gt; to generate the new initrd.&lt;br /&gt;
&lt;br /&gt;
&lt;strong&gt;Setting up GRUB&lt;/strong&gt;&lt;br /&gt;
&lt;strong&gt;Note:&lt;/strong&gt; Keep in mind we&#39;re still in the arch-chroot!&lt;br /&gt;
It&#39;s best to read the Arch Wiki for &lt;a href=&quot;https://wiki.archlinux.org/title/GRUB&quot;&gt;GRUB&lt;/a&gt; beforehand, in case your setup is different, i.e., UEFI.&lt;br /&gt;
The GRUB package needs to be downloaded first, along with CPU microcode, if you&lt;br /&gt;
prefer (intel-ucode or amd-ucode). I recommend including the respective one.&lt;br /&gt;
&lt;code&gt;# pacman -S grub intel-ucode&lt;/code&gt;&lt;br /&gt;
GRUB will find the microcode image and include it automatically.&lt;br /&gt;
Here, since my boot drive is still &lt;code&gt;/dev/vda&lt;/code&gt;, that&#39;s where I&#39;ll install GRUB.&lt;br /&gt;
&lt;code&gt;# grub-install --target=i386-pc /dev/vda&lt;/code&gt;,&lt;br /&gt;
where &lt;code&gt;i386-pc&lt;/code&gt; means a BIOS/MBR system. For UEFI, it&#39;s &lt;code&gt;x86_64-efi&lt;/code&gt; with the EFI&lt;br /&gt;
partition mount point supplied. Check the wiki as mentioned.&lt;br /&gt;
&lt;br /&gt;
&lt;img src=&quot;/public/kde-btrfs-swapfile/16-grub.png&quot; alt=&quot;installing grub to the boot drive&quot; /&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;strong&gt;Setting GRUB to boot encrypted partitions&lt;/strong&gt;&lt;br /&gt;
Before the grub.cfg is created, some kernel boot parameters need to be specified&lt;br /&gt;
in &lt;code&gt;/etc/default/grub&lt;/code&gt;.&lt;br /&gt;
First the UUID for the root partition (not the mapped partition!) needs to be saved. It may be easier to do 
all of this in an SSH session from another PC. The SSH daemon probably needs 
starting: &lt;code&gt;# systemctl start sshd&lt;/code&gt;. In that case, using a multiplexer like GNU screen (which I had installed during pacstrap) is probably a good idea in the event the connection is dropped. Otherwise, continue forward.&lt;br /&gt;
While some mega-cool regex stuff could probably be done, I&#39;d spend more time&lt;br /&gt;
trying to figure that out than just appending the UUID to the end of the config&lt;br /&gt;
and then just moving it inside the text editor later. In that case, I did the&lt;br /&gt;
following: &lt;code&gt;# blkid -o value /dev/vda2 | head -n1 | tee -a /etc/default/grub&lt;/code&gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;img src=&quot;/public/kde-btrfs-swapfile/17-root_blkid.png&quot; alt=&quot;getting the root UUID and appending to grub config&quot; /&gt;&lt;br /&gt;
&lt;br /&gt;
Afterwards, I used neovim to move the UUID into the kernel boot arguments.&lt;br /&gt;
The following is needed:&lt;br /&gt;
&lt;code&gt;cryptdevice=UUID=&amp;lt;your UUID here&amp;gt;:root root=/dev/mapper/root&lt;/code&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;img src=&quot;/public/kde-btrfs-swapfile/18-cryptdevice_grub.png&quot; alt=&quot;using neovim to correct the kernel options&quot; /&gt;&lt;br /&gt;
&lt;br /&gt;
Once the grub config is edited appropriately, run &lt;code&gt;# grub-mkconfig -o /boot/grub/grub.cfg&lt;/code&gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;strong&gt;Creating the swap file&lt;/strong&gt;&lt;br /&gt;
Before we forget, we need to disable Btrfs COW for the swap subvolume. This can&lt;br /&gt;
be achieved by adding the &lt;code&gt;+C&lt;/code&gt; attribute to the mount directory.&lt;br /&gt;
&lt;code&gt;# chattr +C /swap&lt;/code&gt;&lt;br /&gt;
This can be verified with &lt;code&gt;# lsattr -d /swap&lt;/code&gt; as shown in the picture.&lt;br /&gt;
&lt;img src=&quot;/public/kde-btrfs-swapfile/19-chattr_swap.png&quot; alt=&quot;using chattr to set the swap mount&quot; /&gt;&lt;br /&gt;
&lt;br /&gt;
Luckily newer versions of Btrfs can generate the swap file for us.&lt;br /&gt;
However we need btrfs-progs: &lt;code&gt;# pacman -S btrfs-progs&lt;/code&gt;.  Then run,&lt;br /&gt;
&lt;code&gt;# btrfs filesystem mkswapfile --size &amp;lt;your ram size&amp;gt;G /swap/swapfile&lt;/code&gt;&lt;br /&gt;
If you&#39;re confused about needing btrfs-progs, it&#39;s because we&#39;re in chroot. The&lt;br /&gt;
ISO of Arch has btrfs-progs included, but we&#39;re in the installed system&#39;s environment.&lt;br /&gt;
If you intend to hibernate, I recommend the swap size being at least equal&lt;br /&gt;
to that of your memory. Since my VM here has 2GiB of RAM, my swap will be 2G.&lt;br /&gt;
Afterwards I need to append the new swap file to the fstab so the system will&lt;br /&gt;
automatically use it. &lt;code&gt;# echo &amp;quot;/swap/swapfile none swap defaults 0 0&amp;quot; | tee -a /etc/fstab&lt;/code&gt;&lt;br /&gt;
&lt;strong&gt;I made a typo in the image, &#39;default&#39; should be &#39;defaults&#39;.&lt;/strong&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;img src=&quot;/public/kde-btrfs-swapfile/20-creating_swapfile.png&quot; alt=&quot;creating swap file and appending to fstab&quot; /&gt;&lt;br /&gt;
&lt;br /&gt;
Piping to &lt;code&gt;tee&lt;/code&gt; (with -a so we don&#39;t overwrite!) just allows me to ensure the&lt;br /&gt;
edited fstab is correct. Well, mine would be without the typo. Just pretend mine&lt;br /&gt;
is right!  &lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;Finally ready to reboot!  &lt;/h2&gt;
&lt;p&gt;Maybe not quite ready. We still need to exit chroot and unmount partitions.&lt;br /&gt;
Simply &lt;code&gt;# exit&lt;/code&gt; from chroot then unmount everything: &lt;code&gt;# umount -R /mnt&lt;/code&gt;.&lt;br /&gt;
If no errors occurred when unmounting, it&#39;s safe to &lt;code&gt;# reboot&lt;/code&gt; or &lt;code&gt;# poweroff&lt;/code&gt;.&lt;br /&gt;
&lt;strong&gt;Note:&lt;/strong&gt; Be sure to remove installation media after the reboot.&lt;br /&gt;
If all is well, the GRUB menu should load and start the kernel automatically,&lt;br /&gt;
landing you at the prompt to enter your LUKS password created a while ago.&lt;br /&gt;
&lt;br /&gt;
&lt;img src=&quot;/public/kde-btrfs-swapfile/21-reboot.png&quot; alt=&quot;Kernel needing LUKS pass to mount root&quot; /&gt;&lt;br /&gt;
&lt;br /&gt;
Characters will not echo to the screen.  &lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;First login to a base system  &lt;/h2&gt;
&lt;p&gt;Login as root. And run &lt;code&gt;# dhclient&lt;/code&gt; to get an IP address.&lt;br /&gt;
&lt;br /&gt;
&lt;img src=&quot;/public/kde-btrfs-swapfile/22-login_root_firsttime_dhclient.png&quot; alt=&quot;login prompt to the root account&quot; /&gt;&lt;br /&gt;
&lt;br /&gt;
Welcome to Arch Linux! It&#39;s not very convenient without a GUI, though.&lt;br /&gt;
Before that, I need to create a normal user and give it sudo privileges.&lt;br /&gt;
I decided giving the user the group &lt;code&gt;wheel&lt;/code&gt; is the best, given it allows&lt;br /&gt;
for many other things. Use your editor of choice by adjusting the EDITOR variable.&lt;br /&gt;
I use neovim, so ran visudo with the following: &lt;code&gt;# EDITOR=nvim visudo&lt;/code&gt;.&lt;br /&gt;
Uncomment the %wheel line as shown in the picture.&lt;br /&gt;
&lt;br /&gt;
&lt;img src=&quot;/public/kde-btrfs-swapfile/23-uncomment_wheel.png&quot; alt=&quot;running visudo and uncommenting %wheel&quot; /&gt;  &lt;/p&gt;
&lt;p&gt;Save and close the editor.  &lt;/p&gt;
&lt;p&gt;Create the new user: &lt;code&gt;# useradd -m &amp;lt;username&amp;gt;&lt;/code&gt;, where &lt;code&gt;-m&lt;/code&gt; generates a home dir.&lt;br /&gt;
Afterwards, assign a login password for the new user: &lt;code&gt;# passwd &amp;lt;username&amp;gt;&lt;/code&gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;img src=&quot;/public/kde-btrfs-swapfile/24-create_user.png&quot; alt=&quot;creating a new user and giving a password&quot; /&gt;  &lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Installing the desktop environment&lt;/strong&gt;&lt;br /&gt;
I&#39;m choosing KDE here given how feature rich it is, but which DE to use is your choice.&lt;br /&gt;
I elected to do a base KDE Plasma install with some necessities just for example.&lt;br /&gt;
Having a terminal emulator is important, so I chose the default KDE Konsole and&lt;br /&gt;
Firefox for my web browser.&lt;br /&gt;
It&#39;s best to read the wiki for &lt;a href=&quot;https://wiki.archlinux.org/title/Desktop_environment&quot;&gt;desktop environments&lt;/a&gt; and &lt;a href=&quot;https://wiki.archlinux.org/title/Display_manager&quot;&gt;display managers&lt;/a&gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;img src=&quot;/public/kde-btrfs-swapfile/25-installing_kde_1.png&quot; alt=&quot;installing KDE plasma with pacman&quot; /&gt;  &lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Enabling the display manager and network manager&lt;/strong&gt;&lt;br /&gt;
Before we can use the DE, we need to enable the display manager SDDM, and the&lt;br /&gt;
network manager to handle network connections (no more dhclient!).&lt;br /&gt;
&lt;code&gt;# systemctl enable sddm&lt;/code&gt; and &lt;code&gt;# systemctl enable NetworkManager&lt;/code&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;img src=&quot;/public/kde-btrfs-swapfile/26-enable_sddm_networkmanager.png&quot; alt=&quot;enabling sddm and NetworkManager with systemctl&quot; /&gt;&lt;br /&gt;
&lt;br /&gt;
Reboot once more.&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;Welcome to KDE  &lt;/h2&gt;
&lt;p&gt;If all is well, SDDM should start up after rebooting (and unlocking LUKS).&lt;br /&gt;
Login as the new normal user.&lt;br /&gt;
&lt;br /&gt;
&lt;img src=&quot;/public/kde-btrfs-swapfile/27-sddm_login_1.png&quot; alt=&quot;SDDM login screen&quot; /&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;img src=&quot;/public/kde-btrfs-swapfile/28-welcome_to_kde.png&quot; alt=&quot;KDE Plasma 5.27 desktop&quot; /&gt;&lt;br /&gt;
&lt;br /&gt;
SDDM is unthemed by default. That&#39;s easily fixed in System Settings.&lt;br /&gt;
Select the theme you like, apply, then also &#39;Apply Plasma settings&#39;.&lt;br /&gt;
&lt;br /&gt;
&lt;img src=&quot;/public/kde-btrfs-swapfile/29-theming_sddm.png&quot; alt=&quot;setting SDDM theme&quot; /&gt;  &lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;Getting hibernation working  &lt;/h2&gt;
&lt;p&gt;If hibernation isn&#39;t needed, you&#39;re done. Continue setting up the system how&lt;br /&gt;
you like. If you want hibernation, continue reading.  &lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Editing mkinitcpio.conf, again.&lt;/strong&gt;&lt;br /&gt;
I recommend, again, reading the Arch Wiki &lt;a href=&quot;https://wiki.archlinux.org/title/Power_management/Suspend_and_hibernate&quot;&gt;here&lt;/a&gt;.&lt;br /&gt;
&lt;br /&gt;
Open up a terminal (Konsole for me). Root privileges will be needed. Either change&lt;br /&gt;
to root with &lt;code&gt;$ su&lt;/code&gt; or &lt;code&gt;$ sudo -s&lt;/code&gt; or just prefix everything with &lt;code&gt;$ sudo&lt;/code&gt;.&lt;br /&gt;
Whatever you choose, open &lt;code&gt;/etc/mkinitcpio.conf&lt;/code&gt; in a text editor of choice.&lt;br /&gt;
Add &lt;code&gt;resume&lt;/code&gt; to the same place as before in &lt;code&gt;HOOKS&lt;/code&gt; but after &lt;code&gt;filesystems&lt;/code&gt; this time. Save and close the editor.&lt;br /&gt;
&lt;br /&gt;
&lt;img src=&quot;/public/kde-btrfs-swapfile/30-mkinitcpio_resume.png&quot; alt=&quot;editing mkinitcpio.conf to support hibernation&quot; /&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;strong&gt;Editing /etc/default/grub, again.&lt;/strong&gt;&lt;br /&gt;
The kernel also needs to know where to retrieve the saved hibernation state when&lt;br /&gt;
waking up. GRUB, of course, can provide this with the kernel options.&lt;br /&gt;
&lt;br /&gt;
Again we need a UUID of a partition, this time of the &lt;em&gt;mapped LUKS partition&lt;/em&gt; and&lt;br /&gt;
not the physical partition as before. Before this, we&#39;ll need the offset of the&lt;br /&gt;
swap file on the Btrfs filesystem. This can be retrieved as root with the following:&lt;br /&gt;
&lt;code&gt;# btrfs inspect-internal map-swapfile -r /swap/swapfile&lt;/code&gt;&lt;br /&gt;
&lt;br /&gt;
It&#39;s probably best to write down the output number, unless you can remember it.&lt;br /&gt;
Now the UUID is needed.&lt;br /&gt;
&lt;code&gt;# blkid -o value /dev/mapper/root | head -n1&lt;/code&gt;&lt;br /&gt;
I&#39;d just copy the output to my clipboard, now we have a GUI to use. Open &lt;code&gt;/etc/default/grub&lt;/code&gt;&lt;br /&gt;
as before and append &lt;code&gt;resume=UUID=&amp;lt;your mapped root UUID&amp;gt; resume_offset=&amp;lt;number you got&amp;gt;&lt;/code&gt;&lt;br /&gt;
to the kernel arguments like we did for the LUKS setup.&lt;br /&gt;
&lt;br /&gt;
&lt;img src=&quot;/public/kde-btrfs-swapfile/32-resume_UUID_offset.png&quot; alt=&quot;adding resume support to GRUB kernel options&quot; /&gt;&lt;br /&gt;
&lt;br /&gt;
If all looks great, reboot the system one last time.&lt;br /&gt;
&lt;br /&gt;
Now I have a Hibernate option in Plasma!&lt;br /&gt;
&lt;br /&gt;
&lt;img src=&quot;/public/kde-btrfs-swapfile/33-new_hibernate_option.png&quot; alt=&quot;photo showing the new hibernate option in the KDE application launcher&quot; /&gt;&lt;br /&gt;
&lt;br /&gt;
Go ahead and test it out. If the system doesn&#39;t fully shut off but reboots, try&lt;br /&gt;
the following: modify &lt;code&gt;/etc/systemd/sleep.conf&lt;/code&gt;.&lt;br /&gt;
&lt;br /&gt;
Uncommenting &lt;code&gt;HibernateMode&lt;/code&gt; and removing &lt;code&gt;platform&lt;/code&gt; so that it&#39;s&lt;br /&gt;
&lt;code&gt;HibernateMode=shutdown&lt;/code&gt; will likely be enough to fix it. If that doesn&#39;t work, 
it&#39;s possible your system firmware doesn&#39;t support hibernation. You&#39;d need to consult help elsewhere in that case.&lt;br /&gt;
&lt;br /&gt;
&lt;img src=&quot;/public/kde-btrfs-swapfile/31-if_system_doesnt_poweroff_when_hibernating.png&quot; alt=&quot;editing sleep.conf&quot; /&gt;  &lt;/p&gt;
&lt;hr /&gt;

&lt;br /&gt;
&lt;strong&gt;That&#39;s it!&lt;/strong&gt;&lt;br /&gt;
&lt;br /&gt;
No seriously, that&#39;s the end of this post. Hopefully it helps someone!&lt;br /&gt;
Please email me any suggestions or corrections.</content>
		<link href="https://nwb.sh/btrfs_swapfile_hibernation"/>
		<id>https://nwb.sh/btrfs_swapfile_hibernation</id>
		<updated>2023-03-09T00:00:00Z</updated>
		<published>2023-03-09T00:00:00Z</published>
	</entry>
</feed>
