2024-06-07 07:33:46 +00:00
# device support for samsung XE303C12 "google-snow" model, specifically.
# see: <https://wiki.postmarketos.org/wiki/Samsung_Chromebook_(google-snow)>
# - build logs: <https://images.postmarketos.org/bpo/edge/google-snow/console/>
# see: <https://github.com/thefloweringash/kevin-nix>
# - related "depthcharge" chromebook, built with nix
# see: <https://mobile.nixos.org/devices/lenovo-wormdingler.html>
# - above module, integrated into an image builder
# - implementation in modules/system-types/depthcharge
# see: <https://web.archive.org/web/20191103000916/http://www.chromium.org/chromium-os/firmware-porting-guide/using-nv-u-boot-on-the-samsung-arm-chromebook>
# - referenced from u-boot `doc/` directory
# - <https://web.archive.org/web/20220813062811/https://www.chromium.org/chromium-os/how-tos-and-troubleshooting/using-an-upstream-kernel-on-snow/>
# - <https://web.archive.org/web/20240119111314/https://www.chromium.org/chromium-os/developer-information-for-chrome-os-devices/custom-firmware/>
# - google exynos5_defconfig: <https://chromium.googlesource.com/chromiumos/overlays/chromiumos-overlay/%2B/HEAD/eclass/cros-kernel>
# see: <repo:postmarketOS/pmaports:device/community/device-google-snow>
# - <https://gitlab.com/postmarketOS/boot-deploy/-/blob/5f08ebb05a520d0e6bccfcda324f12e4aac1623f/boot-deploy-functions.sh#L872>
# - deviceinfo:
# - deviceinfo_flash_method="none"
# - deviceinfo_cgpt_kpart="/boot/vmlinuz.kpart"
# - deviceinfo_cgpt_kpart_start="8192"
# - deviceinfo_cgpt_kpart_size="16384"
# - deviceinfo_kernel_cmdline="console=null"
# - deviceinfo_depthcharge_board="snow"
# - deviceinfo_generate_depthcharge_image="true"
# - deviceinfo_generate_extlinux_config="true"
# - modules-initfs:
# - drm-dp-aux-bus
# - panel-edp
# - drm-kms-helper
# - cros-ec-keyb
# - sbs-battery
# - tps65090-charger
# - uas
# - sd-mod
# - pmOS also uses a custom alsa UCM config
# - pmOS kernel package: linux-postmarketos-exynos5
# - pmOS firmware packages (for WiFi/Bluetooth): linux-firmware-mrvl linux-firmware-s5p-mfc
#
# pmOS image has disk layout:
# /dev/sdb1 8192 24575 16384 8M ChromeOS kernel
# /dev/sdb2 24576 548863 524288 256M EFI System
# /dev/sdb3 548864 31336414 30787551 14.7G Microsoft basic data
# - built using `depthcharge-tools`: <https://github.com/alpernebbi/depthcharge-tools>
# - expected chromeos disk layout documented: <https://www.chromium.org/chromium-os/developer-library/reference/device/disk-format/>
#
# typical boot process:
# - BIOS searches for a partition `ChromeOS Kernel Type GUID (fe3a2a5d-4f32-41a7-b725-accc3285a309)`
# - first 64K are reserved for sigantures (when verified boot is active)
# - then kernel, some datastructures (i.e. config.txt, the command line passed to the kernel), bootloader stub
# - BIOS loads kernel blob into RAM, then invokes the bootstub
# - bootloader stub is an EFI application. it setups up tables and jumps into the kernel.
# - so potentially i could put any EFI application here, and load the kernel myself from somewhere else?
# - partitions are all 2MiB-aligned
# according to depthcharge-tools, max image size is 8 MiB, though i don't know how strict that is.
{ config , lib , pkgs , . . . }:
let
cfg = config . sane . hal . samsung ;
2024-06-10 03:48:31 +00:00
# sus commits:
# - ad3e33fe071dffea07279f96dab4f3773c430fe2 (drm/panel: Move AUX B116XW03 out of panel-edp back to panel-simple)
# says i should switch to `edp-panel`; chrome is lying about the panel.
# - discussion: <https://patchwork.freedesktop.org/patch/559389/>
# - was tested for exynos5-peach -- which worked with the patch and uses panel_simple
# - snow was *not* tested, but previously used panel_edp
linuxSourceHashes = {
" 6 . 2 . 1 6 " = " s h a 2 5 6 - d C 5 l p 4 5 t U 4 J g H S 8 V W e z L M / z 8 C 8 U M x a I d j 5 I 2 D l e M v 8 c = " ; #< boots
" 6 . 3 . 1 3 " = " s h a 2 5 6 - b G N c u E Y B H a Y 3 4 O e G k q b 5 8 d X V + J F 2 X Y 3 b p B t L h g 6 3 4 x A = " ; #< boots
" 6 . 4 . 1 6 " = " s h a 2 5 6 - h D h e l V L 2 0 A M z Q e T 7 I D V D I 3 5 u o G E y r o V P j i s z O 2 J Z z O 8 = " ; #< boots
" 6 . 5 . 1 3 " = " s h a 2 5 6 - l C T w q + 2 R y Z T I X 1 Y Q a / r i H f 1 K C n S 8 d T r L l l j j K A X u d z 4 = " ; #< boots
" 6 . 6 . 0 - r c 1 " = " s h a 2 5 6 - D R a i 7 H h W V t R B 0 G i R C v C v 2 J M 2 T F K R s Z 6 0 o h D 6 G W 0 b 8 A s = " ; #< boots. upstream/torvalds' tag is `v6.6-rc1`
" 6 . 6 . 0 - r c 3 " = " s h a 2 5 6 - / Y c u Q 5 U s S O b q O Z 0 Y I b c N e x 5 H J A L 8 e n e D D z I i T E u M D s Q = " ;
" 6 . 6 . 0 - r c 4 " = " s h a 2 5 6 - K b v + j U 2 I o C 4 s o T 3 m a 1 Z V 8 U n 4 r T Q a k N j u t 5 n l A 1 9 0 7 G Q = " ; #< boots. upstream/torvalds' tag is `v6.6-rc4`
" 6 . 6 . 0 - r c 5 " = " s h a 2 5 6 - i a 0 F / W 3 B R + g D 8 q E 5 L E w U c J C q w B s 3 c 5 k j 8 0 D b e D z F F q Y = " ;
" 6 . 6 . 0 - r c 6 " = " s h a 2 5 6 - H I r n 3 f k o C q V S S J 0 g x Y 6 N O 8 I 3 M 8 P 7 B D 5 X z Q p j r h d w / / s = " ; #< boots. upstream/torvalds' tag is `v6.6-rc6`
" 6 . 6 . 0 - r c 6 - b i - 5 1 8 8 " = " s h a 2 5 6 - T m R r P y 2 I h n v T V l q 5 b N h z s v N P g R g 0 q k 1 u 2 M h 3 q / l B a s k = " ; #< boots
" 6 . 6 . 0 - r c 6 - b i - 5 2 6 4 " = " s h a 2 5 6 - B X t 5 O 9 h U C 9 l Y I T B O 5 6 R z b 9 X J H T h j t 6 D u i X i z U i 2 G 6 / 0 = " ; # *does not boot*. this is commit ad3e33fe071dffea07279f96dab4f3773c430fe2; actually 6.6.0-rc1, because of merge order
" 6 . 6 . 0 - r c 7 " = " s h a 2 5 6 - u + s e Q p 8 2 U S t 6 3 z g M l v D R I p D m m W D 2 P h a 5 d 4 1 C o r w Y 7 f 8 = " ; #< *does not boot*. upstream/torvalds' tag is `v6.6-rc7`
" 6 . 6 . 0 " = " s h a 2 5 6 - i U T H P M b E L h t R o g b r K r 3 n 2 F B w j 8 m b G Y G a c y 2 U g j P Z Z N g = " ; #< *does not boot*. upstream/torvalds' tag is `v6.6`
" 6 . 7 . 1 2 " = " s h a 2 5 6 - 6 F m 7 l C 2 b w k + w Y Y G e a s r + 6 t c S w + n 3 V E 4 d 9 J W b c 9 j N 6 f A = " ; #< *does not boot*
" 6 . 1 0 . 0 - r c 3 " = " s h a 2 5 6 - k 9 M p f f 9 6 x g f T y j R M n 0 w O Q B O m 7 N K Z 7 I D t J B R Y w r n c c o Y = " ; #< *does not boot*. upstream/torvalds' tag is `v6.10-rc3`
} ;
2024-06-07 07:33:46 +00:00
in
{
options = {
sane . hal . samsung . enable = lib . mkEnableOption " s a m s u n g - s p e c i f i c h a r d w a r e s u p p o r t " ;
} ;
config = lib . mkIf cfg . enable {
boot . initrd . compressor = " g z i p " ;
# boot.initrd.compressorArgs = [ "--ultra" "-22" ];
2024-06-11 00:26:02 +00:00
hardware . firmware = [
( pkgs . linux-firmware . overrideAttrs ( _ : {
# mwifiex_sdio seems to require uncompressed firmware (even with a kernel configured for CONFIG_MODULE_COMPRESS_ZSTD=y)
passthru . compressFirmware = false ;
} ) )
] ;
2024-06-07 07:33:46 +00:00
boot . initrd . availableKernelModules = [
# boot.initrd.kernelModules = [
# from postmarketOS
" d r m - d p - a u x - b u s "
" p a n e l - e d p "
" d r m - k m s - h e l p e r "
" c r o s - e c - k e y b "
" s b s - b a t t e r y "
" t p s 6 5 0 9 0 - c h a r g e r "
" u a s "
" s d - m o d "
] ;
2024-06-07 07:39:21 +00:00
# N.B: mobile-nixos says these modules break udev, if builtin or run before udev:
2024-06-07 07:33:46 +00:00
# "sbs-battery"
# "sbs-charger"
# "sbs-manager"
2024-06-10 03:48:31 +00:00
# boot.kernelPackages = with pkgs; linuxPackagesFor (linux_6_1.override {
# preferBuiltin = false;
# extraConfig = "";
# structuredExtraConfig = with lib.kernel; {
# SUN8I_DE2_CCU = lib.mkForce no; #< nixpkgs' option parser gets confused on this one, somehow
# NET_VENDOR_MICREL = no; #< to overcome broken KS8851_MLL (broken by nixpkgs' `extraConfig`)
# # KS8851_MLL = lib.mkForce module; #< nixpkgs' option parser gets confused on this one, somehow
# #v XXX: required for e.g. SECURITY_LANDLOCK (specified by upstream nixpkgs) to take effect if `autoModules = false`
# #v seems that upstream linux (the defconfigs?), it defaults to Yes for:
# # - arch/x86/configs/x86_64_defconfig
# # - arch/arm64/configs/defconfig
# # but that it's left unset for e.g. arch/arm64/configs/pinephone_defconfig
# # SECURITY = yes;
# };
2024-06-09 18:40:38 +00:00
# });
2024-06-10 03:48:31 +00:00
# boot.kernelPackages = with pkgs; linuxPackagesFor linux_6_1;
# boot.kernelPackages = with pkgs; linuxPackagesFor linux-exynos5-mainline;
2024-06-12 06:16:13 +00:00
# boot.kernelPackages = with pkgs; linuxPackagesFor (linux-postmarketos-exynos5.override {
# # linux = let version = "6.6.0-rc1"; rev = "6.6.0-rc6-bi-5264"; in {
# # # src = pkgs.fetchzip {
# # # url = "https://git.kernel.org/stable/t/linux-6.2.16.tar.gz";
# # # };
# # src = pkgs.fetchFromGitea {
# # domain = "git.uninsane.org";
# # owner = "colin";
# # repo = "linux";
# # rev = "v${rev}";
# # hash = linuxSourceHashes."${rev}";
# # };
# # inherit version;
# # modDirVersion = version;
# # extraMakeFlags = [];
# # };
# # linux = linux_6_6;
# # linux = linux_6_8;
# # linux = linux_6_9;
# linux = linux_latest;
# # optimizeForSize = true;
# # useEdpPanel = true;
# revertPanelSimplePatch = true;
2024-06-07 07:33:46 +00:00
# });
2024-06-12 06:16:13 +00:00
# boot.kernelPackages = pkgs.linuxPackagesFor pkgs.linux-postmarketos-exynos5;
boot . kernelPackages = pkgs . linuxPackagesFor ( pkgs . linux-exynos5-mainline . override {
kernelPatches = [
pkgs . linux-postmarketos-exynos5 . sanePatches . revertPanelSimplePatch
] ;
structuredExtraConfig = with lib . kernel ; {
SECURITY = yes ;
SECURITY_LANDLOCK = yes ;
LSM = freeform " l a n d l o c k , l o c k d o w n , y a m a , l o a d p i n , s a f e s e t i d , s e l i n u x , s m a c k , t o m o y o , a p p a r m o r , b p f " ;
} ;
} ) ;
2024-06-07 07:33:46 +00:00
2024-06-07 07:39:21 +00:00
system . build . u-boot = pkgs . buildUBoot {
defconfig = " s n o w _ d e f c o n f i g " ;
extraMeta . platforms = [ " a r m v 7 l - l i n u x " ] ;
filesToInstall = [
" u - b o o t " #< ELF file
" u - b o o t . b i n " #< raw binary, load it into RAM and jump toit
" u - b o o t . c f g " #< copy of Kconfig which this u-boot was compiled with
" u - b o o t . d t b "
" u - b o o t . m a p "
" u - b o o t - n o d t b . b i n "
" u - b o o t . s y m "
] ;
2024-06-10 06:07:53 +00:00
# CONFIG_BOOTCOMMAND: autoboot from usb, and fix the ordering so that it happens before the internal memory (mmc0)
extraConfig = ''
CONFIG_BOOTCOMMAND = " e n v s e t b o o t c m d _ u s b 0 \" d e v n u m = 0 ; r u n u s b _ b o o t \" ; e n v s e t b o o t _ t a r g e t s \" u s b 0 m m c 2 m m c 1 m m c 0 \" ; r u n d i s t r o _ b o o t c m d "
'' ;
2024-06-07 07:39:21 +00:00
} ;
2024-06-07 07:33:46 +00:00
system . build . platformPartition = pkgs . runCommandLocal " k e r n e l - p a r t i t i o n " {
nativeBuildInputs = with pkgs ; [
vboot_reference
dtc
ubootTools
] ;
} ''
# according to depthcharge-tools, bootloader.bin is legacy, was used by the earliest
# chromebooks (H2C) *only*.
dd if = /dev/zero of = dummy_bootloader . bin bs = 512 count = 1
echo auto > dummy_config . txt
# from uboot snow_defconfig, also == CONFIG_SYS_LOAD_ADDR
CONFIG_TEXT_BASE = 0 x43e00000
cp $ { config . system . build . u-boot } /u-boot.bin .
ubootFlags = (
- A arm # architecture
- O linux # operating system
- T kernel # image type
- C none # compression
- a $ CONFIG_TEXT_BASE # load address (CONFIG_TEXT_BASE)
- e $ CONFIG_TEXT_BASE # entry point (CONFIG_SYS_LOAD_ADDR), i.e. where u-boot `bootm` should jump to to execute the kernel
- n nixos-uboot # image name
- d u-boot . bin # image data
u-boot . fit # output
)
mkimage " ' ' ${ ubootFlags [ @ ] } "
futility \
- - debug \
vbutil_kernel \
- - version 1 \
- - bootloader ./dummy_bootloader.bin \
- - vmlinuz u-boot . fit \
- - arch arm \
- - keyblock $ { pkgs . buildPackages . vboot_reference } /share/vboot/devkeys/kernel.keyblock \
- - signprivate $ { pkgs . buildPackages . vboot_reference } /share/vboot/devkeys/kernel_data_key.vbprivk \
- - config ./dummy_config.txt \
- - pack $ out
'' ;
2024-06-07 07:39:21 +00:00
# the platform partition presently only holds u-boot,
# and it seems possibly a limitation of depthcharge that it can't launch anything > 8 MiB (?)
# still, give a little extra room so i'm free to rearrange stuff if i find a way how.
2024-06-07 07:33:46 +00:00
sane . image . platformPartSize = 256 * 1024 * 1024 ;
# depthcharge firmware is designed for an A/B partition style,
# where partition A holds a kernel and partion B holds a different kernel.
# an update is to flash the currently inactive partition and then mark that one as active,
# either switching the default boot from partition A to partition B, or from B to A.
# anyway, this relies on the partitions having some extra metadata, which we add here.
# i believe this metadata is stored in a depthcharge-specific format, not anything
# which can be generalized.
sane . image . installBootloader = ''
$ { lib . getExe' pkgs . buildPackages . vboot_reference " c g p t " } add $ { lib . concatStringsSep " " [
" - i 1 " # work on the first partition (instead of adding)
" - S 1 " # mark as successful (so it'll be booted from)
" - T 5 " # tries remaining
" - P 1 0 " # priority
" $ o u t "
] }
'' ;
} ;
}