加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
文件
该仓库未声明开源许可证文件(LICENSE),使用请关注具体项目描述及其代码上游依赖。
克隆/下载
port-Add-LoongArch-support.patch 115.44 KB
一键复制 编辑 原始数据 按行查看 历史
mengyingkun 提交于 2023-01-10 17:19 . Add LoongArch support
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574
From 781cdb1573ffb77ed6d507d8daa7c6ff92256c57 Mon Sep 17 00:00:00 2001
From: mengyingkun <mengyingkun@loongson.cn>
Date: Thu, 12 Jan 2023 14:44:13 +0800
Subject: [PATCH] port: Add LoongArch support
This patch adds support for LoongArch. From now on, we can boot up
grub as a UEFI application on LoongArch platform.
Signed-off-by: yangqiming <yangqiming@loongson.cn>
Signed-off-by: mengyingkun <mengyingkun@loongson.cn>
---
Makefile.util.def | 1 +
bootstrap.conf | 4 +
configure.ac | 24 +
gentpl.py | 9 +-
grub-core/Makefile.am | 6 +
grub-core/Makefile.core.def | 23 +
grub-core/kern/dl.c | 9 +-
grub-core/kern/efi/mm.c | 3 +-
grub-core/kern/loongarch64/cache.S | 26 +
grub-core/kern/loongarch64/dl.c | 150 +++++
grub-core/kern/loongarch64/dl_helper.c | 264 +++++++++
grub-core/kern/loongarch64/efi/init.c | 73 +++
grub-core/kern/loongarch64/efi/startup.S | 45 ++
grub-core/kern/loongarch64/init.c | 47 ++
.../lib/gnulib-patches/fix-loongarch.patch | 26 +
grub-core/lib/loongarch64/relocator.c | 163 ++++++
grub-core/lib/loongarch64/relocator_asm.S | 51 ++
grub-core/lib/loongarch64/setjmp.S | 68 +++
grub-core/lib/setjmp.S | 2 +
grub-core/loader/efi/chainloader.c | 2 +
grub-core/loader/loongarch64/linux-efi.c | 144 +++++
grub-core/loader/loongarch64/linux-elf.c | 529 ++++++++++++++++++
grub-core/loader/loongarch64/linux.c | 398 +++++++++++++
include/grub/efi/api.h | 2 +-
include/grub/efi/efi.h | 6 +-
include/grub/efi/pe32.h | 4 +
include/grub/elf.h | 30 +
include/grub/fdt.h | 4 +-
include/grub/loongarch64/efi/loader.h | 25 +
include/grub/loongarch64/efi/memory.h | 15 +
include/grub/loongarch64/efi/time.h | 0
include/grub/loongarch64/io.h | 62 ++
include/grub/loongarch64/linux.h | 144 +++++
include/grub/loongarch64/loongarch64.h | 30 +
include/grub/loongarch64/memory.h | 59 ++
include/grub/loongarch64/reloc.h | 113 ++++
include/grub/loongarch64/relocator.h | 38 ++
include/grub/loongarch64/setjmp.h | 27 +
include/grub/loongarch64/time.h | 39 ++
include/grub/loongarch64/types.h | 34 ++
include/grub/util/install.h | 1 +
util/grub-install-common.c | 1 +
util/grub-install.c | 16 +
util/grub-mkimagexx.c | 99 +++-
util/grub-module-verifier.c | 15 +
util/mkimage.c | 16 +
46 files changed, 2833 insertions(+), 14 deletions(-)
create mode 100644 grub-core/kern/loongarch64/cache.S
create mode 100644 grub-core/kern/loongarch64/dl.c
create mode 100644 grub-core/kern/loongarch64/dl_helper.c
create mode 100644 grub-core/kern/loongarch64/efi/init.c
create mode 100644 grub-core/kern/loongarch64/efi/startup.S
create mode 100644 grub-core/kern/loongarch64/init.c
create mode 100644 grub-core/lib/gnulib-patches/fix-loongarch.patch
create mode 100644 grub-core/lib/loongarch64/relocator.c
create mode 100644 grub-core/lib/loongarch64/relocator_asm.S
create mode 100644 grub-core/lib/loongarch64/setjmp.S
create mode 100644 grub-core/loader/loongarch64/linux-efi.c
create mode 100644 grub-core/loader/loongarch64/linux-elf.c
create mode 100644 grub-core/loader/loongarch64/linux.c
create mode 100644 include/grub/loongarch64/efi/loader.h
create mode 100644 include/grub/loongarch64/efi/memory.h
create mode 100644 include/grub/loongarch64/efi/time.h
create mode 100644 include/grub/loongarch64/io.h
create mode 100644 include/grub/loongarch64/linux.h
create mode 100644 include/grub/loongarch64/loongarch64.h
create mode 100644 include/grub/loongarch64/memory.h
create mode 100644 include/grub/loongarch64/reloc.h
create mode 100644 include/grub/loongarch64/relocator.h
create mode 100644 include/grub/loongarch64/setjmp.h
create mode 100644 include/grub/loongarch64/time.h
create mode 100644 include/grub/loongarch64/types.h
diff --git a/Makefile.util.def b/Makefile.util.def
index b7a6311..932a8c2 100644
--- a/Makefile.util.def
+++ b/Makefile.util.def
@@ -169,6 +169,7 @@ library = {
common = grub-core/kern/ia64/dl_helper.c;
common = grub-core/kern/arm/dl_helper.c;
common = grub-core/kern/arm64/dl_helper.c;
+ common = grub-core/kern/loongarch64/dl_helper.c;
common = grub-core/lib/minilzo/minilzo.c;
common = grub-core/lib/xzembed/xz_dec_bcj.c;
common = grub-core/lib/xzembed/xz_dec_lzma2.c;
diff --git a/bootstrap.conf b/bootstrap.conf
index 03f1093..854d3c0 100644
--- a/bootstrap.conf
+++ b/bootstrap.conf
@@ -85,6 +85,10 @@ cp -a INSTALL INSTALL.grub
bootstrap_post_import_hook () {
set -e
+ for patchname in fix-loongarch; do
+ patch -d gnulib -p1 \
+ < "grub-core/lib/gnulib-patches/$patchname.patch"
+ done
for patchname in \
0001-Support-POTFILES-shell \
0002-Handle-gettext_printf-shell-function \
diff --git a/configure.ac b/configure.ac
index 0a9522a..d03e089 100644
--- a/configure.ac
+++ b/configure.ac
@@ -149,6 +149,10 @@ case "$target_cpu" in
riscv64*)
target_cpu=riscv64
;;
+ loongarch64)
+ target_cpu=loongarch64
+ machine_CPPFLAGS="$machine_CPPFLAGS -DGRUB_CPU_LOONGARCH64=1"
+ ;;
esac
# Specify the platform (such as firmware).
@@ -167,6 +171,7 @@ if test "x$with_platform" = x; then
powerpc64-*) platform=ieee1275 ;;
powerpc64le-*) platform=ieee1275 ;;
sparc64-*) platform=ieee1275 ;;
+ loongarch64-*) platform=efi ;;
mipsel-*) platform=loongson ;;
mips-*) platform=arc ;;
ia64-*) platform=efi ;;
@@ -218,6 +223,7 @@ case "$target_cpu"-"$platform" in
mipsel-yeeloong) platform=loongson ;;
mipsel-fuloong) platform=loongson ;;
mipsel-loongson) ;;
+ loongarch64-efi) ;;
arm-uboot) ;;
arm-coreboot) ;;
arm-efi) ;;
@@ -276,6 +282,7 @@ case "$platform" in
pc) machine_CPPFLAGS="$machine_CPPFLAGS -DGRUB_MACHINE_PCBIOS=1" ;;
emu) machine_CPPFLAGS="$machine_CPPFLAGS -DGRUB_MACHINE_EMU=1" ;;
loongson) machine_CPPFLAGS="$machine_CPPFLAGS -DGRUB_MACHINE_MIPS_LOONGSON=1" ;;
+ loongson64) machine_CPPFLAGS="$machine_CPPFLAGS -DGRUB_MACHINE_LOONARCH64=1" ;;
qemu_mips) machine_CPPFLAGS="$machine_CPPFLAGS -DGRUB_MACHINE_MIPS_QEMU_MIPS=1" ;;
arc) machine_CPPFLAGS="$machine_CPPFLAGS -DGRUB_MACHINE_ARC=1" ;;
esac
@@ -890,6 +897,21 @@ if ( test "x$target_cpu" = xi386 || test "x$target_cpu" = xx86_64 ) && test "x$p
TARGET_CFLAGS="$TARGET_CFLAGS -mno-mmx -mno-sse -mno-sse2 -mno-sse3 -mno-3dnow"
fi
+if test "x$target_cpu" = xloongarch64; then
+ AC_CACHE_CHECK([whether _mno_explicit_relocs works], [grub_cv_cc_mno_explicit_relocs], [
+ CFLAGS="$TARGET_CFLAGS -mno-explicit-relocs -Werror"
+ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[]], [[]])],
+ [grub_cv_cc_mno_explicit_relocs=yes],
+ [grub_cv_cc_mno_explicit_relocs=no])
+ ])
+ if test "x$grub_cv_cc_mno_explicit_relocs" = xyes; then
+ TARGET_CFLAGS="$TARGET_CFLAGS -mno-explicit-relocs -fno-plt"
+ TARGET_CCASFLAGS="$TARGET_CCASFLAGS -mno-explicit-relocs -fno-plt"
+ fi
+ TARGET_CFLAGS="$TARGET_CFLAGS -Wa,-mla-global-with-abs"
+ TARGET_CCASFLAGS="$TARGET_CCASFLAGS -Wa,-mla-global-with-abs"
+fi
+
# Should grub utils get the host CFLAGS, or the target CFLAGS?
AC_ARG_WITH([utils],
AS_HELP_STRING([--with-utils=host|target|build],
@@ -2166,6 +2188,8 @@ AM_CONDITIONAL([COND_mips_arc], [test "(" x$target_cpu = xmips -o x$target_cpu =
AM_CONDITIONAL([COND_sparc64_ieee1275], [test x$target_cpu = xsparc64 -a x$platform = xieee1275])
AM_CONDITIONAL([COND_sparc64_emu], [test x$target_cpu = xsparc64 -a x$platform = xemu])
AM_CONDITIONAL([COND_powerpc_ieee1275], [test x$target_cpu = xpowerpc -a x$platform = xieee1275])
+AM_CONDITIONAL([COND_loongarch64_efi], [test x$target_cpu = xloongarch64 -a x$platform = xefi])
+AM_CONDITIONAL([COND_loongarch64], [test x$target_cpu = xloongarch64])
AM_CONDITIONAL([COND_mips], [test x$target_cpu = xmips -o x$target_cpu = xmipsel])
AM_CONDITIONAL([COND_mipsel], [test x$target_cpu = xmipsel])
AM_CONDITIONAL([COND_mipseb], [test x$target_cpu = xmips])
diff --git a/gentpl.py b/gentpl.py
index 59f62ef..f03aff8 100644
--- a/gentpl.py
+++ b/gentpl.py
@@ -32,7 +32,8 @@ GRUB_PLATFORMS = [ "emu", "i386_pc", "i386_efi", "i386_qemu", "i386_coreboot",
"mips_loongson", "sparc64_ieee1275",
"powerpc_ieee1275", "mips_arc", "ia64_efi",
"mips_qemu_mips", "arm_uboot", "arm_efi", "arm64_efi",
- "arm_coreboot", "riscv32_efi", "riscv64_efi" ]
+ "arm_coreboot", "riscv32_efi", "riscv64_efi",
+ "loongarch64_efi" ]
GROUPS = {}
@@ -49,11 +50,12 @@ GROUPS["arm"] = [ "arm_uboot", "arm_efi", "arm_coreboot" ]
GROUPS["arm64"] = [ "arm64_efi" ]
GROUPS["riscv32"] = [ "riscv32_efi" ]
GROUPS["riscv64"] = [ "riscv64_efi" ]
+GROUPS["loongarch64"] = [ "loongarch64_efi" ]
# Groups based on firmware
GROUPS["pc"] = [ "i386_pc" ]
GROUPS["efi"] = [ "i386_efi", "x86_64_efi", "ia64_efi", "arm_efi", "arm64_efi",
- "riscv32_efi", "riscv64_efi" ]
+ "riscv32_efi", "riscv64_efi", "loongarch64_efi" ]
GROUPS["ieee1275"] = [ "i386_ieee1275", "sparc64_ieee1275", "powerpc_ieee1275" ]
GROUPS["uboot"] = [ "arm_uboot" ]
GROUPS["xen"] = [ "i386_xen", "x86_64_xen" ]
@@ -80,7 +82,8 @@ GROUPS["terminfomodule"] = GRUB_PLATFORMS[:];
for i in GROUPS["terminfoinkernel"]: GROUPS["terminfomodule"].remove(i)
# Flattened Device Trees (FDT)
-GROUPS["fdt"] = [ "arm64_efi", "arm_uboot", "arm_efi", "riscv32_efi", "riscv64_efi" ]
+GROUPS["fdt"] = [ "arm64_efi", "arm_uboot", "arm_efi", "riscv32_efi",
+ "riscv64_efi", "loongarch64_efi" ]
# Needs software helpers for division
# Must match GRUB_DIVISION_IN_SOFTWARE in misc.h
diff --git a/grub-core/Makefile.am b/grub-core/Makefile.am
index dd49939..6582f16 100644
--- a/grub-core/Makefile.am
+++ b/grub-core/Makefile.am
@@ -240,6 +240,12 @@ KERNEL_HEADER_FILES += $(top_builddir)/include/grub/machine/memory.h
KERNEL_HEADER_FILES += $(top_builddir)/include/grub/machine/kernel.h
endif
+if COND_loongarch64_efi
+KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/efi/efi.h
+KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/efi/disk.h
+KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/acpi.h
+endif
+
if COND_powerpc_ieee1275
KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/ieee1275/ieee1275.h
KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/terminfo.h
diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def
index 6b00eb5..016d345 100644
--- a/grub-core/Makefile.core.def
+++ b/grub-core/Makefile.core.def
@@ -103,6 +103,9 @@ kernel = {
arm_coreboot_ldflags = '-Wl,-r,-d';
arm_coreboot_stripflags = '--strip-unneeded -K start -R .note -R .comment -R .note.gnu.gold-version';
+ loongarch64_efi_ldflags = '-Wl,-r,-d';
+ loongarch64_efi_stripflags = '--strip-unneeded -K start -R .note -R .comment -R .note.gnu.gold-version -R .eh_frame';
+
i386_pc_startup = kern/i386/pc/startup.S;
i386_efi_startup = kern/i386/efi/startup.S;
x86_64_efi_startup = kern/x86_64/efi/startup.S;
@@ -122,6 +125,7 @@ kernel = {
arm64_efi_startup = kern/arm64/efi/startup.S;
riscv32_efi_startup = kern/riscv/efi/startup.S;
riscv64_efi_startup = kern/riscv/efi/startup.S;
+ loongarch64_efi_startup = kern/loongarch64/efi/startup.S;
common = kern/buffer.c;
common = kern/command.c;
@@ -270,6 +274,9 @@ kernel = {
riscv64_efi = kern/riscv/efi/init.c;
riscv64_efi = kern/efi/fdt.c;
+ loongarch64_efi = kern/loongarch64/efi/init.c;
+ loongarch64_efi = kern/efi/fdt.c;
+
i386_pc = kern/i386/pc/init.c;
i386_pc = kern/i386/pc/mmap.c;
i386_pc = term/i386/pc/console.c;
@@ -351,6 +358,12 @@ kernel = {
riscv64 = kern/riscv/cache_flush.S;
riscv64 = kern/riscv/dl.c;
+ loongarch64 = kern/loongarch64/init.c;
+ loongarch64 = kern/loongarch64/dl.c;
+ loongarch64 = kern/loongarch64/dl_helper.c;
+ loongarch64 = kern/loongarch64/cache.S;
+ loongarch64 = kern/generic/rtc_get_time_ms.c;
+
fdt = lib/fdt.c;
emu = disk/host.c;
@@ -864,6 +877,7 @@ module = {
enable = arm_coreboot;
enable = riscv32_efi;
enable = riscv64_efi;
+ enable = loongarch64_efi;
};
module = {
@@ -941,6 +955,7 @@ module = {
i386_multiboot = commands/acpihalt.c;
i386_efi = commands/acpihalt.c;
x86_64_efi = commands/acpihalt.c;
+ loongarch64_efi = commands/acpihalt.c;
i386_multiboot = lib/i386/halt.c;
i386_coreboot = lib/i386/halt.c;
i386_qemu = lib/i386/halt.c;
@@ -1715,6 +1730,8 @@ module = {
x86_64_xen = lib/x86_64/xen/relocator.S;
xen = lib/i386/relocator_common_c.c;
x86_64_efi = lib/x86_64/efi/relocator.c;
+ loongarch64 = lib/loongarch64/relocator_asm.S;
+ loongarch64 = lib/loongarch64/relocator.c;
extra_dist = lib/i386/relocator_common.S;
extra_dist = kern/powerpc/cache_flush.S;
@@ -1724,6 +1741,7 @@ module = {
enable = x86;
enable = i386_xen_pvh;
enable = xen;
+ enable = loongarch64;
};
module = {
@@ -1756,6 +1774,7 @@ module = {
extra_dist = lib/arm/setjmp.S;
extra_dist = lib/arm64/setjmp.S;
extra_dist = lib/riscv/setjmp.S;
+ extra_dist = lib/loongarch64/setjmp.S;
};
module = {
@@ -1854,6 +1873,9 @@ module = {
arm64 = loader/arm64/linux.c;
riscv32 = loader/riscv/linux.c;
riscv64 = loader/riscv/linux.c;
+ loongarch64 = loader/loongarch64/linux.c;
+ loongarch64 = loader/loongarch64/linux-elf.c;
+ loongarch64 = loader/loongarch64/linux-efi.c;
emu = loader/emu/linux.c;
common = loader/linux.c;
@@ -1953,6 +1975,7 @@ module = {
enable = riscv32_efi;
enable = riscv64_efi;
enable = mips;
+ enable = loongarch64_efi;
};
module = {
diff --git a/grub-core/kern/dl.c b/grub-core/kern/dl.c
index f304494..8c82ea1 100644
--- a/grub-core/kern/dl.c
+++ b/grub-core/kern/dl.c
@@ -278,7 +278,8 @@ grub_dl_load_segments (grub_dl_t mod, const Elf_Ehdr *e)
unsigned i;
const Elf_Shdr *s;
grub_size_t tsize = 0, talign = 1;
-#if !defined (__i386__) && !defined (__x86_64__) && !defined(__riscv)
+#if !defined (__i386__) && !defined (__x86_64__) && !defined(__riscv) && \
+ !defined(__loongarch__)
grub_size_t tramp;
grub_size_t got;
grub_err_t err;
@@ -294,7 +295,8 @@ grub_dl_load_segments (grub_dl_t mod, const Elf_Ehdr *e)
talign = s->sh_addralign;
}
-#if !defined (__i386__) && !defined (__x86_64__) && !defined(__riscv)
+#if !defined (__i386__) && !defined (__x86_64__) && !defined(__riscv) && \
+ !defined(__loongarch__)
err = grub_arch_dl_get_tramp_got_size (e, &tramp, &got);
if (err)
return err;
@@ -357,7 +359,8 @@ grub_dl_load_segments (grub_dl_t mod, const Elf_Ehdr *e)
mod->segment = seg;
}
}
-#if !defined (__i386__) && !defined (__x86_64__) && !defined(__riscv)
+#if !defined (__i386__) && !defined (__x86_64__) && !defined(__riscv) && \
+ !defined(__loongarch__)
ptr = (char *) ALIGN_UP ((grub_addr_t) ptr, GRUB_ARCH_DL_TRAMP_ALIGN);
mod->tramp = ptr;
mod->trampptr = ptr;
diff --git a/grub-core/kern/efi/mm.c b/grub-core/kern/efi/mm.c
index 8553fcd..9d723a9 100644
--- a/grub-core/kern/efi/mm.c
+++ b/grub-core/kern/efi/mm.c
@@ -699,7 +699,8 @@ grub_efi_mm_init (void)
2 * BYTES_TO_PAGES (MEMORY_MAP_SIZE));
}
-#if defined (__aarch64__) || defined (__arm__) || defined (__riscv)
+#if defined (__aarch64__) || defined (__arm__) || defined (__riscv) \
+ || defined (__loongarch__)
grub_err_t
grub_efi_get_ram_base(grub_addr_t *base_addr)
{
diff --git a/grub-core/kern/loongarch64/cache.S b/grub-core/kern/loongarch64/cache.S
new file mode 100644
index 0000000..d291c67
--- /dev/null
+++ b/grub-core/kern/loongarch64/cache.S
@@ -0,0 +1,26 @@
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2009,2017 Free Software Foundation, Inc.
+ *
+ * GRUB is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GRUB is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <grub/symbol.h>
+
+FUNCTION (grub_arch_sync_caches)
+ jr $ra
+
+FUNCTION (grub_arch_sync_dma_caches)
+ jr $ra
+
diff --git a/grub-core/kern/loongarch64/dl.c b/grub-core/kern/loongarch64/dl.c
new file mode 100644
index 0000000..47196a2
--- /dev/null
+++ b/grub-core/kern/loongarch64/dl.c
@@ -0,0 +1,150 @@
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2022 Free Software Foundation, Inc.
+ *
+ * GRUB is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GRUB is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <grub/dl.h>
+#include <grub/elf.h>
+#include <grub/misc.h>
+#include <grub/err.h>
+#include <grub/types.h>
+#include <grub/mm.h>
+#include <grub/i18n.h>
+#include <grub/cpu/reloc.h>
+
+/* Check if EHDR is a valid ELF header. */
+grub_err_t
+grub_arch_dl_check_header (void *ehdr)
+{
+ Elf_Ehdr *e = ehdr;
+
+ /* Check the magic numbers. */
+ if (e->e_ident[EI_CLASS] != ELFCLASS64
+ || e->e_ident[EI_DATA] != ELFDATA2LSB || e->e_machine != EM_LOONGARCH)
+ return grub_error (GRUB_ERR_BAD_OS, N_("invalid arch-dependent ELF magic"));
+
+ return GRUB_ERR_NONE;
+}
+
+#pragma GCC diagnostic ignored "-Wcast-align"
+
+/*
+ * Unified function for both REL and RELA.
+ */
+grub_err_t
+grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr,
+ Elf_Shdr *s, grub_dl_segment_t seg)
+{
+ Elf_Rel *rel, *max;
+ struct grub_loongarch64_stack stack;
+ grub_loongarch64_stack_init (&stack);
+
+ for (rel = (Elf_Rel *) ((char *) ehdr + s->sh_offset),
+ max = (Elf_Rel *) ((char *) rel + s->sh_size);
+ rel < max;
+ rel = (Elf_Rel *) ((char *) rel + s->sh_entsize))
+ {
+ Elf_Sym *sym;
+ void *place;
+ grub_uint64_t sym_addr;
+
+ if (rel->r_offset >= seg->size)
+ return grub_error (GRUB_ERR_BAD_MODULE,
+ "reloc offset is outside the segment");
+
+ sym = (Elf_Sym *) ((char*)mod->symtab
+ + mod->symsize * ELF_R_SYM (rel->r_info));
+
+ sym_addr = sym->st_value;
+ if (s->sh_type == SHT_RELA)
+ sym_addr += ((Elf_Rela *) rel)->r_addend;
+
+ place = (void *) ((grub_addr_t)seg->addr + rel->r_offset);
+
+ switch (ELF_R_TYPE (rel->r_info))
+ {
+ case R_LARCH_64:
+ {
+ grub_uint64_t *abs_place = place;
+
+ grub_dprintf ("dl", "reloc_abs64 %p => 0x%016llx, %p\n",
+ place, (unsigned long long) sym_addr, abs_place);
+
+ *abs_place += (grub_uint64_t) sym_addr;
+ }
+ break;
+ case R_LARCH_MARK_LA:
+ break;
+ case R_LARCH_SOP_PUSH_PCREL:
+ case R_LARCH_SOP_PUSH_PLT_PCREL:
+ grub_loongarch64_sop_push (&stack, sym_addr - (grub_uint64_t)place);
+ break;
+ case R_LARCH_B26:
+ {
+ grub_uint32_t *abs_place = place;
+ grub_ssize_t off = sym_addr - (grub_addr_t) place;
+
+ grub_loongarch64_b26 (abs_place, off);
+ }
+ break;
+ case R_LARCH_ABS_HI20:
+ {
+ grub_uint32_t *abs_place = place;
+ grub_loongarch64_xxx_hi20 (abs_place, sym_addr);
+ }
+ break;
+ case R_LARCH_ABS64_LO20:
+ {
+ grub_uint32_t *abs_place = place;
+ grub_loongarch64_xxx64_lo20 (abs_place, sym_addr);
+ }
+ break;
+ case R_LARCH_ABS64_HI12:
+ {
+ grub_uint32_t *abs_place = place;
+ grub_loongarch64_xxx64_hi12 (abs_place, sym_addr);
+ }
+ break;
+ case R_LARCH_PCALA_HI20:
+ {
+ grub_uint32_t *abs_place = place;
+ grub_int32_t off = (((sym_addr + 0x800) & ~0xfffULL) - ((grub_addr_t)place & ~0xfffULL));
+
+ grub_loongarch64_xxx_hi20 (abs_place, off);
+ }
+ break;
+ case R_LARCH_ABS_LO12:
+ case R_LARCH_PCALA_LO12:
+ {
+ grub_uint32_t *abs_place = place;
+ grub_loongarch64_xxx_lo12 (abs_place, sym_addr);
+ }
+ break;
+ GRUB_LOONGARCH64_RELOCATION (&stack, place, sym_addr)
+ default:
+ {
+ char rel_info[17]; /* log16(2^64) = 16, plus NUL. */
+
+ grub_snprintf (rel_info, sizeof (rel_info) - 1, "%" PRIxGRUB_UINT64_T,
+ (grub_uint64_t) ELF_R_TYPE (rel->r_info));
+ return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
+ N_("relocation 0x%s is not implemented yet"), rel_info);
+ }
+ break;
+ }
+ }
+ return GRUB_ERR_NONE;
+}
diff --git a/grub-core/kern/loongarch64/dl_helper.c b/grub-core/kern/loongarch64/dl_helper.c
new file mode 100644
index 0000000..68275fe
--- /dev/null
+++ b/grub-core/kern/loongarch64/dl_helper.c
@@ -0,0 +1,264 @@
+/* dl_helper.c - relocation helper functions for modules and grub-mkimage */
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2022 Free Software Foundation, Inc.
+ *
+ * GRUB is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GRUB is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <grub/dl.h>
+#include <grub/elf.h>
+#include <grub/misc.h>
+#include <grub/err.h>
+#include <grub/mm.h>
+#include <grub/i18n.h>
+#include <grub/loongarch64/reloc.h>
+
+static void grub_loongarch64_stack_push (grub_loongarch64_stack_t stack, grub_uint64_t x);
+static grub_uint64_t grub_loongarch64_stack_pop (grub_loongarch64_stack_t stack);
+
+void
+grub_loongarch64_stack_init (grub_loongarch64_stack_t stack)
+{
+ stack->top = -1;
+ stack->count = LOONGARCH64_STACK_MAX;
+}
+
+static void
+grub_loongarch64_stack_push (grub_loongarch64_stack_t stack, grub_uint64_t x)
+{
+ if (stack->top == stack->count)
+ return;
+ stack->data[++stack->top] = x;
+}
+
+static grub_uint64_t
+grub_loongarch64_stack_pop (grub_loongarch64_stack_t stack)
+{
+ if (stack->top == -1)
+ return -1;
+ return stack->data[stack->top--];
+}
+
+void
+grub_loongarch64_sop_push (grub_loongarch64_stack_t stack, grub_int64_t offset)
+{
+ grub_loongarch64_stack_push (stack, offset);
+}
+
+/* opr2 = pop (), opr1 = pop (), push (opr1 - opr2) */
+void
+grub_loongarch64_sop_sub (grub_loongarch64_stack_t stack)
+{
+ grub_uint64_t a, b;
+ b = grub_loongarch64_stack_pop (stack);
+ a = grub_loongarch64_stack_pop (stack);
+ grub_loongarch64_stack_push (stack, a - b);
+}
+
+/* opr2 = pop (), opr1 = pop (), push (opr1 << opr2) */
+void
+grub_loongarch64_sop_sl (grub_loongarch64_stack_t stack)
+{
+ grub_uint64_t a, b;
+ b = grub_loongarch64_stack_pop (stack);
+ a = grub_loongarch64_stack_pop (stack);
+ grub_loongarch64_stack_push (stack, a << b);
+}
+
+/* opr2 = pop (), opr1 = pop (), push (opr1 >> opr2) */
+void
+grub_loongarch64_sop_sr (grub_loongarch64_stack_t stack)
+{
+ grub_uint64_t a, b;
+ b = grub_loongarch64_stack_pop (stack);
+ a = grub_loongarch64_stack_pop (stack);
+ grub_loongarch64_stack_push (stack, a >> b);
+}
+
+/* opr2 = pop (), opr1 = pop (), push (opr1 + opr2) */
+void
+grub_loongarch64_sop_add (grub_loongarch64_stack_t stack)
+{
+ grub_uint64_t a, b;
+ b = grub_loongarch64_stack_pop (stack);
+ a = grub_loongarch64_stack_pop (stack);
+ grub_loongarch64_stack_push (stack, a + b);
+}
+
+/* opr2 = pop (), opr1 = pop (), push (opr1 & opr2) */
+void
+grub_loongarch64_sop_and (grub_loongarch64_stack_t stack)
+{
+ grub_uint64_t a, b;
+ b = grub_loongarch64_stack_pop (stack);
+ a = grub_loongarch64_stack_pop (stack);
+ grub_loongarch64_stack_push (stack, a & b);
+}
+
+/* opr3 = pop (), opr2 = pop (), opr1 = pop (), push (opr1 ? opr2 : opr3) */
+void
+grub_loongarch64_sop_if_else (grub_loongarch64_stack_t stack)
+{
+ grub_uint64_t a, b, c;
+ c = grub_loongarch64_stack_pop (stack);
+ b = grub_loongarch64_stack_pop (stack);
+ a = grub_loongarch64_stack_pop (stack);
+
+ if (a) {
+ grub_loongarch64_stack_push (stack, b);
+ } else {
+ grub_loongarch64_stack_push (stack, c);
+ }
+}
+
+/* opr1 = pop (), (*(uint32_t *) PC) [14 ... 10] = opr1 [4 ... 0] */
+void
+grub_loongarch64_sop_32_s_10_5 (grub_loongarch64_stack_t stack,
+ grub_uint64_t *place)
+{
+ grub_uint64_t a = grub_loongarch64_stack_pop (stack);
+ *place |= ((a & 0x1f) << 10);
+}
+
+/* opr1 = pop (), (*(uint32_t *) PC) [21 ... 10] = opr1 [11 ... 0] */
+void
+grub_loongarch64_sop_32_u_10_12 (grub_loongarch64_stack_t stack,
+ grub_uint64_t *place)
+{
+ grub_uint64_t a = grub_loongarch64_stack_pop (stack);
+ *place = *place | ((a & 0xfff) << 10);
+}
+
+/* opr1 = pop (), (*(uint32_t *) PC) [21 ... 10] = opr1 [11 ... 0] */
+void
+grub_loongarch64_sop_32_s_10_12 (grub_loongarch64_stack_t stack,
+ grub_uint64_t *place)
+{
+ grub_uint64_t a = grub_loongarch64_stack_pop (stack);
+ *place = (*place) | ((a & 0xfff) << 10);
+}
+
+/* opr1 = pop (), (*(uint32_t *) PC) [25 ... 10] = opr1 [15 ... 0] */
+void
+grub_loongarch64_sop_32_s_10_16 (grub_loongarch64_stack_t stack,
+ grub_uint64_t *place)
+{
+ grub_uint64_t a = grub_loongarch64_stack_pop (stack);
+ *place = (*place) | ((a & 0xffff) << 10);
+}
+
+/* opr1 = pop (), (*(uint32_t *) PC) [25 ... 10] = opr1 [17 ... 2] */
+void
+grub_loongarch64_sop_32_s_10_16_s2 (grub_loongarch64_stack_t stack,
+ grub_uint64_t *place)
+{
+ grub_uint64_t a = grub_loongarch64_stack_pop (stack);
+ *place = (*place) | (((a >> 2) & 0xffff) << 10);
+}
+
+/* opr1 = pop (), (*(uint32_t *) PC) [24 ... 5] = opr1 [19 ... 0] */
+void
+grub_loongarch64_sop_32_s_5_20 (grub_loongarch64_stack_t stack, grub_uint64_t *place)
+{
+ grub_uint64_t a = grub_loongarch64_stack_pop (stack);
+ *place = (*place) | ((a & 0xfffff)<<5);
+}
+
+/* opr1 = pop (),
+ (*(uint32_t *) PC) [4 ... 0] = opr1 [22 ... 18]
+ (*(uint32_t *) PC) [25 ...10] = opr1 [17 ... 2]
+ */
+void
+grub_loongarch64_sop_32_s_0_5_10_16_s2 (grub_loongarch64_stack_t stack,
+ grub_uint64_t *place)
+{
+ grub_uint64_t a = grub_loongarch64_stack_pop (stack);
+
+ *place =(*place) | (((a >> 2) & 0xffff) << 10);
+ *place =(*place) | ((a >> 18) & 0x1f);
+}
+
+/*
+ opr1 = pop ()
+ (*(uint32_t *) PC) [9 ... 0] = opr1 [27 ... 18],
+ (*(uint32_t *) PC) [25 ... 10] = opr1 [17 ... 2]
+*/
+void
+grub_loongarch64_sop_32_s_0_10_10_16_s2 (grub_loongarch64_stack_t stack,
+ grub_uint64_t *place)
+{
+ grub_uint64_t a = grub_loongarch64_stack_pop (stack);
+ *place =(*place) | (((a >> 2) & 0xffff) << 10);
+ *place =(*place) | ((a >> 18) & 0x3ff);
+}
+
+void grub_loongarch64_b26 (grub_uint32_t *place, grub_int64_t offset)
+{
+ grub_uint32_t val;
+ const grub_uint32_t insmask = grub_cpu_to_le32_compile_time (0xfc000000);
+
+ grub_dprintf ("dl", " reloc_xxxx64 %p %c= 0x%llx\n",
+ place, offset > 0 ? '+' : '-',
+ offset < 0 ? (long long) -(unsigned long long) offset : offset);
+
+ val = ((offset >> 18) & 0x3ff) | (((offset >> 2) & 0xffff) << 10);
+
+ *place &= insmask;
+ *place |= grub_cpu_to_le32 (val) & ~insmask;
+}
+
+void grub_loongarch64_xxx_hi20 (grub_uint32_t *place, grub_int64_t offset)
+{
+ const grub_uint32_t insmask = grub_cpu_to_le32_compile_time (0xfe00001f);
+ grub_uint32_t val;
+
+ offset >>= 12;
+ val = ((offset & 0xfffff) << 5);
+
+ *place &= insmask;
+ *place |= grub_cpu_to_le32 (val) & ~insmask;
+}
+
+void grub_loongarch64_xxx_lo12 (grub_uint32_t *place, grub_int64_t offset)
+{
+ const grub_uint32_t insmask = grub_cpu_to_le32_compile_time (0xffc003ff);
+
+ *place &= insmask;
+ *place |= grub_cpu_to_le32 (offset << 10) & ~insmask;
+}
+
+void grub_loongarch64_xxx64_hi12 (grub_uint32_t *place, grub_int64_t offset)
+{
+ const grub_uint32_t insmask = grub_cpu_to_le32_compile_time (0xffc003ff);
+ grub_uint32_t val;
+
+ offset >>= 52;
+ val = ((offset & 0xfff) << 10);
+
+ *place &= insmask;
+ *place |= grub_cpu_to_le32 (val) & ~insmask;
+}
+
+void grub_loongarch64_xxx64_lo20 (grub_uint32_t *place, grub_int64_t offset)
+{
+ const grub_uint32_t insmask = grub_cpu_to_le32_compile_time (0xfe00001f);
+ grub_uint32_t val;
+
+ offset >>= 32;
+ val = ((offset & 0xfffff) << 5);
+
+ *place &= insmask;
+ *place |= grub_cpu_to_le32 (val) & ~insmask;
+}
diff --git a/grub-core/kern/loongarch64/efi/init.c b/grub-core/kern/loongarch64/efi/init.c
new file mode 100644
index 0000000..7f7c866
--- /dev/null
+++ b/grub-core/kern/loongarch64/efi/init.c
@@ -0,0 +1,73 @@
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2013 Free Software Foundation, Inc.
+ *
+ * GRUB is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GRUB is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <grub/env.h>
+#include <grub/kernel.h>
+#include <grub/misc.h>
+#include <grub/mm.h>
+#include <grub/time.h>
+#include <grub/cpu/time.h>
+#include <grub/efi/efi.h>
+#include <grub/loader.h>
+
+static grub_uint64_t tmr;
+static grub_efi_event_t tmr_evt;
+
+static grub_uint64_t
+grub_efi_get_time_ms (void)
+{
+ return tmr;
+}
+
+static void
+grub_loongson_increment_timer (grub_efi_event_t event __attribute__ ((unused)),
+ void *context __attribute__ ((unused)))
+{
+ tmr += 10;
+}
+
+void
+grub_machine_init (void)
+{
+ grub_efi_boot_services_t *b;
+
+ grub_efi_init ();
+
+ b = grub_efi_system_table->boot_services;
+ efi_call_5 (b->create_event, GRUB_EFI_EVT_TIMER | GRUB_EFI_EVT_NOTIFY_SIGNAL,
+ GRUB_EFI_TPL_CALLBACK, grub_loongson_increment_timer, NULL, &tmr_evt);
+ efi_call_3 (b->set_timer, tmr_evt, GRUB_EFI_TIMER_PERIODIC, 100000);
+
+ grub_install_get_time_ms (grub_efi_get_time_ms);
+}
+
+void
+grub_machine_fini (int flags)
+{
+ grub_efi_boot_services_t *b;
+
+ if (!(flags & GRUB_LOADER_FLAG_NORETURN))
+ return;
+
+ b = grub_efi_system_table->boot_services;
+
+ efi_call_3 (b->set_timer, tmr_evt, GRUB_EFI_TIMER_CANCEL, 0);
+ efi_call_1 (b->close_event, tmr_evt);
+
+ grub_efi_fini ();
+}
diff --git a/grub-core/kern/loongarch64/efi/startup.S b/grub-core/kern/loongarch64/efi/startup.S
new file mode 100644
index 0000000..1ffff08
--- /dev/null
+++ b/grub-core/kern/loongarch64/efi/startup.S
@@ -0,0 +1,45 @@
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2013 Free Software Foundation, Inc.
+ *
+ * GRUB is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GRUB is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <grub/symbol.h>
+
+ .file "startup.S"
+ .text
+ .globl start, _start
+ .align 4
+
+FUNCTION(start)
+FUNCTION(_start)
+ /*
+ * EFI_SYSTEM_TABLE and EFI_HANDLE are passed in a1/a0.
+ */
+ addi.d $sp, $sp, -16
+ st.d $ra, $sp, 0
+
+ la $a2, grub_efi_image_handle
+ st.d $a0, $a2, 0
+ la $a2, grub_efi_system_table
+ st.d $a1, $a2, 0
+
+ bl grub_main
+
+1:
+ ld.d $ra, $sp, 0
+ addi.d $sp, $sp, 16
+ jr $ra
+
diff --git a/grub-core/kern/loongarch64/init.c b/grub-core/kern/loongarch64/init.c
new file mode 100644
index 0000000..b2de930
--- /dev/null
+++ b/grub-core/kern/loongarch64/init.c
@@ -0,0 +1,47 @@
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2009,2017 Free Software Foundation, Inc.
+ *
+ * GRUB is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GRUB is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <grub/kernel.h>
+#include <grub/env.h>
+#include <grub/time.h>
+#include <grub/cpu/loongarch64.h>
+
+grub_uint32_t grub_arch_cpuclock;
+
+/* FIXME: use interrupt to count high. */
+grub_uint64_t
+grub_get_rtc (void)
+{
+ static grub_uint32_t high = 0;
+ static grub_uint32_t last = 0;
+ grub_uint32_t low;
+
+ asm volatile ("csrrd %0, " GRUB_CPU_LOONGARCH_COP0_TIMER_COUNT : "=r" (low));
+ if (low < last)
+ high++;
+ last = low;
+
+ return (((grub_uint64_t) high) << 32) | low;
+}
+
+void
+grub_timer_init (grub_uint32_t cpuclock)
+{
+ grub_arch_cpuclock = cpuclock;
+ grub_install_get_time_ms (grub_rtc_get_time_ms);
+}
diff --git a/grub-core/lib/gnulib-patches/fix-loongarch.patch b/grub-core/lib/gnulib-patches/fix-loongarch.patch
new file mode 100644
index 0000000..fa0b09a
--- /dev/null
+++ b/grub-core/lib/gnulib-patches/fix-loongarch.patch
@@ -0,0 +1,26 @@
+diff --git a/build-aux/config.guess b/build-aux/config.guess
+index 8e2a58b..927581d 100755
+--- a/build-aux/config.guess
++++ b/build-aux/config.guess
+@@ -990,6 +990,9 @@ EOF
+ k1om:Linux:*:*)
+ echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
+ exit ;;
++ loongarch32:Linux:*:* | loongarch64:Linux:*:* | loongarchx32:Linux:*:*)
++ echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
++ exit ;;
+ m32r*:Linux:*:*)
+ echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
+ exit ;;
+diff --git a/build-aux/config.sub b/build-aux/config.sub
+index 1fc4cde..6303428 100755
+--- a/build-aux/config.sub
++++ b/build-aux/config.sub
+@@ -1184,6 +1184,7 @@ case $cpu-$vendor in
+ | k1om \
+ | le32 | le64 \
+ | lm32 \
++ | loongarch32 | loongarch64 | loongarchx32 \
+ | m32c | m32r | m32rle \
+ | m5200 | m68000 | m680[012346]0 | m68360 | m683?2 | m68k | v70 | w65 \
+ | m6811 | m68hc11 | m6812 | m68hc12 | m68hcs12x | nvptx | picochip \
diff --git a/grub-core/lib/loongarch64/relocator.c b/grub-core/lib/loongarch64/relocator.c
new file mode 100644
index 0000000..faa4553
--- /dev/null
+++ b/grub-core/lib/loongarch64/relocator.c
@@ -0,0 +1,163 @@
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2022 Free Software Foundation, Inc.
+ *
+ * GRUB is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GRUB is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <grub/mm.h>
+#include <grub/misc.h>
+
+#include <grub/types.h>
+#include <grub/types.h>
+#include <grub/err.h>
+#include <grub/cache.h>
+
+#include <grub/loongarch64/relocator.h>
+#include <grub/relocator_private.h>
+
+extern grub_uint8_t grub_relocator_forward_start;
+extern grub_uint8_t grub_relocator_forward_end;
+extern grub_uint8_t grub_relocator_backward_start;
+extern grub_uint8_t grub_relocator_backward_end;
+
+#define REGW_SIZEOF (4 * sizeof (grub_uint32_t))
+#define JUMP_SIZEOF (2 * sizeof (grub_uint32_t))
+
+#define RELOCATOR_SRC_SIZEOF(x) (&grub_relocator_##x##_end \
+ - &grub_relocator_##x##_start)
+#define RELOCATOR_SIZEOF(x) (RELOCATOR_SRC_SIZEOF(x) \
+ + REGW_SIZEOF * 3)
+grub_size_t grub_relocator_align = sizeof (grub_uint64_t);
+grub_size_t grub_relocator_forward_size;
+grub_size_t grub_relocator_backward_size;
+grub_size_t grub_relocator_jumper_size = JUMP_SIZEOF + REGW_SIZEOF;
+
+void
+grub_cpu_relocator_init (void)
+{
+ grub_relocator_forward_size = RELOCATOR_SIZEOF(forward);
+ grub_relocator_backward_size = RELOCATOR_SIZEOF(backward);
+}
+
+static void
+write_reg (int regn, grub_uint64_t val, void **target)
+{
+ grub_uint32_t lu12iw=0x14000000;
+ grub_uint32_t ori=0x03800000;
+ grub_uint32_t lu32id=0x16000000;
+ grub_uint32_t lu52id=0x03000000;
+
+ *(grub_uint32_t *) *target = (lu12iw | (grub_uint32_t)((val & 0xfffff000)>>12<<5) | (grub_uint32_t)regn);;
+ *target = ((grub_uint32_t *) *target) + 1;
+ *(grub_uint32_t *) *target = (ori | (grub_uint32_t)((val & 0xfff)<<10) | (grub_uint32_t)(regn | regn<<5));
+ *target = ((grub_uint32_t *) *target) + 1;
+ *(grub_uint32_t *) *target = (lu32id | (grub_uint32_t)((val & 0xfffff00000000)>>32<<5) | (grub_uint32_t)regn);;
+ *target = ((grub_uint32_t *) *target) + 1;
+ *(grub_uint32_t *) *target = (lu52id | (grub_uint32_t)((val & 0xfff0000000000000)>>52<<10) | (grub_uint32_t)(regn | regn<<5));;
+ *target = ((grub_uint32_t *) *target) + 1;
+}
+
+static void
+write_jump (int regn, void **target)
+{
+ grub_uint32_t jirl=0x4c000000;
+
+ *(grub_uint32_t *) *target = (jirl | (grub_uint32_t)(regn<<5));
+ *target = ((grub_uint32_t *) *target) + 1;
+}
+
+void
+grub_cpu_relocator_jumper (void *rels, grub_addr_t addr)
+{
+ write_reg (1, addr, &rels);
+ write_jump (1, &rels);
+}
+
+void
+grub_cpu_relocator_backward (void *ptr0, void *src, void *dest,
+ grub_size_t size)
+{
+ void *ptr = ptr0;
+ write_reg (8, (grub_uint64_t) src, &ptr);
+ write_reg (9, (grub_uint64_t) dest, &ptr);
+ write_reg (10, (grub_uint64_t) size, &ptr);
+ grub_memcpy (ptr, &grub_relocator_backward_start,
+ RELOCATOR_SRC_SIZEOF (backward));
+}
+
+void
+grub_cpu_relocator_forward (void *ptr0, void *src, void *dest,
+ grub_size_t size)
+{
+ void *ptr = ptr0;
+ write_reg (8, (grub_uint64_t) src, &ptr);
+ write_reg (9, (grub_uint64_t) dest, &ptr);
+ write_reg (10, (grub_uint64_t) size, &ptr);
+ grub_memcpy (ptr, &grub_relocator_forward_start,
+ RELOCATOR_SRC_SIZEOF (forward));
+}
+
+grub_err_t
+grub_relocator64_boot (struct grub_relocator *rel,
+ struct grub_relocator64_state state)
+{
+ grub_relocator_chunk_t ch;
+ void *ptr;
+ grub_err_t err;
+ void *relst;
+ grub_size_t relsize;
+ grub_size_t stateset_size = 31 * REGW_SIZEOF + JUMP_SIZEOF;
+ unsigned i;
+ grub_addr_t vtarget;
+
+ err = grub_relocator_alloc_chunk_align (rel, &ch, 0,
+ (0xffffffff - stateset_size)
+ + 1, stateset_size,
+ grub_relocator_align,
+ GRUB_RELOCATOR_PREFERENCE_NONE, 0);
+ if (err)
+ return err;
+
+ ptr = get_virtual_current_address (ch);
+ for (i = 1; i < 32; i++)
+ write_reg (i, state.gpr[i], &ptr);
+ write_jump (state.jumpreg, &ptr);
+
+ vtarget = (grub_addr_t) grub_map_memory (get_physical_target_address (ch),
+ stateset_size);
+
+ err = grub_relocator_prepare_relocs (rel, vtarget, &relst, &relsize);
+ if (err)
+ return err;
+
+ grub_arch_sync_caches ((void *) relst, relsize);
+
+ asm volatile (
+ "ibar 0 \n");
+
+ grub_uint64_t val;
+ __asm__ __volatile__(
+ "li.w %0, 0x4\n\t"
+ "csrxchg $r0, %0, 0x0\n\t"
+ : "=r"(val)
+ :
+ :
+ );
+
+ ((void (*) (void)) relst) ();
+
+ /* Not reached. */
+ return GRUB_ERR_NONE;
+}
diff --git a/grub-core/lib/loongarch64/relocator_asm.S b/grub-core/lib/loongarch64/relocator_asm.S
new file mode 100644
index 0000000..ffdccc9
--- /dev/null
+++ b/grub-core/lib/loongarch64/relocator_asm.S
@@ -0,0 +1,51 @@
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2022 Free Software Foundation, Inc.
+ *
+ * GRUB is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GRUB is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <grub/symbol.h>
+
+ .p2align 4 /* force 16-byte alignment */
+
+VARIABLE (grub_relocator_forward_start)
+
+copycont1:
+ ld.d $r11,$r8,0
+ st.d $r11,$r9,0
+ addi.d $r8, $r8, 8
+ addi.d $r10, $r10, -8
+ addi.d $r9, $r9, 8
+ bne $r10, $r0, copycont1
+
+VARIABLE (grub_relocator_forward_end)
+
+VARIABLE (grub_relocator_backward_start)
+
+ add.d $r9, $r9, $r10
+ add.d $r8, $r8, $r10
+ /* Backward movsl is implicitly off-by-one. compensate that. */
+ addi.d $r9, $r9, -8
+ addi.d $r8, $r8, -8
+copycont2:
+ ld.w $r11,$r8,0
+ st.w $r11,$r9,0
+ addi.d $r8, $r8, -8
+ addi.d $r10, $r10, -8
+ addi.d $r9, $r9, -8
+ bne $r10, $r0, copycont2
+
+VARIABLE (grub_relocator_backward_end)
+
diff --git a/grub-core/lib/loongarch64/setjmp.S b/grub-core/lib/loongarch64/setjmp.S
new file mode 100644
index 0000000..bb09959
--- /dev/null
+++ b/grub-core/lib/loongarch64/setjmp.S
@@ -0,0 +1,68 @@
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2021 Free Software Foundation, Inc.
+ *
+ * GRUB is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GRUB is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <grub/dl.h>
+
+ .file "setjmp.S"
+
+GRUB_MOD_LICENSE "GPLv3+"
+
+ .text
+
+/*
+ * int grub_setjmp (jmp_buf env)
+ */
+FUNCTION(grub_setjmp)
+ st.d $s0, $a0, 0x0
+ st.d $s1, $a0, 0x8
+ st.d $s2, $a0, 0x10
+ st.d $s3, $a0, 0x18
+ st.d $s4, $a0, 0x20
+ st.d $s5, $a0, 0x28
+ st.d $s6, $a0, 0x30
+ st.d $s7, $a0, 0x38
+ st.d $s8, $a0, 0x40
+ st.d $fp, $a0, 0x48
+ st.d $sp, $a0, 0x50
+ st.d $ra, $a0, 0x58
+
+ move $a0, $zero
+ jr $ra
+
+/*
+ * void grub_longjmp (jmp_buf env, int val)
+ */
+FUNCTION(grub_longjmp)
+ ld.d $s0, $a0, 0x0
+ ld.d $s1, $a0, 0x8
+ ld.d $s2, $a0, 0x10
+ ld.d $s3, $a0, 0x18
+ ld.d $s4, $a0, 0x20
+ ld.d $s5, $a0, 0x28
+ ld.d $s6, $a0, 0x30
+ ld.d $s7, $a0, 0x38
+ ld.d $s8, $a0, 0x40
+ ld.d $fp, $a0, 0x48
+ ld.d $sp, $a0, 0x50
+ ld.d $ra, $a0, 0x58
+
+ li.w $a0, 1
+ beqz $a1, .L0
+ move $a0, $a1
+.L0:
+ jr $ra
diff --git a/grub-core/lib/setjmp.S b/grub-core/lib/setjmp.S
index aa297ab..da71fc7 100644
--- a/grub-core/lib/setjmp.S
+++ b/grub-core/lib/setjmp.S
@@ -15,6 +15,8 @@
#include "./arm/setjmp.S"
#elif defined(__aarch64__)
#include "./arm64/setjmp.S"
+#elif defined(__loongarch64)
+#include "./loongarch64/setjmp.S"
#elif defined(__riscv)
#include "./riscv/setjmp.S"
#else
diff --git a/grub-core/loader/efi/chainloader.c b/grub-core/loader/efi/chainloader.c
index fb874f1..faf60ef 100644
--- a/grub-core/loader/efi/chainloader.c
+++ b/grub-core/loader/efi/chainloader.c
@@ -345,6 +345,8 @@ static const grub_uint16_t machine_type __attribute__((__unused__)) =
GRUB_PE32_MACHINE_I386;
#elif defined(__ia64__)
GRUB_PE32_MACHINE_IA64;
+#elif defined(__loongarch64)
+ GRUB_PE32_MACHINE_LOONGARCH64;
#elif defined(__riscv) && (__riscv_xlen == 32)
GRUB_PE32_MACHINE_RISCV32;
#elif defined(__riscv) && (__riscv_xlen == 64)
diff --git a/grub-core/loader/loongarch64/linux-efi.c b/grub-core/loader/loongarch64/linux-efi.c
new file mode 100644
index 0000000..4dcefd9
--- /dev/null
+++ b/grub-core/loader/loongarch64/linux-efi.c
@@ -0,0 +1,144 @@
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2021 Free Software Foundation, Inc.
+ *
+ * GRUB is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GRUB is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
+ */
+#include <grub/linux.h>
+#include <grub/fdt.h>
+#include <grub/efi/efi.h>
+#include <grub/cpu/linux.h>
+#include <grub/efi/memory.h>
+#include <grub/efi/fdtload.h>
+#include <grub/charset.h>
+
+#define GRUB_EFI_PE_MAGIC 0x5A4D
+
+grub_err_t
+finalize_efi_params_linux (struct linux_loongarch64_kernel_params *kernel_params)
+{
+ int node, retval;
+
+ void *fdt;
+
+ fdt = grub_fdt_load (GRUB_EFI_LINUX_FDT_EXTRA_SPACE);
+
+ if (!fdt)
+ goto failure;
+
+ node = grub_fdt_find_subnode (fdt, 0, "chosen");
+ if (node < 0)
+ node = grub_fdt_add_subnode (fdt, 0, "chosen");
+
+ if (node < 1)
+ goto failure;
+
+ /* Set initrd info */
+ if (kernel_params->ramdisk_addr && kernel_params->ramdisk_size)
+ {
+ grub_dprintf ("linux", "Initrd @ %p-%p\n",
+ (void *) kernel_params->ramdisk_addr,
+ (void *) (kernel_params->ramdisk_addr + kernel_params->ramdisk_size));
+
+ retval = grub_fdt_set_prop64 (fdt, node, "linux,initrd-start",
+ kernel_params->ramdisk_addr);
+ if (retval)
+ goto failure;
+ retval = grub_fdt_set_prop64 (fdt, node, "linux,initrd-end",
+ kernel_params->ramdisk_addr + kernel_params->ramdisk_size);
+ if (retval)
+ goto failure;
+ }
+
+ if (grub_fdt_install() != GRUB_ERR_NONE)
+ goto failure;
+
+ return GRUB_ERR_NONE;
+
+failure:
+ grub_fdt_unload();
+ return grub_error(GRUB_ERR_BAD_OS, "failed to install/update FDT");
+}
+
+grub_err_t
+grub_arch_efi_linux_check_image (struct linux_arch_kernel_header * lh)
+{
+ if ((lh->code0 & 0xffff) == GRUB_EFI_PE_MAGIC)
+ return GRUB_ERR_NONE;
+ else
+ return 1;
+
+ grub_dprintf ("linux", "UEFI stub kernel:\n");
+ grub_dprintf ("linux", "PE/COFF header @ %08x\n", lh->hdr_offset);
+
+ return GRUB_ERR_NONE;
+}
+
+grub_err_t
+grub_arch_efi_linux_boot_image (grub_addr_t addr, grub_size_t size, char *args)
+{
+ grub_efi_memory_mapped_device_path_t *mempath;
+ grub_efi_handle_t image_handle;
+ grub_efi_boot_services_t *b;
+ grub_efi_status_t status;
+ grub_efi_loaded_image_t *loaded_image;
+ int len;
+
+ mempath = grub_malloc (2 * sizeof (grub_efi_memory_mapped_device_path_t));
+ if (!mempath)
+ return grub_errno;
+
+ mempath[0].header.type = GRUB_EFI_HARDWARE_DEVICE_PATH_TYPE;
+ mempath[0].header.subtype = GRUB_EFI_MEMORY_MAPPED_DEVICE_PATH_SUBTYPE;
+ mempath[0].header.length = grub_cpu_to_le16_compile_time (sizeof (*mempath));
+ mempath[0].memory_type = GRUB_EFI_LOADER_DATA;
+ mempath[0].start_address = addr;
+ mempath[0].end_address = addr + size;
+
+ mempath[1].header.type = GRUB_EFI_END_DEVICE_PATH_TYPE;
+ mempath[1].header.subtype = GRUB_EFI_END_ENTIRE_DEVICE_PATH_SUBTYPE;
+ mempath[1].header.length = sizeof (grub_efi_device_path_t);
+
+ b = grub_efi_system_table->boot_services;
+ status = b->load_image (0, grub_efi_image_handle,
+ (grub_efi_device_path_t *) mempath,
+ (void *) addr, size, &image_handle);
+ if (status != GRUB_EFI_SUCCESS)
+ return grub_error (GRUB_ERR_BAD_OS, "cannot load image");
+
+ grub_dprintf ("linux", "linux command line: '%s'\n", args);
+
+ /* Convert command line to UCS-2 */
+ loaded_image = grub_efi_get_loaded_image (image_handle);
+ loaded_image->load_options_size = len =
+ (grub_strlen (args) + 1) * sizeof (grub_efi_char16_t);
+ loaded_image->load_options =
+ grub_efi_allocate_any_pages (GRUB_EFI_BYTES_TO_PAGES (loaded_image->load_options_size));
+ if (!loaded_image->load_options)
+ return grub_errno;
+
+ loaded_image->load_options_size =
+ 2 * grub_utf8_to_utf16 (loaded_image->load_options, len,
+ (grub_uint8_t *) args, len, NULL);
+
+ grub_dprintf ("linux", "starting image %p\n", image_handle);
+ status = b->start_image (image_handle, 0, NULL);
+
+ /* When successful, not reached */
+ b->unload_image (image_handle);
+ grub_efi_free_pages ((grub_addr_t) loaded_image->load_options,
+ GRUB_EFI_BYTES_TO_PAGES (loaded_image->load_options_size));
+
+ return grub_errno;
+}
diff --git a/grub-core/loader/loongarch64/linux-elf.c b/grub-core/loader/loongarch64/linux-elf.c
new file mode 100644
index 0000000..85585b4
--- /dev/null
+++ b/grub-core/loader/loongarch64/linux-elf.c
@@ -0,0 +1,529 @@
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2021 Free Software Foundation, Inc.
+ *
+ * GRUB is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GRUB is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <grub/cpu/linux.h>
+#include <grub/linux.h>
+#include <grub/fdt.h>
+#include <grub/efi/efi.h>
+#include <grub/elfload.h>
+#include <grub/cpu/relocator.h>
+#include <grub/efi/memory.h>
+
+#define GRUB_ADDRESS_TYPE_SYSRAM 1
+#define GRUB_ADDRESS_TYPE_RESERVED 2
+#define GRUB_ADDRESS_TYPE_ACPI 3
+#define GRUB_ADDRESS_TYPE_NVS 4
+#define GRUB_ADDRESS_TYPE_PMEM 5
+#define GRUB_EFI_LOONGSON_BPI_TABLE_GUID \
+ { 0x4660f721, 0x2ec5, 0x416a, \
+ { 0x89, 0x9a, 0x43, 0x18, 0x02, 0x50, 0xa0, 0xc9 } \
+ }
+
+static struct grub_relocator *relocator;
+
+void grub_linux_loongarch_elf_relocator_unload (void)
+{
+ grub_relocator_unload (relocator);
+}
+
+static grub_err_t
+allocate_fdt_and_exit_boot (struct linux_loongarch64_kernel_params *kernel_params)
+{
+ int node, retval;
+ grub_err_t err;
+ unsigned int size;
+ grub_efi_uintn_t mmap_size;
+ grub_efi_uintn_t desc_size;
+ grub_efi_uint32_t desc_version;
+ grub_efi_memory_descriptor_t *mmap_buf;
+
+ size = GRUB_FDT_EMPTY_TREE_SZ + FDT_ADDR_SIZE_EXTRA + GRUB_EFI_LINUX_FDT_EXTRA_SPACE;
+
+ kernel_params->fdt = grub_efi_allocate_any_pages (GRUB_EFI_BYTES_TO_PAGES (size));
+ if (!kernel_params->fdt)
+ return GRUB_ERR_OUT_OF_MEMORY;
+
+ grub_fdt_create_empty_tree (kernel_params->fdt, size);
+ grub_fdt_set_prop32 (kernel_params->fdt, 0, FDT_ADDR_CELLS_STRING, 2);
+ grub_fdt_set_prop32 (kernel_params->fdt, 0, FDT_SIZE_CELLS_STRING, 2);
+
+ node = grub_fdt_find_subnode (kernel_params->fdt, 0, "chosen");
+ if (node < 0)
+ node = grub_fdt_add_subnode (kernel_params->fdt, 0, "chosen");
+ if (node < 1)
+ goto failure;
+
+ grub_dprintf ("loongson", "command_line %s, len %ld\n",
+ (char *)kernel_params->linux_args,
+ grub_strlen(kernel_params->linux_args) + 1);
+ if ((kernel_params->linux_args != NULL) && (grub_strlen(kernel_params->linux_args) > 0)) {
+ retval = grub_fdt_set_prop (kernel_params->fdt, node, "bootargs", kernel_params->linux_args,
+ grub_strlen(kernel_params->linux_args) + 1);
+ if (retval)
+ goto failure;
+ }
+
+ /* Set initrd info */
+ if (kernel_params->ramdisk_addr && kernel_params->ramdisk_size)
+ {
+ grub_dprintf ("linux", "Initrd @ %p-%p\n",
+ (void *) kernel_params->ramdisk_addr,
+ (void *) (kernel_params->ramdisk_addr + kernel_params->ramdisk_size));
+
+ retval = grub_fdt_set_prop64 (kernel_params->fdt, node, "linux,initrd-start",
+ kernel_params->ramdisk_addr);
+ if (retval)
+ goto failure;
+ retval = grub_fdt_set_prop64 (kernel_params->fdt, node, "linux,initrd-end",
+ (grub_uint64_t) (kernel_params->ramdisk_addr + kernel_params->ramdisk_size));
+ if (retval)
+ goto failure;
+ }
+
+ node = grub_fdt_find_subnode (kernel_params->fdt, 0, "chosen");
+ retval = grub_fdt_set_prop64 (kernel_params->fdt, node, "linux,uefi-system-table",
+ (grub_uint64_t)grub_efi_system_table);
+ if (retval)
+ goto failure;
+
+ mmap_size = grub_efi_find_mmap_size ();
+ if (! mmap_size)
+ return grub_errno;
+ mmap_buf = grub_efi_allocate_any_pages (GRUB_EFI_BYTES_TO_PAGES (mmap_size));
+ if (! mmap_buf)
+ return grub_error (GRUB_ERR_IO, "cannot allocate memory map");
+ err = grub_efi_finish_boot_services (&mmap_size, mmap_buf, NULL,
+ &desc_size, &desc_version);
+ if (err)
+ return err;
+
+ if (!mmap_buf || !mmap_size || !desc_size)
+ return GRUB_ERR_BAD_ARGUMENT;
+
+ retval = grub_fdt_set_prop64 (kernel_params->fdt, node, "linux,uefi-mmap-start",
+ (grub_uint64_t)mmap_buf);
+ if (retval)
+ goto failure;
+
+ retval = grub_fdt_set_prop32 (kernel_params->fdt, node, "linux,uefi-mmap-size",
+ mmap_size);
+ if (retval)
+ goto failure;
+
+ retval = grub_fdt_set_prop32 (kernel_params->fdt, node, "linux,uefi-mmap-desc-size",
+ desc_size);
+ if (retval)
+ goto failure;
+
+ retval = grub_fdt_set_prop32 (kernel_params->fdt, node, "linux,uefi-mmap-desc-ver",
+ desc_version);
+ if (retval)
+ goto failure;
+
+ return GRUB_ERR_NONE;
+
+failure:
+ if (!kernel_params->fdt) {
+ return GRUB_ERR_BAD_OS;
+ }
+ grub_efi_free_pages ((grub_addr_t) kernel_params->fdt,
+ GRUB_EFI_BYTES_TO_PAGES (grub_fdt_get_totalsize (kernel_params->fdt)));
+ kernel_params->fdt = NULL;
+ return grub_error(GRUB_ERR_BAD_OS, "failed to install/update FDT");
+}
+
+static void
+grub_linux_loongarch_elf_make_argv (struct linux_loongarch64_kernel_params *kernel_params)
+{
+ static void* linux_args_addr;
+ int size;
+ grub_uint64_t *linux_argv;
+ char *args, *p, *linux_args;
+ int i, argc;
+ grub_err_t err;
+
+ argc = kernel_params->linux_argc;
+ args = kernel_params->linux_args;
+
+ /* new size */
+ p = args;
+ size = (argc + 3 + 1) * sizeof (grub_uint64_t); /* orig arguments */
+ for (i = 0; i < argc; i++)
+ {
+ size += ALIGN_UP (grub_strlen (p) + 1, 4);
+ p += grub_strlen (p) + 1;
+ }
+
+ if (kernel_params->ramdisk_addr && kernel_params->ramdisk_size)
+ {
+ size += ALIGN_UP (sizeof ("rd_start=0xXXXXXXXXXXXXXXXX"), 4) \
+ + ALIGN_UP (sizeof ("rd_size=0xXXXXXXXXXXXXXXXX"), 4) \
+ + ALIGN_UP (sizeof ("initrd=0xXXXXXXXXXXXXXXXX,0xXXXXXXXXXXXXXXXX"),
+ 4);
+ }
+ size = ALIGN_UP (size, 8);
+
+ /* alloc memory */
+ linux_args_addr = grub_linux_loongarch_alloc_virtual_mem_align (size, 8, &err);
+
+ linux_argv = linux_args_addr;
+ linux_args = (char *)(linux_argv + (argc + 1 + 3));
+ p = args;
+ for (i = 0; i < argc; i++)
+ {
+ grub_memcpy (linux_args, p, grub_strlen (p) + 1);
+ *linux_argv = (grub_uint64_t) (grub_addr_t) linux_args;
+ linux_argv++;
+ linux_args += ALIGN_UP (grub_strlen (p) + 1, 4);
+ p += grub_strlen (p) + 1;
+ }
+
+ if (kernel_params->ramdisk_addr && kernel_params->ramdisk_size)
+ {
+ /* rd_start */
+ grub_snprintf (linux_args,
+ sizeof ("rd_start=0xXXXXXXXXXXXXXXXX"),
+ "rd_start=0x%lx",
+ (grub_uint64_t) kernel_params->ramdisk_addr);
+ *linux_argv = (grub_uint64_t) (grub_addr_t) linux_args;
+ linux_argv++;
+ linux_args += ALIGN_UP (sizeof ("rd_start=0xXXXXXXXXXXXXXXXX"), 4);
+ kernel_params->linux_argc++;
+
+ /* rd_size */
+ grub_snprintf (linux_args,
+ sizeof ("rd_size=0xXXXXXXXXXXXXXXXX"),
+ "rd_size=0x%lx",
+ (grub_uint64_t) kernel_params->ramdisk_size);
+ *linux_argv = (grub_uint64_t) (grub_addr_t) linux_args;
+ linux_argv++;
+ linux_args += ALIGN_UP (sizeof ("rd_size=0xXXXXXXXXXXXXXXXX"), 4);
+ kernel_params->linux_argc++;
+
+ /* initrd */
+ grub_snprintf (linux_args,
+ sizeof ("initrd=0xXXXXXXXXXXXXXXXX,0xXXXXXXXXXXXXXXXX"),
+ "initrd=0x%lx,0x%lx",
+ ((grub_uint64_t) kernel_params->ramdisk_addr & 0xffffffff),
+ (grub_uint64_t) kernel_params->ramdisk_size);
+ *linux_argv = (grub_uint64_t) (grub_addr_t) linux_args;
+ linux_argv++;
+ linux_args += ALIGN_UP (sizeof ("initrd=0xXXXXXXXXXXXXXXXX,0xXXXXXXXXXXXXXXXX"), 4);
+ kernel_params->linux_argc++;
+ }
+
+ /* Reserve space for initrd arguments. */
+ *linux_argv = 0;
+
+ grub_free (kernel_params->linux_args);
+ kernel_params->linux_argv = (grub_addr_t) linux_args_addr;
+}
+
+grub_err_t
+grub_linux_loongarch_elf_linux_boot_image (struct linux_loongarch64_kernel_params
+ *kernel_params)
+{
+ struct boot_params_interface *boot_params = NULL;
+ struct grub_relocator64_state state;
+ grub_err_t err;
+
+ /* linux kernel type is ELF */
+ grub_memset (&state, 0, sizeof (state));
+
+ state.jumpreg = 1;
+ state.gpr[1] = kernel_params->kernel_addr; /* ra */
+ if (grub_linux_loongarch_elf_get_boot_params (&boot_params) == 0)
+ {
+ grub_printf("not find param, is fdt boot\n");
+ if (allocate_fdt_and_exit_boot (kernel_params) != GRUB_ERR_NONE)
+ return grub_errno;
+ state.gpr[4] = 1 << FLAGS_EFI_SUPPORT_BIT; /* a0 = flag */
+ state.gpr[5] = (grub_uint64_t)kernel_params->fdt; /* a1 = fdt */
+ state.gpr[6] = 0; /* a2 = flag */
+ } else {
+ grub_printf("find param, is bpi boot\n");
+ grub_linux_loongarch_elf_make_argv (kernel_params);
+ state.gpr[4] = kernel_params->linux_argc; /* a0 = argc */
+ state.gpr[5] = kernel_params->linux_argv; /* a1 = args */
+ state.gpr[6] = (grub_uint64_t) boot_params; /* a2 = envp */
+ err = grub_linux_loongarch_elf_boot_params (boot_params);
+ if (err)
+ return err;
+ }
+
+ /* Boot the ELF kernel */
+ grub_relocator64_boot (relocator, state);
+
+ return GRUB_ERR_NONE;
+}
+
+void*
+grub_linux_loongarch_alloc_virtual_mem_addr (grub_addr_t addr,
+ grub_size_t size,
+ grub_err_t *err)
+{
+ relocator = grub_relocator_new ();
+ if (!relocator)
+ return NULL;
+
+ grub_relocator_chunk_t ch;
+ *err = grub_relocator_alloc_chunk_addr (relocator, &ch,
+ grub_vtop ((void *) addr),
+ size);
+ if (*err)
+ return NULL;
+ return get_virtual_current_address (ch);
+}
+
+void*
+grub_linux_loongarch_alloc_virtual_mem_align (grub_size_t size,
+ grub_size_t align,
+ grub_err_t *err)
+{
+ grub_relocator_chunk_t ch;
+
+ *err = grub_relocator_alloc_chunk_align (relocator, &ch,
+ 0, (0xffffffff - size) + 1,
+ size, align,
+ GRUB_RELOCATOR_PREFERENCE_LOW, 0);
+ return get_virtual_current_address (ch);
+}
+
+int
+grub_linux_loongarch_elf_get_boot_params (struct boot_params_interface **boot_params)
+{
+ grub_efi_configuration_table_t *tables;
+ grub_efi_guid_t bpi_guid = GRUB_EFI_LOONGSON_BPI_TABLE_GUID;
+ unsigned int i;
+ int found = 0;
+
+ /* Look for Loongson BPI in UEFI config tables. */
+ tables = grub_efi_system_table->configuration_table;
+
+ for (i = 0; i < grub_efi_system_table->num_table_entries; i++)
+ if (grub_memcmp (&tables[i].vendor_guid, &bpi_guid, sizeof (bpi_guid)) == 0)
+ {
+ *boot_params = tables[i].vendor_table;
+ char *p = (char*) &((*boot_params)->signature);
+ if (grub_strncmp (p, "BPI", 3) == 0)
+ {
+ found = 1;
+ break;
+ }
+ }
+ return found;
+}
+
+static grub_uint8_t
+grub_kernel_update_checksum (const grub_uint8_t *buffer, grub_efi_uintn_t length)
+{
+ grub_uint8_t sum;
+ grub_efi_uintn_t count;
+
+ for (sum = 0, count = 0; count < length; count++)
+ {
+ sum = (grub_uint8_t) (sum + *(buffer + count));
+ }
+
+ return (grub_uint8_t) (0x100 - sum);
+}
+
+static grub_uint32_t
+grub_efi_loongarch64_memmap_sort (struct memmap array[],
+ grub_uint32_t length,
+ struct loongsonlist_mem_map* bpmem,
+ grub_uint32_t index,
+ grub_uint32_t memtype)
+{
+ grub_uint64_t tempmemsize = 0;
+ grub_uint32_t j = 0;
+ grub_uint32_t t = 0;
+
+ for(j = 0; j < length;)
+ {
+ tempmemsize = array[j].mem_size;
+ for(t = j + 1; t < length; t++)
+ {
+ if(array[j].mem_start + tempmemsize == array[t].mem_start)
+ {
+ tempmemsize += array[t].mem_size;
+ }
+ else
+ {
+ break;
+ }
+ }
+ bpmem->map[index].mem_type = memtype;
+ bpmem->map[index].mem_start = array[j].mem_start;
+ bpmem->map[index].mem_size = tempmemsize;
+ grub_printf("map[%d]:type %"PRIuGRUB_UINT32_T", start 0x%"
+ PRIxGRUB_UINT64_T", end 0x%"PRIxGRUB_UINT64_T"\n",
+ index,
+ bpmem->map[index].mem_type,
+ bpmem->map[index].mem_start,
+ bpmem->map[index].mem_start+ bpmem->map[index].mem_size
+ );
+ j = t;
+ index++;
+ }
+ return index;
+}
+
+grub_err_t
+grub_linux_loongarch_elf_boot_params (struct boot_params_interface *boot_params)
+{
+ grub_int8_t checksum = 0;
+ grub_err_t err;
+
+ struct loongsonlist_mem_map *loongson_mem_map = NULL;
+ struct _extention_list_hdr * listpointer = NULL;
+ grub_uint32_t tmp_index = 0;
+ grub_efi_memory_descriptor_t * lsdesc = NULL;
+
+ grub_uint32_t free_index = 0;
+ grub_uint32_t reserve_index = 0;
+ grub_uint32_t acpi_table_index = 0;
+ grub_uint32_t acpi_nvs_index = 0;
+
+ grub_efi_uintn_t mmap_size;
+ grub_efi_uintn_t desc_size;
+ grub_efi_memory_descriptor_t *mmap_buf;
+
+ struct memmap reserve_mem[GRUB_LOONGSON3_BOOT_MEM_MAP_MAX];
+ struct memmap free_mem[GRUB_LOONGSON3_BOOT_MEM_MAP_MAX];
+ struct memmap acpi_table_mem[GRUB_LOONGSON3_BOOT_MEM_MAP_MAX];
+ struct memmap acpi_nvs_mem[GRUB_LOONGSON3_BOOT_MEM_MAP_MAX];
+
+ grub_memset (reserve_mem, 0, sizeof(struct memmap) * GRUB_LOONGSON3_BOOT_MEM_MAP_MAX);
+ grub_memset (free_mem, 0, sizeof(struct memmap) * GRUB_LOONGSON3_BOOT_MEM_MAP_MAX);
+ grub_memset (acpi_table_mem, 0, sizeof(struct memmap) * GRUB_LOONGSON3_BOOT_MEM_MAP_MAX);
+ grub_memset (acpi_nvs_mem, 0, sizeof(struct memmap) * GRUB_LOONGSON3_BOOT_MEM_MAP_MAX);
+
+ /* Check extlist headers */
+ listpointer = boot_params->extlist;
+ for( ;listpointer != NULL; listpointer = listpointer->next)
+ {
+ char *pl= (char *)&(listpointer->signature);
+ if(grub_strncmp(pl, "MEM", 3) == 0)
+ {
+ loongson_mem_map = (struct loongsonlist_mem_map *)listpointer;
+ break;
+ }
+ }
+
+ mmap_size = grub_efi_find_mmap_size ();
+ if (! mmap_size)
+ return grub_errno;
+ mmap_buf = grub_efi_allocate_any_pages (GRUB_EFI_BYTES_TO_PAGES (mmap_size));
+ if (! mmap_buf)
+ return grub_error (GRUB_ERR_IO, "cannot allocate memory map");
+
+ err = grub_efi_finish_boot_services (&mmap_size, mmap_buf, NULL,
+ &desc_size, NULL);
+ if (err)
+ return err;
+
+ if (!mmap_buf || !mmap_size || !desc_size)
+ return -1;
+
+ /*
+ According to UEFI SPEC,mmap_buf is the accurate Memory Map array \
+ now we can fill platform specific memory structure.
+ */
+ for (lsdesc = mmap_buf; lsdesc < (grub_efi_memory_descriptor_t *)((char *)mmap_buf + mmap_size);
+ lsdesc = (grub_efi_memory_descriptor_t *)((char *)lsdesc + desc_size))
+ {
+ /* System RAM */
+ if((lsdesc->type != GRUB_EFI_ACPI_RECLAIM_MEMORY) && \
+ (lsdesc->type != GRUB_EFI_ACPI_MEMORY_NVS) && \
+ (lsdesc->type != GRUB_EFI_RUNTIME_SERVICES_DATA) && \
+ (lsdesc->type != GRUB_EFI_RUNTIME_SERVICES_CODE) && \
+ (lsdesc->type != GRUB_EFI_RESERVED_MEMORY_TYPE) && \
+ (lsdesc->type != GRUB_EFI_PAL_CODE))
+ {
+ free_mem[free_index].mem_type = GRUB_ADDRESS_TYPE_SYSRAM;
+ free_mem[free_index].mem_start = (lsdesc->physical_start) & GRUB_EFI_MAX_PHY_ADDRESS;
+ free_mem[free_index].mem_size = lsdesc->num_pages * GRUB_EFI_PAGE_SIZE;
+ free_index++;
+
+ /*ACPI*/
+ }else if((lsdesc->type == GRUB_EFI_ACPI_RECLAIM_MEMORY)){
+ acpi_table_mem[acpi_table_index].mem_type = GRUB_ADDRESS_TYPE_ACPI;
+ acpi_table_mem[acpi_table_index].mem_start = (lsdesc->physical_start) & GRUB_EFI_MAX_PHY_ADDRESS;
+ acpi_table_mem[acpi_table_index].mem_size = lsdesc->num_pages * GRUB_EFI_PAGE_SIZE;
+ acpi_table_index++;
+ }else if((lsdesc->type == GRUB_EFI_ACPI_MEMORY_NVS)){
+ acpi_nvs_mem[acpi_nvs_index].mem_type = GRUB_ADDRESS_TYPE_NVS;
+ acpi_nvs_mem[acpi_nvs_index].mem_start = (lsdesc->physical_start) & GRUB_EFI_MAX_PHY_ADDRESS;
+ acpi_nvs_mem[acpi_nvs_index].mem_size = lsdesc->num_pages * GRUB_EFI_PAGE_SIZE;
+ acpi_nvs_index++;
+
+ /* Reserve */
+ }else{
+ reserve_mem[reserve_index].mem_type = GRUB_ADDRESS_TYPE_RESERVED;
+ reserve_mem[reserve_index].mem_start = (lsdesc->physical_start) & GRUB_EFI_MAX_PHY_ADDRESS;
+ reserve_mem[reserve_index].mem_size = lsdesc->num_pages * GRUB_EFI_PAGE_SIZE;
+ reserve_index++;
+ }
+ }
+
+ tmp_index = loongson_mem_map->map_count;
+ /*System RAM Sort*/
+ tmp_index = grub_efi_loongarch64_memmap_sort(free_mem,
+ free_index,
+ loongson_mem_map,
+ tmp_index,
+ GRUB_ADDRESS_TYPE_SYSRAM);
+ /*ACPI Sort*/
+ tmp_index = grub_efi_loongarch64_memmap_sort(acpi_table_mem,
+ acpi_table_index,
+ loongson_mem_map,
+ tmp_index,
+ GRUB_ADDRESS_TYPE_ACPI);
+ tmp_index = grub_efi_loongarch64_memmap_sort(acpi_nvs_mem,
+ acpi_nvs_index,
+ loongson_mem_map,
+ tmp_index,
+ GRUB_ADDRESS_TYPE_NVS);
+
+ /*Reserve Sort*/
+ {
+ grub_uint64_t loongarch_addr;
+ asm volatile ("csrrd %0, 0x181" : "=r" (loongarch_addr));
+ if ((loongarch_addr & 0xff00000000000000) == 0x9000000000000000)
+ tmp_index = grub_efi_loongarch64_memmap_sort(reserve_mem,
+ reserve_index,
+ loongson_mem_map,
+ tmp_index,
+ GRUB_ADDRESS_TYPE_RESERVED);
+ else
+ tmp_index = grub_efi_loongarch64_memmap_sort(reserve_mem,
+ reserve_index,
+ loongson_mem_map,
+ tmp_index,
+ GRUB_ADDRESS_TYPE_RESERVED + 1);
+ }
+ loongson_mem_map->map_count = tmp_index;
+ loongson_mem_map->header.checksum = 0;
+
+ checksum = grub_kernel_update_checksum ((grub_uint8_t *) loongson_mem_map,
+ loongson_mem_map->header.length);
+ loongson_mem_map->header.checksum = checksum;
+
+ return grub_errno;
+}
diff --git a/grub-core/loader/loongarch64/linux.c b/grub-core/loader/loongarch64/linux.c
new file mode 100644
index 0000000..783054b
--- /dev/null
+++ b/grub-core/loader/loongarch64/linux.c
@@ -0,0 +1,398 @@
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2021 Free Software Foundation, Inc.
+ *
+ * GRUB is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GRUB is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <grub/loader.h>
+#include <grub/misc.h>
+#include <grub/command.h>
+#include <grub/i18n.h>
+#include <grub/lib/cmdline.h>
+#include <grub/linux.h>
+#include <grub/cpu/linux.h>
+#include <grub/efi/memory.h>
+
+GRUB_MOD_LICENSE ("GPLv3+");
+
+#define INITRD_MAX_ADDRESS_OFFSET (32ULL * 1024 * 1024 * 1024)
+
+static struct linux_loongarch64_kernel_params kernel_params;
+
+static grub_addr_t phys_addr;
+static grub_dl_t my_mod;
+static int loaded;
+static int is_bpi_boot;
+static int grub_loongarch_linux_type = GRUB_LOONGARCH_LINUX_BAD;
+
+static grub_err_t
+grub_linux_boot (void)
+{
+
+ if (grub_loongarch_linux_type == GRUB_LOONGARCH_LINUX_EFI) {
+ if (finalize_efi_params_linux (&kernel_params) != GRUB_ERR_NONE)
+ return grub_errno;
+ return (grub_arch_efi_linux_boot_image((grub_addr_t) kernel_params.kernel_addr,
+ kernel_params.kernel_size,
+ kernel_params.linux_args));
+ }
+ if (grub_loongarch_linux_type == GRUB_LOONGARCH_LINUX_ELF) {
+ return grub_linux_loongarch_elf_linux_boot_image (&kernel_params);
+ }
+
+ return GRUB_ERR_NONE;
+}
+
+static grub_err_t
+grub_linux_unload (void)
+{
+
+ if (grub_loongarch_linux_type == GRUB_LOONGARCH_LINUX_EFI) {
+ if (kernel_params.ramdisk_addr)
+ grub_efi_free_pages ((grub_efi_physical_address_t) kernel_params.ramdisk_addr,
+ GRUB_EFI_BYTES_TO_PAGES (kernel_params.ramdisk_size));
+ kernel_params.ramdisk_size = 0;
+
+ if (kernel_params.kernel_addr)
+ grub_efi_free_pages ((grub_addr_t) kernel_params.kernel_addr,
+ GRUB_EFI_BYTES_TO_PAGES (kernel_params.kernel_size));
+ kernel_params.kernel_addr = 0;
+ }
+
+ if (grub_loongarch_linux_type == GRUB_LOONGARCH_LINUX_ELF) {
+ grub_free (kernel_params.linux_args);
+ kernel_params.linux_args = 0;
+ grub_linux_loongarch_elf_relocator_unload ();
+ }
+
+ grub_dl_unref (my_mod);
+ loaded = 0;
+ grub_loongarch_linux_type = GRUB_LOONGARCH_LINUX_BAD;
+
+ return GRUB_ERR_NONE;
+}
+
+grub_err_t
+grub_linux_loongarch_elf_load_kernel (grub_elf_t elf, const char *filename)
+{
+ Elf64_Addr base;
+ grub_err_t err;
+ grub_uint8_t *playground;
+ grub_uint64_t addr;
+ int flag;
+
+ /* Linux's entry point incorrectly contains a virtual address. */
+ kernel_params.kernel_addr = elf->ehdr.ehdr64.e_entry;
+ kernel_params.kernel_size = grub_elf64_size (elf, &base, 0);
+
+ if (kernel_params.kernel_size == 0)
+ return grub_errno;
+
+ phys_addr = base;
+ kernel_params.kernel_size = ALIGN_UP (base + kernel_params.kernel_size - base, 8);
+
+ asm volatile ("csrrd %0, 0x181" : "=r" (addr));
+ if (addr & 0x1) {
+ flag = GRUB_ELF_LOAD_FLAGS_NONE;
+ } else {
+ flag = GRUB_ELF_LOAD_FLAGS_30BITS;
+ base &= ~ELF64_LOADMASK;
+ kernel_params.kernel_addr &= ~ELF64_LOADMASK;
+ }
+
+ playground = grub_linux_loongarch_alloc_virtual_mem_addr (phys_addr,
+ kernel_params.kernel_size,
+ &err);
+ if (playground == NULL)
+ return err;
+
+ /* Now load the segments into the area we claimed. */
+ return grub_elf64_load (elf, filename, playground - base,
+ flag, 0, 0);
+}
+
+static grub_err_t
+grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
+ int argc, char *argv[])
+{
+ grub_file_t file = 0;
+ struct linux_arch_kernel_header lh;
+ struct boot_params_interface *boot_params = NULL;
+ grub_elf_t elf = NULL;
+ grub_err_t err;
+ grub_size_t cmdline_size;
+ int i;
+
+ grub_dl_ref (my_mod);
+
+ /* Release the previously used memory. */
+ grub_loader_unset ();
+
+ if (argc == 0)
+ {
+ grub_error (GRUB_ERR_BAD_ARGUMENT, N_("filename expected"));
+ goto fail;
+ }
+
+ file = grub_file_open (argv[0], GRUB_FILE_TYPE_LINUX_KERNEL);
+ if (!file)
+ goto fail;
+
+ kernel_params.kernel_size = grub_file_size (file);
+ grub_dprintf ("linux", "kernel file size: %" PRIuGRUB_SIZE "\n",
+ kernel_params.kernel_size);
+
+ if (grub_file_read (file, &lh, sizeof (lh)) < (long) sizeof (lh))
+ return grub_errno;
+
+ if (grub_arch_efi_linux_check_image (&lh) == GRUB_ERR_NONE) {
+ grub_loongarch_linux_type = GRUB_LOONGARCH_LINUX_EFI;
+ }
+
+ if (grub_loongarch_linux_type != GRUB_LOONGARCH_LINUX_EFI) {
+ elf = grub_elf_file (file, argv[0]);
+ if (elf != NULL)
+ {
+ /* linux kernel type is ELF */
+ grub_loongarch_linux_type = GRUB_LOONGARCH_LINUX_ELF;
+ if (elf->ehdr.ehdr64.e_type != ET_EXEC)
+ {
+ grub_error (GRUB_ERR_UNKNOWN_OS,
+ N_("this ELF file is not of the right type"));
+ goto fail;
+ }
+ if (elf->ehdr.ehdr64.e_machine != EM_LOONGARCH)
+ {
+ grub_error (GRUB_ERR_BAD_OS, "invalid magic number");
+ goto fail;
+ }
+
+ if (grub_elf_is_elf64 (elf))
+ {
+ err = grub_linux_loongarch_elf_load_kernel (elf, argv[0]);
+ if (err)
+ goto fail;
+ } else {
+ grub_error (GRUB_ERR_BAD_OS, N_("invalid arch-dependent ELF magic"));
+ goto fail;
+ }
+ grub_dprintf ("linux", "kernel @ %p\n", (void*) elf->ehdr.ehdr64.e_entry);
+ }
+ } else {
+ if (grub_file_seek (file, 0) == (grub_off_t) -1)
+ goto fail;
+
+ if (grub_file_read (file, &lh, sizeof (lh)) < (grub_ssize_t) sizeof (lh))
+ {
+ if (!grub_errno)
+ grub_error (GRUB_ERR_BAD_OS, N_("premature end of file %s"),
+ argv[0]);
+ goto fail;
+ }
+
+ if (grub_arch_efi_linux_check_image (&lh) != GRUB_ERR_NONE)
+ {
+ goto fail;
+ }
+ /* linux kernel type is EFI */
+ grub_loongarch_linux_type = GRUB_LOONGARCH_LINUX_EFI;
+ kernel_params.kernel_addr = (grub_addr_t) grub_efi_allocate_any_pages (
+ GRUB_EFI_BYTES_TO_PAGES (kernel_params.kernel_size));
+ grub_dprintf ("linux", "kernel numpages: %" PRIuGRUB_SIZE "\n",
+ GRUB_EFI_BYTES_TO_PAGES (kernel_params.kernel_size));
+ if (!kernel_params.kernel_addr)
+ {
+ grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("out of memory"));
+ goto fail;
+ }
+
+ grub_file_seek (file, 0);
+ if (grub_file_read (file, (void*) kernel_params.kernel_addr, kernel_params.kernel_size)
+ < (grub_int64_t) kernel_params.kernel_size)
+ {
+ if (!grub_errno)
+ grub_error (GRUB_ERR_BAD_OS, N_("premature end of file %s"), argv[0]);
+ goto fail;
+ }
+
+ grub_dprintf ("linux", "kernel @ %p\n", (void*) kernel_params.kernel_addr);
+ }
+
+ cmdline_size = grub_loader_cmdline_size (argc, argv) + sizeof (LINUX_IMAGE);
+ kernel_params.linux_argc = argc;
+ kernel_params.linux_args = grub_malloc (cmdline_size);
+ if (!kernel_params.linux_args)
+ {
+ grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("out of memory"));
+ goto fail;
+ }
+
+ grub_memcpy (kernel_params.linux_args, LINUX_IMAGE, sizeof (LINUX_IMAGE));
+
+ if (grub_linux_loongarch_elf_get_boot_params (&boot_params) == 1)
+ is_bpi_boot = 1;
+ else
+ is_bpi_boot = 0;
+
+ if (is_bpi_boot == 0)
+ {
+ err = grub_create_loader_cmdline (argc, argv,
+ (char*) ((grub_addr_t) kernel_params.linux_args + sizeof (LINUX_IMAGE) - 1),
+ cmdline_size,
+ GRUB_VERIFY_KERNEL_CMDLINE);
+ if (err)
+ goto fail;
+ } else {
+ /* save args from linux cmdline */
+ char *p = kernel_params.linux_args;
+
+ p += sizeof (LINUX_IMAGE) - 1;
+ for (i=0; i < argc; i++)
+ {
+ grub_memcpy (p, argv[i], grub_strlen(argv[i]) + 1);
+ p += grub_strlen(argv[i]) + 1;
+ }
+ }
+
+ if (grub_errno == GRUB_ERR_NONE)
+ {
+ grub_loader_set (grub_linux_boot, grub_linux_unload, 0);
+ loaded = 1;
+ }
+
+fail:
+ if (elf != NULL) {
+ /* grub_elf_close will call grub_file_close() */
+ grub_elf_close (elf);
+ } else {
+ if (file)
+ grub_file_close (file);
+ }
+
+ if (grub_errno != GRUB_ERR_NONE)
+ {
+ grub_dl_unref (my_mod);
+ loaded = 0;
+ }
+
+ if (kernel_params.linux_args && !loaded)
+ grub_free (kernel_params.linux_args);
+
+ if (grub_loongarch_linux_type == GRUB_LOONGARCH_LINUX_EFI) {
+ if (kernel_params.kernel_addr && !loaded)
+ grub_efi_free_pages ((grub_addr_t) kernel_params.kernel_addr,
+ GRUB_EFI_BYTES_TO_PAGES (kernel_params.kernel_size));
+ }
+
+ return grub_errno;
+}
+
+/*
+ * This function returns a pointer to a legally allocated initrd buffer,
+ * or NULL if unsuccessful
+ */
+static void *
+allocate_initrd_mem (int initrd_pages)
+{
+ grub_addr_t max_addr;
+
+ if (grub_efi_get_ram_base (&max_addr) != GRUB_ERR_NONE)
+ return NULL;
+
+ max_addr += INITRD_MAX_ADDRESS_OFFSET - 1;
+
+ return grub_efi_allocate_pages_real (max_addr, initrd_pages,
+ GRUB_EFI_ALLOCATE_MAX_ADDRESS,
+ GRUB_EFI_LOADER_DATA);
+}
+
+
+static grub_err_t
+grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)),
+ int argc, char *argv[])
+{
+ struct grub_linux_initrd_context initrd_ctx = { 0, 0, 0 };
+ grub_size_t initrd_size;
+ void *initrd_mem = NULL;
+
+ if (argc == 0)
+ {
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("filename expected"));
+ goto fail;
+ }
+
+ if (!loaded)
+ {
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("you need to load the kernel first"));
+ goto fail;
+ }
+
+ if (grub_initrd_init (argc, argv, &initrd_ctx))
+ goto fail;
+
+ initrd_size = grub_get_initrd_size (&initrd_ctx);
+ grub_dprintf ("linux", "Loading initrd\n");
+
+ if (is_bpi_boot == 0) {
+ grub_size_t initrd_pages;
+ initrd_pages = (GRUB_EFI_BYTES_TO_PAGES (initrd_size));
+ initrd_mem = allocate_initrd_mem (initrd_pages);
+ } else {
+ grub_err_t err;
+ initrd_mem = grub_linux_loongarch_alloc_virtual_mem_align (initrd_size, 0x10000, &err);
+ if (err)
+ goto fail;
+ }
+
+ if (!initrd_mem)
+ {
+ grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("out of memory"));
+ goto fail;
+ }
+
+ if (grub_initrd_load (&initrd_ctx, argv, initrd_mem))
+ goto fail;
+
+ /* save ramdisk addr and size */
+ kernel_params.ramdisk_addr = (grub_addr_t) initrd_mem;
+ kernel_params.ramdisk_size = initrd_size;
+ grub_dprintf ("linux", "ramdisk [addr=%p, size=0x%lx]\n",
+ (void *) initrd_mem, initrd_size);
+fail:
+ grub_initrd_close (&initrd_ctx);
+ if (is_bpi_boot == 0) {
+ if (initrd_mem && !kernel_params.ramdisk_addr)
+ grub_efi_free_pages ((grub_addr_t) initrd_mem,
+ GRUB_EFI_BYTES_TO_PAGES (initrd_size));
+ }
+ return grub_errno;
+}
+
+static grub_command_t cmd_linux, cmd_initrd;
+
+GRUB_MOD_INIT(linux)
+{
+ cmd_linux = grub_register_command ("linux", grub_cmd_linux,
+ N_("FILE [ARGS...]"), N_("Load Linux."));
+ cmd_initrd = grub_register_command ("initrd", grub_cmd_initrd,
+ N_("FILE"), N_("Load initrd."));
+ my_mod = mod;
+}
+
+GRUB_MOD_FINI(linux)
+{
+ grub_unregister_command (cmd_linux);
+ grub_unregister_command (cmd_initrd);
+}
diff --git a/include/grub/efi/api.h b/include/grub/efi/api.h
index f431f49..a74ce39 100644
--- a/include/grub/efi/api.h
+++ b/include/grub/efi/api.h
@@ -2104,7 +2104,7 @@ typedef struct grub_efi_ip6_config_manual_address grub_efi_ip6_config_manual_add
#if (GRUB_TARGET_SIZEOF_VOID_P == 4) || defined (__ia64__) \
|| defined (__aarch64__) || defined (__MINGW64__) || defined (__CYGWIN__) \
- || defined(__riscv)
+ || defined(__riscv) || defined (__loongarch64)
#define efi_call_0(func) func()
#define efi_call_1(func, a) func(a)
diff --git a/include/grub/efi/efi.h b/include/grub/efi/efi.h
index 8dfc89a..c816359 100644
--- a/include/grub/efi/efi.h
+++ b/include/grub/efi/efi.h
@@ -135,13 +135,17 @@ extern void (*EXPORT_VAR(grub_efi_net_config)) (grub_efi_handle_t hnd,
char **device,
char **path);
-#if defined(__arm__) || defined(__aarch64__) || defined(__riscv)
+#if defined(__arm__) || defined(__aarch64__) || defined(__riscv) || defined(__loongarch__)
void *EXPORT_FUNC(grub_efi_get_firmware_fdt)(void);
grub_err_t EXPORT_FUNC(grub_efi_get_ram_base)(grub_addr_t *);
#include <grub/cpu/linux.h>
grub_err_t grub_arch_efi_linux_check_image(struct linux_arch_kernel_header *lh);
+#if defined(__loongarch__)
+grub_err_t grub_arch_efi_linux_boot_image(grub_addr_t addr, grub_size_t size, char *args);
+#else
grub_err_t grub_arch_efi_linux_boot_image(grub_addr_t addr, char *args);
#endif
+#endif
grub_addr_t grub_efi_section_addr (const char *section);
diff --git a/include/grub/efi/pe32.h b/include/grub/efi/pe32.h
index a43adf2..f8f2402 100644
--- a/include/grub/efi/pe32.h
+++ b/include/grub/efi/pe32.h
@@ -79,6 +79,8 @@ struct grub_pe32_coff_header
#define GRUB_PE32_MACHINE_ARM64 0xAA64
#define GRUB_PE32_MACHINE_RISCV32 0x5032
#define GRUB_PE32_MACHINE_RISCV64 0x5064
+#define GRUB_PE32_MACHINE_LOONGARCH32 0x6232
+#define GRUB_PE32_MACHINE_LOONGARCH64 0x6264
#define GRUB_PE32_RELOCS_STRIPPED 0x0001
#define GRUB_PE32_EXECUTABLE_IMAGE 0x0002
@@ -338,6 +340,8 @@ struct grub_pe32_fixup_block
#define GRUB_PE32_REL_BASED_ARM_MOV32T 7
#define GRUB_PE32_REL_BASED_RISCV_LOW12I 7
#define GRUB_PE32_REL_BASED_RISCV_LOW12S 8
+#define GRUB_PE32_REL_BASED_LOONGARCH32_MARK_LA 8
+#define GRUB_PE32_REL_BASED_LOONGARCH64_MARK_LA 8
#define GRUB_PE32_REL_BASED_IA64_IMM64 9
#define GRUB_PE32_REL_BASED_DIR64 10
#define GRUB_PE32_REL_BASED_HIGH3ADJ 11
diff --git a/include/grub/elf.h b/include/grub/elf.h
index c478933..73175bd 100644
--- a/include/grub/elf.h
+++ b/include/grub/elf.h
@@ -248,6 +248,7 @@ typedef struct
#define EM_NUM 95
#define EM_AARCH64 183 /* ARM 64-bit architecture */
#define EM_RISCV 243 /* RISC-V */
+#define EM_LOONGARCH 258 /* LoongArch */
/* If it is necessary to assign new unofficial EM_* values, please
pick large random numbers (0x8523, 0xa7f2, etc.) to minimize the
@@ -2531,6 +2532,35 @@ typedef Elf32_Addr Elf32_Conflict;
#define R_RISCV_SET32 56
#define R_RISCV_32_PCREL 57
+/* LoongArch relocations */
+#define R_LARCH_NONE 0
+#define R_LARCH_64 2
+#define R_LARCH_MARK_LA 20
+#define R_LARCH_SOP_PUSH_PCREL 22
+#define R_LARCH_SOP_PUSH_ABSOLUTE 23
+#define R_LARCH_SOP_PUSH_PLT_PCREL 29
+#define R_LARCH_SOP_SUB 32
+#define R_LARCH_SOP_SL 33
+#define R_LARCH_SOP_SR 34
+#define R_LARCH_SOP_ADD 35
+#define R_LARCH_SOP_AND 36
+#define R_LARCH_SOP_IF_ELSE 37
+#define R_LARCH_SOP_POP_32_S_10_5 38
+#define R_LARCH_SOP_POP_32_U_10_12 39
+#define R_LARCH_SOP_POP_32_S_10_12 40
+#define R_LARCH_SOP_POP_32_S_10_16 41
+#define R_LARCH_SOP_POP_32_S_10_16_S2 42
+#define R_LARCH_SOP_POP_32_S_5_20 43
+#define R_LARCH_SOP_POP_32_S_0_5_10_16_S2 44
+#define R_LARCH_SOP_POP_32_S_0_10_10_16_S2 45
+#define R_LARCH_B26 66
+#define R_LARCH_ABS_HI20 67
+#define R_LARCH_ABS_LO12 68
+#define R_LARCH_ABS64_LO20 69
+#define R_LARCH_ABS64_HI12 70
+#define R_LARCH_PCALA_HI20 71
+#define R_LARCH_PCALA_LO12 72
+
#ifdef GRUB_TARGET_WORDSIZE
#if GRUB_TARGET_WORDSIZE == 32
diff --git a/include/grub/fdt.h b/include/grub/fdt.h
index 3514aa4..ba2f9a9 100644
--- a/include/grub/fdt.h
+++ b/include/grub/fdt.h
@@ -20,7 +20,7 @@
#define GRUB_FDT_HEADER 1
#if !defined(GRUB_MACHINE_EMU) && \
- (defined(__arm__) || defined(__aarch64__) || defined(__riscv))
+ (defined(__arm__) || defined(__aarch64__) || defined(__riscv) || defined(__loongarch__))
#include <grub/types.h>
#include <grub/symbol.h>
@@ -148,6 +148,6 @@ int EXPORT_FUNC(grub_fdt_set_prop) (void *fdt, unsigned int nodeoffset, const ch
})
#endif /* !defined(GRUB_MACHINE_EMU) && \
- (defined(__arm__) || defined(__aarch64__) || defined(__riscv)) */
+ (defined(__arm__) || defined(__aarch64__) || defined(__riscv) || defined(__loongarch__)) */
#endif /* ! GRUB_FDT_HEADER */
diff --git a/include/grub/loongarch64/efi/loader.h b/include/grub/loongarch64/efi/loader.h
new file mode 100644
index 0000000..71a0159
--- /dev/null
+++ b/include/grub/loongarch64/efi/loader.h
@@ -0,0 +1,25 @@
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2002,2003,2004,2006,2007,2017 Free Software Foundation, Inc.
+ *
+ * GRUB is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GRUB is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef GRUB_LOADER_MACHINE_HEADER
+#define GRUB_LOADER_MACHINE_HEADER 1
+
+#include <grub/types.h>
+#include <grub/symbol.h>
+
+#endif /* ! GRUB_LOADER_MACHINE_HEADER */
diff --git a/include/grub/loongarch64/efi/memory.h b/include/grub/loongarch64/efi/memory.h
new file mode 100644
index 0000000..2d3f36e
--- /dev/null
+++ b/include/grub/loongarch64/efi/memory.h
@@ -0,0 +1,15 @@
+#ifndef GRUB_MEMORY_CPU_HEADER
+#include <grub/efi/memory.h>
+
+
+static inline grub_uint64_t grub_efi_max_usable_address(void)
+{
+ grub_uint64_t addr;
+ asm volatile ("csrrd %0, 0x181" : "=r" (addr));
+ return addr |= 0xffffffffffUL;
+}
+
+#define GRUB_EFI_MAX_USABLE_ADDRESS (grub_efi_max_usable_address())
+#define GRUB_EFI_MAX_ALLOCATION_ADDRESS GRUB_EFI_MAX_USABLE_ADDRESS
+
+#endif /* ! GRUB_MEMORY_CPU_HEADER */
diff --git a/include/grub/loongarch64/efi/time.h b/include/grub/loongarch64/efi/time.h
new file mode 100644
index 0000000..e69de29
diff --git a/include/grub/loongarch64/io.h b/include/grub/loongarch64/io.h
new file mode 100644
index 0000000..5f34103
--- /dev/null
+++ b/include/grub/loongarch64/io.h
@@ -0,0 +1,62 @@
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2009,2017 Free Software Foundation, Inc.
+ *
+ * GRUB is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GRUB is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef GRUB_IO_H
+#define GRUB_IO_H 1
+
+#include <grub/types.h>
+
+typedef grub_addr_t grub_port_t;
+
+static __inline unsigned char
+grub_inb (grub_port_t port)
+{
+ return *(volatile grub_uint8_t *) port;
+}
+
+static __inline unsigned short int
+grub_inw (grub_port_t port)
+{
+ return *(volatile grub_uint16_t *) port;
+}
+
+static __inline unsigned int
+grub_inl (grub_port_t port)
+{
+ return *(volatile grub_uint32_t *) port;
+}
+
+static __inline void
+grub_outb (unsigned char value, grub_port_t port)
+{
+ *(volatile grub_uint8_t *) port = value;
+}
+
+static __inline void
+grub_outw (unsigned short int value, grub_port_t port)
+{
+ *(volatile grub_uint16_t *) port = value;
+}
+
+static __inline void
+grub_outl (unsigned int value, grub_port_t port)
+{
+ *(volatile grub_uint32_t *) port = value;
+}
+
+#endif /* _SYS_IO_H */
diff --git a/include/grub/loongarch64/linux.h b/include/grub/loongarch64/linux.h
new file mode 100644
index 0000000..af1f51d
--- /dev/null
+++ b/include/grub/loongarch64/linux.h
@@ -0,0 +1,144 @@
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2021 Free Software Foundation, Inc.
+ *
+ * GRUB is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GRUB is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef GRUB_LOONGARCH64_LINUX_HEADER
+#define GRUB_LOONGARCH64_LINUX_HEADER 1
+
+#include <grub/types.h>
+
+/* LoongArch linux kernel type */
+#define GRUB_LOONGARCH_LINUX_BAD 0
+#define GRUB_LOONGARCH_LINUX_ELF 1
+#define GRUB_LOONGARCH_LINUX_EFI 2
+
+#define GRUB_LOONGSON3_BOOT_MEM_MAP_MAX 128
+
+#define GRUB_LINUX_LOONGARCH_MAGIC_SIGNATURE 0x6E6F73676E6F6F4C /* 'Loongson' */
+#define linux_arch_kernel_header linux_loongarch64_kernel_header
+
+/* From linux/Documentation/loongarch/booting.txt
+ *
+ * 0-1: MZ
+ * 0x28: LoongArch\0
+ * 0x3c: PE/COFF头偏移
+ * 0x20e:内核版本号偏移-512
+ * riscv的version字段在0x20偏移处,现在LoongArch没有使用,是0
+ */
+struct linux_loongarch64_kernel_header
+{
+ grub_uint32_t code0; /* Executable code */
+ grub_uint32_t code1; /* Executable code */
+ grub_uint64_t text_offset; /* Image load offset */
+ grub_uint64_t res0; /* reserved */
+ grub_uint64_t res1; /* reserved */
+ grub_uint64_t res2; /* reserved */
+ grub_uint64_t magic; /* Magic number, little endian, "Loongson" */
+ grub_uint64_t res3; /* reserved */
+ grub_uint32_t res4; /* reserved */
+ grub_uint32_t hdr_offset; /* Offset of PE/COFF header */
+};
+
+struct linux_loongarch64_kernel_params
+{
+ grub_addr_t kernel_addr; /* kernel entry address */
+ grub_size_t kernel_size; /* kernel size */
+ grub_addr_t ramdisk_addr; /* initrd load address */
+ grub_size_t ramdisk_size; /* initrd size */
+ int linux_argc; /* cmdline parameters number*/
+ grub_addr_t linux_argv; /* cmdline parameters address*/
+ void* linux_args;
+ void* fdt;
+};
+
+#include <grub/efi/efi.h>
+#include <grub/elfload.h>
+
+#define GRUB_EFI_MAX_PHY_ADDRESS 0xffffffffffffULL
+#define ELF32_LOADMASK (0xf0000000UL)
+#define ELF64_LOADMASK (0xf000000000000000ULL)
+#define FLAGS_EFI_SUPPORT_BIT 0
+
+#define FDT_ADDR_CELLS_STRING "#address-cells"
+#define FDT_SIZE_CELLS_STRING "#size-cells"
+#define FDT_ADDR_SIZE_EXTRA ((2 * grub_fdt_prop_entry_size (sizeof(grub_uint32_t))) + \
+ sizeof (FDT_ADDR_CELLS_STRING) + \
+ sizeof (FDT_SIZE_CELLS_STRING))
+
+/* From arch/loongarch/include/asm/mach-loongson64/boot_param.h */
+struct _extention_list_hdr {
+ grub_uint64_t signature;
+ grub_uint32_t length;
+ grub_uint8_t revision;
+ grub_uint8_t checksum;
+ union {
+ struct _extention_list_hdr *next;
+ grub_uint64_t next_offset;
+ };
+
+} GRUB_PACKED;
+
+struct boot_params_interface {
+ grub_uint64_t signature; /* {"B", "P", "I", "0", "1", ... } */
+ grub_efi_system_table_t *systemtable;
+ union {
+ struct _extention_list_hdr *extlist;
+ grub_uint64_t extlist_offset;
+ };
+ grub_uint64_t flags;
+}GRUB_PACKED;
+
+struct loongsonlist_mem_map {
+ struct _extention_list_hdr header; /* {"M", "E", "M"} */
+ grub_uint8_t map_count;
+ struct memmap {
+ grub_uint32_t mem_type;
+ grub_uint64_t mem_start;
+ grub_uint64_t mem_size;
+ } GRUB_PACKED map[GRUB_LOONGSON3_BOOT_MEM_MAP_MAX];
+}GRUB_PACKED;
+
+grub_err_t
+finalize_efi_params_linux (struct linux_loongarch64_kernel_params *kernel_params);
+
+grub_err_t
+grub_linux_loongarch_elf_linux_boot_image (struct linux_loongarch64_kernel_params
+ *kernel_params);
+
+void*
+grub_linux_loongarch_alloc_virtual_mem_addr (grub_addr_t addr,
+ grub_size_t size,
+ grub_err_t *err);
+
+void*
+grub_linux_loongarch_alloc_virtual_mem_align (grub_size_t size,
+ grub_size_t align,
+ grub_err_t *err);
+
+void
+grub_linux_loongarch_elf_relocator_unload (void);
+
+int
+grub_linux_loongarch_elf_get_boot_params (struct boot_params_interface **boot_params);
+
+grub_err_t
+grub_linux_loongarch_elf_boot_params (struct boot_params_interface *boot_params);
+
+grub_err_t
+grub_linux_loongarch_elf_load_kernel (grub_elf_t elf, const char *filename);
+
+#endif /* ! GRUB_LOONGARCH64_LINUX_HEADER */
diff --git a/include/grub/loongarch64/loongarch64.h b/include/grub/loongarch64/loongarch64.h
new file mode 100644
index 0000000..ea3be3d
--- /dev/null
+++ b/include/grub/loongarch64/loongarch64.h
@@ -0,0 +1,30 @@
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2010,2017 Free Software Foundation, Inc.
+ *
+ * GRUB is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GRUB is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef GRUB_REGISTERS_CPU_HEADER
+#define GRUB_REGISTERS_CPU_HEADER 1
+
+#ifdef ASM_FILE
+#define GRUB_CPU_REGISTER_WRAP(x) x
+#else
+#define GRUB_CPU_REGISTER_WRAP(x) #x
+#endif
+
+#define GRUB_CPU_LOONGARCH_COP0_TIMER_COUNT GRUB_CPU_REGISTER_WRAP(9)
+
+#endif
diff --git a/include/grub/loongarch64/memory.h b/include/grub/loongarch64/memory.h
new file mode 100644
index 0000000..cc9faef
--- /dev/null
+++ b/include/grub/loongarch64/memory.h
@@ -0,0 +1,59 @@
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2017 Free Software Foundation, Inc.
+ *
+ * GRUB is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GRUB is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef GRUB_MEMORY_CPU_HEADER
+#define GRUB_MEMORY_CPU_HEADER 1
+
+#ifndef ASM_FILE
+#include <grub/symbol.h>
+#include <grub/err.h>
+#include <grub/types.h>
+#endif
+
+#ifndef ASM_FILE
+
+typedef grub_addr_t grub_phys_addr_t;
+
+static inline grub_phys_addr_t
+grub_vtop (void *a)
+{
+ if (-1 == ((grub_int64_t) a >> 32))
+ return ((grub_phys_addr_t) a) & 0x1fffffffUL;
+ return ((grub_phys_addr_t) a) & 0xffffffffffffUL;
+}
+
+static inline void *
+grub_map_memory (grub_phys_addr_t a, grub_size_t size)
+{
+ grub_uint64_t addr;
+ asm volatile ("csrrd %0, 0x181" : "=r" (addr));
+ if (addr & 0x1)
+ return (void *) (a | (addr & 0xffffffffffffff00UL));
+ else
+ return (void *) a;
+}
+
+static inline void
+grub_unmap_memory (void *a __attribute__ ((unused)),
+ grub_size_t size __attribute__ ((unused)))
+{
+}
+
+#endif
+
+#endif
diff --git a/include/grub/loongarch64/reloc.h b/include/grub/loongarch64/reloc.h
new file mode 100644
index 0000000..2106ba2
--- /dev/null
+++ b/include/grub/loongarch64/reloc.h
@@ -0,0 +1,113 @@
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2022 Free Software Foundation, Inc.
+ *
+ * GRUB is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GRUB is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef GRUB_LOONGARCH64_RELOC_H
+#define GRUB_LOONGARCH64_RELOC_H 1
+#include <grub/types.h>
+
+#define LOONGARCH64_STACK_MAX 16
+
+struct grub_loongarch64_stack
+{
+ grub_uint64_t data[LOONGARCH64_STACK_MAX];
+ int count;
+ int top;
+};
+
+typedef struct grub_loongarch64_stack* grub_loongarch64_stack_t;
+
+void grub_loongarch64_stack_init (grub_loongarch64_stack_t stack);
+void grub_loongarch64_sop_push (grub_loongarch64_stack_t stack,
+ grub_int64_t offset);
+void grub_loongarch64_sop_sub (grub_loongarch64_stack_t stack);
+void grub_loongarch64_sop_sl (grub_loongarch64_stack_t stack);
+void grub_loongarch64_sop_sr (grub_loongarch64_stack_t stack);
+void grub_loongarch64_sop_add (grub_loongarch64_stack_t stack);
+void grub_loongarch64_sop_and (grub_loongarch64_stack_t stack);
+void grub_loongarch64_sop_if_else (grub_loongarch64_stack_t stack);
+void grub_loongarch64_sop_32_s_10_5 (grub_loongarch64_stack_t stack,
+ grub_uint64_t *place);
+void grub_loongarch64_sop_32_u_10_12 (grub_loongarch64_stack_t stack,
+ grub_uint64_t *place);
+void grub_loongarch64_sop_32_s_10_12 (grub_loongarch64_stack_t stack,
+ grub_uint64_t *place);
+void grub_loongarch64_sop_32_s_10_16 (grub_loongarch64_stack_t stack,
+ grub_uint64_t *place);
+void grub_loongarch64_sop_32_s_10_16_s2 (grub_loongarch64_stack_t stack,
+ grub_uint64_t *place);
+void grub_loongarch64_sop_32_s_5_20 (grub_loongarch64_stack_t stack,
+ grub_uint64_t *place);
+void grub_loongarch64_sop_32_s_0_5_10_16_s2 (grub_loongarch64_stack_t stack,
+ grub_uint64_t *place);
+void grub_loongarch64_sop_32_s_0_10_10_16_s2 (grub_loongarch64_stack_t stack,
+ grub_uint64_t *place);
+
+void grub_loongarch64_b26 (grub_uint32_t *place, grub_int64_t offset);
+void grub_loongarch64_xxx_hi20 (grub_uint32_t *place, grub_int64_t offset);
+void grub_loongarch64_xxx_lo12 (grub_uint32_t *place, grub_int64_t offset);
+void grub_loongarch64_xxx64_hi12 (grub_uint32_t *place, grub_int64_t offset);
+void grub_loongarch64_xxx64_lo20 (grub_uint32_t *place, grub_int64_t offset);
+
+#define GRUB_LOONGARCH64_RELOCATION(STACK, PLACE, OFFSET) \
+ case R_LARCH_SOP_PUSH_ABSOLUTE: \
+ grub_loongarch64_sop_push (STACK, OFFSET); \
+ break; \
+ case R_LARCH_SOP_SUB: \
+ grub_loongarch64_sop_sub (STACK); \
+ break; \
+ case R_LARCH_SOP_SL: \
+ grub_loongarch64_sop_sl (STACK); \
+ break; \
+ case R_LARCH_SOP_SR: \
+ grub_loongarch64_sop_sr (STACK); \
+ break; \
+ case R_LARCH_SOP_ADD: \
+ grub_loongarch64_sop_add (STACK); \
+ break; \
+ case R_LARCH_SOP_AND: \
+ grub_loongarch64_sop_and (STACK); \
+ break; \
+ case R_LARCH_SOP_IF_ELSE: \
+ grub_loongarch64_sop_if_else (STACK); \
+ break; \
+ case R_LARCH_SOP_POP_32_S_10_5: \
+ grub_loongarch64_sop_32_s_10_5 (STACK, PLACE); \
+ break; \
+ case R_LARCH_SOP_POP_32_U_10_12: \
+ grub_loongarch64_sop_32_u_10_12 (STACK, PLACE); \
+ break; \
+ case R_LARCH_SOP_POP_32_S_10_12: \
+ grub_loongarch64_sop_32_s_10_12 (STACK, PLACE); \
+ break; \
+ case R_LARCH_SOP_POP_32_S_10_16: \
+ grub_loongarch64_sop_32_s_10_16 (STACK, PLACE); \
+ break; \
+ case R_LARCH_SOP_POP_32_S_10_16_S2: \
+ grub_loongarch64_sop_32_s_10_16_s2 (STACK, PLACE); \
+ break; \
+ case R_LARCH_SOP_POP_32_S_5_20: \
+ grub_loongarch64_sop_32_s_5_20 (STACK, PLACE); \
+ break; \
+ case R_LARCH_SOP_POP_32_S_0_5_10_16_S2: \
+ grub_loongarch64_sop_32_s_0_5_10_16_s2 (STACK, PLACE); \
+ break; \
+ case R_LARCH_SOP_POP_32_S_0_10_10_16_S2: \
+ grub_loongarch64_sop_32_s_0_10_10_16_s2 (STACK, PLACE); \
+ break;
+
+#endif /* GRUB_LOONGARCH64_RELOC_H */
diff --git a/include/grub/loongarch64/relocator.h b/include/grub/loongarch64/relocator.h
new file mode 100644
index 0000000..cef3aaa
--- /dev/null
+++ b/include/grub/loongarch64/relocator.h
@@ -0,0 +1,38 @@
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2022 Free Software Foundation, Inc.
+ *
+ * GRUB is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GRUB is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef GRUB_RELOCATOR_CPU_HEADER
+#define GRUB_RELOCATOR_CPU_HEADER 1
+
+#include <grub/types.h>
+#include <grub/err.h>
+#include <grub/relocator.h>
+
+struct grub_relocator64_state
+{
+ /* gpr[0] is ignored since it's hardwired to 0. */
+ grub_uint64_t gpr[32];
+ /* Register holding target $pc. */
+ int jumpreg;
+};
+
+grub_err_t
+grub_relocator64_boot (struct grub_relocator *rel,
+ struct grub_relocator64_state state);
+
+#endif /* ! GRUB_RELOCATOR_CPU_HEADER */
diff --git a/include/grub/loongarch64/setjmp.h b/include/grub/loongarch64/setjmp.h
new file mode 100644
index 0000000..d9a0776
--- /dev/null
+++ b/include/grub/loongarch64/setjmp.h
@@ -0,0 +1,27 @@
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2002,2004,2006,2007,2009,2017 Free Software Foundation, Inc.
+ *
+ * GRUB is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GRUB is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef GRUB_SETJMP_CPU_HEADER
+#define GRUB_SETJMP_CPU_HEADER 1
+
+typedef grub_uint64_t grub_jmp_buf[12];
+
+int grub_setjmp (grub_jmp_buf env) RETURNS_TWICE;
+void grub_longjmp (grub_jmp_buf env, int val) __attribute__ ((noreturn));
+
+#endif /* ! GRUB_SETJMP_CPU_HEADER */
diff --git a/include/grub/loongarch64/time.h b/include/grub/loongarch64/time.h
new file mode 100644
index 0000000..c9a7334
--- /dev/null
+++ b/include/grub/loongarch64/time.h
@@ -0,0 +1,39 @@
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2003,2004,2005,2007,2017 Free Software Foundation, Inc.
+ *
+ * GRUB is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GRUB is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef KERNEL_CPU_TIME_HEADER
+#define KERNEL_CPU_TIME_HEADER 1
+
+#ifndef GRUB_UTIL
+
+#define GRUB_TICKS_PER_SECOND (grub_arch_cpuclock / 2)
+
+void grub_timer_init (grub_uint32_t cpuclock);
+
+/* Return the real time in ticks. */
+grub_uint64_t grub_get_rtc (void);
+
+extern grub_uint32_t grub_arch_cpuclock;
+#endif
+
+static inline void
+grub_cpu_idle(void)
+{
+}
+
+#endif
diff --git a/include/grub/loongarch64/types.h b/include/grub/loongarch64/types.h
new file mode 100644
index 0000000..2dbefbf
--- /dev/null
+++ b/include/grub/loongarch64/types.h
@@ -0,0 +1,34 @@
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2002,2006,2007,2009,2017 Free Software Foundation, Inc.
+ *
+ * GRUB is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GRUB is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef GRUB_TYPES_CPU_HEADER
+#define GRUB_TYPES_CPU_HEADER 1
+
+/* The size of void *. */
+#define GRUB_TARGET_SIZEOF_VOID_P 8
+
+/* The size of long. */
+#define GRUB_TARGET_SIZEOF_LONG 8
+
+#ifdef GRUB_CPU_LOONGARCH
+/* loongarch is little-endian. */
+#undef GRUB_TARGET_WORDS_BIGENDIAN
+
+#endif /* ! GRUB_TYPES_CPU_HEADER */
+
+#endif
diff --git a/include/grub/util/install.h b/include/grub/util/install.h
index 51f3b13..a728afc 100644
--- a/include/grub/util/install.h
+++ b/include/grub/util/install.h
@@ -114,6 +114,7 @@ enum grub_install_plat
GRUB_INSTALL_PLATFORM_ARM_COREBOOT,
GRUB_INSTALL_PLATFORM_RISCV32_EFI,
GRUB_INSTALL_PLATFORM_RISCV64_EFI,
+ GRUB_INSTALL_PLATFORM_LOONGARCH64_EFI,
GRUB_INSTALL_PLATFORM_MAX
};
diff --git a/util/grub-install-common.c b/util/grub-install-common.c
index 4833407..60d2c00 100644
--- a/util/grub-install-common.c
+++ b/util/grub-install-common.c
@@ -939,6 +939,7 @@ static struct
[GRUB_INSTALL_PLATFORM_ARM_COREBOOT] = { "arm", "coreboot" },
[GRUB_INSTALL_PLATFORM_RISCV32_EFI] = { "riscv32", "efi" },
[GRUB_INSTALL_PLATFORM_RISCV64_EFI] = { "riscv64", "efi" },
+ [GRUB_INSTALL_PLATFORM_LOONGARCH64_EFI] = { "loongarch64", "efi" },
};
char *
diff --git a/util/grub-install.c b/util/grub-install.c
index 5babc7a..c8f15df 100644
--- a/util/grub-install.c
+++ b/util/grub-install.c
@@ -332,6 +332,8 @@ get_default_platform (void)
#else
return NULL;
#endif
+#elif defined (__loongarch64)
+ return "loongarch64-efi";
#else
return NULL;
#endif
@@ -487,6 +489,7 @@ have_bootdev (enum grub_install_plat pl)
case GRUB_INSTALL_PLATFORM_ARM64_EFI:
case GRUB_INSTALL_PLATFORM_RISCV32_EFI:
case GRUB_INSTALL_PLATFORM_RISCV64_EFI:
+ case GRUB_INSTALL_PLATFORM_LOONGARCH64_EFI:
case GRUB_INSTALL_PLATFORM_I386_IEEE1275:
case GRUB_INSTALL_PLATFORM_SPARC64_IEEE1275:
case GRUB_INSTALL_PLATFORM_POWERPC_IEEE1275:
@@ -906,6 +909,7 @@ main (int argc, char *argv[])
case GRUB_INSTALL_PLATFORM_I386_EFI:
case GRUB_INSTALL_PLATFORM_IA64_EFI:
case GRUB_INSTALL_PLATFORM_X86_64_EFI:
+ case GRUB_INSTALL_PLATFORM_LOONGARCH64_EFI:
is_efi = 1;
grub_util_error (_("this utility cannot be used for EFI platforms"
" because it does not support UEFI Secure Boot"));
@@ -933,6 +937,7 @@ main (int argc, char *argv[])
case GRUB_INSTALL_PLATFORM_ARM64_EFI:
case GRUB_INSTALL_PLATFORM_RISCV32_EFI:
case GRUB_INSTALL_PLATFORM_RISCV64_EFI:
+ case GRUB_INSTALL_PLATFORM_LOONGARCH64_EFI:
case GRUB_INSTALL_PLATFORM_IA64_EFI:
case GRUB_INSTALL_PLATFORM_I386_IEEE1275:
case GRUB_INSTALL_PLATFORM_SPARC64_IEEE1275:
@@ -980,6 +985,7 @@ main (int argc, char *argv[])
case GRUB_INSTALL_PLATFORM_ARM64_EFI:
case GRUB_INSTALL_PLATFORM_RISCV32_EFI:
case GRUB_INSTALL_PLATFORM_RISCV64_EFI:
+ case GRUB_INSTALL_PLATFORM_LOONGARCH64_EFI:
case GRUB_INSTALL_PLATFORM_IA64_EFI:
case GRUB_INSTALL_PLATFORM_I386_IEEE1275:
case GRUB_INSTALL_PLATFORM_ARM_UBOOT:
@@ -1133,6 +1139,9 @@ main (int argc, char *argv[])
case GRUB_INSTALL_PLATFORM_RISCV64_EFI:
efi_file = "BOOTRISCV64.EFI";
break;
+ case GRUB_INSTALL_PLATFORM_LOONGARCH64_EFI:
+ efi_file = "BOOTLOONGARCH64.EFI";
+ break;
default:
grub_util_error ("%s", _("You've found a bug"));
break;
@@ -1166,6 +1175,9 @@ main (int argc, char *argv[])
case GRUB_INSTALL_PLATFORM_RISCV64_EFI:
efi_file = "grubriscv64.efi";
break;
+ case GRUB_INSTALL_PLATFORM_LOONGARCH64_EFI:
+ efi_file = "grubloongarch64.efi";
+ break;
default:
efi_file = "grub.efi";
break;
@@ -1470,6 +1482,7 @@ main (int argc, char *argv[])
case GRUB_INSTALL_PLATFORM_ARM64_EFI:
case GRUB_INSTALL_PLATFORM_RISCV32_EFI:
case GRUB_INSTALL_PLATFORM_RISCV64_EFI:
+ case GRUB_INSTALL_PLATFORM_LOONGARCH64_EFI:
case GRUB_INSTALL_PLATFORM_IA64_EFI:
g = grub_util_guess_efi_drive (*curdev);
break;
@@ -1614,6 +1627,7 @@ main (int argc, char *argv[])
case GRUB_INSTALL_PLATFORM_ARM64_EFI:
case GRUB_INSTALL_PLATFORM_RISCV32_EFI:
case GRUB_INSTALL_PLATFORM_RISCV64_EFI:
+ case GRUB_INSTALL_PLATFORM_LOONGARCH64_EFI:
case GRUB_INSTALL_PLATFORM_IA64_EFI:
core_name = "core.efi";
snprintf (mkimage_target, sizeof (mkimage_target),
@@ -1719,6 +1733,7 @@ main (int argc, char *argv[])
case GRUB_INSTALL_PLATFORM_ARM64_EFI:
case GRUB_INSTALL_PLATFORM_RISCV32_EFI:
case GRUB_INSTALL_PLATFORM_RISCV64_EFI:
+ case GRUB_INSTALL_PLATFORM_LOONGARCH64_EFI:
case GRUB_INSTALL_PLATFORM_IA64_EFI:
case GRUB_INSTALL_PLATFORM_MIPSEL_QEMU_MIPS:
case GRUB_INSTALL_PLATFORM_MIPS_QEMU_MIPS:
@@ -1973,6 +1988,7 @@ main (int argc, char *argv[])
case GRUB_INSTALL_PLATFORM_ARM64_EFI:
case GRUB_INSTALL_PLATFORM_RISCV32_EFI:
case GRUB_INSTALL_PLATFORM_RISCV64_EFI:
+ case GRUB_INSTALL_PLATFORM_LOONGARCH64_EFI:
case GRUB_INSTALL_PLATFORM_IA64_EFI:
{
char *dst = grub_util_path_concat (2, efidir, efi_file);
diff --git a/util/grub-mkimagexx.c b/util/grub-mkimagexx.c
index 3931194..cf582a9 100644
--- a/util/grub-mkimagexx.c
+++ b/util/grub-mkimagexx.c
@@ -44,6 +44,7 @@
#include <grub/arm/reloc.h>
#include <grub/arm64/reloc.h>
#include <grub/ia64/reloc.h>
+#include <grub/loongarch64/reloc.h>
#include <grub/osdep/hostfile.h>
#include <grub/util/install.h>
#include <grub/util/mkimage.h>
@@ -1160,7 +1161,60 @@ SUFFIX (relocate_addrs) (Elf_Ehdr *e, struct section_metadata *smd,
}
break;
}
-#endif
+ case EM_LOONGARCH:
+ {
+ grub_int64_t pc;
+ grub_uint32_t *t32 = (grub_uint32_t *) target;
+
+ sym_addr += addend;
+ pc = offset + target_section_addr + image_target->vaddr_offset;
+
+ switch (ELF_R_TYPE (info))
+ {
+ case R_LARCH_64:
+ {
+ grub_uint64_t *t64 = (grub_uint64_t *) target;
+ *t64 = grub_host_to_target64 (grub_target_to_host64 (*t64) + sym_addr);
+ }
+ break;
+ case R_LARCH_MARK_LA:
+ break;
+ case R_LARCH_B26:
+ {
+ grub_int64_t off;
+ off = sym_addr - target_section_addr - offset
+ - image_target->vaddr_offset;
+ grub_loongarch64_b26 (t32, off);
+ }
+ break;
+ case R_LARCH_ABS_HI20:
+ grub_loongarch64_xxx_hi20 (t32, sym_addr);
+ break;
+ case R_LARCH_ABS64_LO20:
+ grub_loongarch64_xxx64_lo20 (t32, sym_addr);
+ break;
+ case R_LARCH_ABS64_HI12:
+ grub_loongarch64_xxx64_hi12 (t32, sym_addr);
+ break;
+ case R_LARCH_PCALA_HI20:
+ {
+ grub_int32_t hi20;
+ hi20 = (((sym_addr + 0x800) & ~0xfffULL) - (pc & ~0xfffULL));
+ grub_loongarch64_xxx_hi20 (t32, hi20);
+ }
+ break;
+ case R_LARCH_ABS_LO12:
+ case R_LARCH_PCALA_LO12:
+ grub_loongarch64_xxx_lo12 (t32, sym_addr);
+ break;
+ default:
+ grub_util_error (_("relocation 0x%x is not implemented yet"),
+ (unsigned int) ELF_R_TYPE (info));
+ break;
+ }
+ break;
+ }
+#endif /* defined(MKIMAGE_ELF64) */
#if defined(MKIMAGE_ELF32)
case EM_ARM:
{
@@ -1538,7 +1592,10 @@ add_fixup_entry (struct fixup_block_list **cblock, grub_uint16_t type,
/* The spec does not mention the requirement of a Page RVA.
Here, align the address with a 4K boundary for safety. */
- b->page_rva = (addr & ~(0x1000 - 1));
+#ifdef GRUB_CPU_LOONGARCH64
+ if (type)
+#endif
+ b->page_rva = (addr & ~(0x1000 - 1));
b->block_size = sizeof (*b);
}
@@ -1548,7 +1605,11 @@ add_fixup_entry (struct fixup_block_list **cblock, grub_uint16_t type,
/* Add a new entry. */
cur_index = ((b->block_size - sizeof (*b)) >> 1);
+#ifdef GRUB_CPU_LOONGARCH64
+ entry = GRUB_PE32_FIXUP_ENTRY (type, type ? (addr - b->page_rva) : addr);
+#else
entry = GRUB_PE32_FIXUP_ENTRY (type, addr - b->page_rva);
+#endif
b->entries[cur_index] = grub_host_to_target16 (entry);
b->block_size += 2;
}
@@ -1704,7 +1765,39 @@ translate_relocation_pe (struct translate_context *ctx,
break;
}
break;
- break;
+#if defined(MKIMAGE_ELF64)
+ case EM_LOONGARCH:
+ switch (ELF_R_TYPE (info))
+ {
+ case R_LARCH_64:
+ ctx->current_address = add_fixup_entry (&ctx->lst,
+ GRUB_PE32_REL_BASED_DIR64, addr, 0,
+ ctx->current_address, image_target);
+ break;
+ case R_LARCH_MARK_LA:
+ ctx->current_address = add_fixup_entry (&ctx->lst,
+ GRUB_PE32_REL_BASED_LOONGARCH64_MARK_LA,
+ addr, 0, ctx->current_address, image_target);
+ break;
+ /* Relative relocations do not require fixup entries. */
+ case R_LARCH_B26:
+ case R_LARCH_ABS_HI20:
+ case R_LARCH_ABS_LO12:
+ case R_LARCH_ABS64_LO20:
+ case R_LARCH_ABS64_HI12:
+ case R_LARCH_PCALA_HI20:
+ case R_LARCH_PCALA_LO12:
+ grub_util_info (" %s: not adding fixup: 0x%08x : 0x%08x",
+ __FUNCTION__, (unsigned int) addr,
+ (unsigned int) ctx->current_address);
+ break;
+ default:
+ grub_util_error (_("relocation 0x%x is not implemented yet"),
+ (unsigned int) ELF_R_TYPE (info));
+ break;
+ }
+ break;
+#endif /* defined(MKIMAGE_ELF64) */
#if defined(MKIMAGE_ELF32)
case EM_ARM:
switch (ELF_R_TYPE (info))
diff --git a/util/grub-module-verifier.c b/util/grub-module-verifier.c
index 163529c..071d1c3 100644
--- a/util/grub-module-verifier.c
+++ b/util/grub-module-verifier.c
@@ -176,6 +176,21 @@ struct grub_module_verifier_arch archs[] = {
-1
}
},
+ { "loongarch64", 8, 0, EM_LOONGARCH, GRUB_MODULE_VERIFY_SUPPORTS_REL | GRUB_MODULE_VERIFY_SUPPORTS_RELA, (int[]){
+ R_LARCH_NONE,
+ R_LARCH_64,
+ R_LARCH_MARK_LA,
+ R_LARCH_B26,
+ R_LARCH_ABS_HI20,
+ R_LARCH_ABS_LO12,
+ R_LARCH_ABS64_LO20,
+ R_LARCH_ABS64_HI12,
+ R_LARCH_PCALA_HI20,
+ R_LARCH_PCALA_LO12,
+ -1
+ }, (int[]){
+ -1
+ } },
};
struct platform_whitelist {
diff --git a/util/mkimage.c b/util/mkimage.c
index 8319e8d..4e09dfc 100644
--- a/util/mkimage.c
+++ b/util/mkimage.c
@@ -654,6 +654,22 @@ static const struct grub_install_image_target_desc image_targets[] =
.pe_target = GRUB_PE32_MACHINE_RISCV64,
.elf_target = EM_RISCV,
},
+ {
+ .dirname = "loongarch64-efi",
+ .names = { "loongarch64-efi", NULL },
+ .voidp_sizeof = 8,
+ .bigendian = 0,
+ .id = IMAGE_EFI,
+ .flags = PLATFORM_FLAGS_NONE,
+ .total_module_size = TARGET_NO_FIELD,
+ .decompressor_compressed_size = TARGET_NO_FIELD,
+ .decompressor_uncompressed_size = TARGET_NO_FIELD,
+ .decompressor_uncompressed_addr = TARGET_NO_FIELD,
+ .section_align = GRUB_PE32_SECTION_ALIGNMENT,
+ .vaddr_offset = EFI64_HEADER_SIZE,
+ .pe_target = GRUB_PE32_MACHINE_LOONGARCH64,
+ .elf_target = EM_LOONGARCH,
+ },
};
#include <grub/lib/LzmaEnc.h>
--
2.33.0
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化